5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

オフグリッドAdvent Calendar 2024

Day 9

pandasを使った主要フォーマットファイル操作網羅

Last updated at Posted at 2024-12-26

Pandasを用いて様々なファイル形式の、読み込みと書き込みの基本操作をまとめます.

目次

環境

Python 3.11.9
pandas 2.2.3
openpyxl 3.1.5

下記のコマンドでインストールできます。

pip install pandas openpyxl

Excelファイルの操作

openpyxlについて

PythonでExcelファイル(特に.xlsx形式)を操作するためのライブラリです。
Pandasはデータ分析用のライブラリであり、Excelファイルを扱う際にはread_excel関数を使用します。この関数は内部でopenpyxlを利用して.xlsxファイルを読み込むため、Pandasを使用する場合はopenpyxlが必要となります。

公式ドキュメント

Excelファイルの読み込み

PandasでExcelファイルを読み込む際には、read_excel関数を使用します。引数に読み込みたいExcelファイルのパスを指定すると、戻り値としてDataFrameオブジェクト(単一のシートを読み込む場合) または DataFrameオブジェクト の辞書(複数のシートを読み込む場合)が返ってきます。

sample.py
import pandas

# 読み込みたいExcelファイルのパス
READ_EXCEL_PATH = r".\sample.xlsx"

# パスを引数に指定
df = pandas.read_excel(READ_EXCEL_PATH)

print(type(df)) # <class 'pandas.core.frame.DataFrame'>

複数シートを読み込みたい(読み込むシートを指定したい)時は、sheet_nameパラメータをlist形式で指定します。Noneを指定することで、全てのシートを読み込みます。

sample.py
# 配列で指定すると複数シート読み込み
df_dict = pandas.read_excel(READ_EXCEL_PATH, sheet_name=["Sheet1", "Sheet2"])
print(df_dict)
print(type(df_dict)) # <class 'dict'>

read_excel関数の主なパラメータ

sample.py
# ヘッダー行の指定 
# 2行目をヘッダーとして使用
df = pandas.read_excel(READ_EXCEL_PATH, header=1)

# 読み込む列の指定 
# 1列目から4列目(0, 1, 2, 3列)を読み込む
df = pandas.read_excel(READ_EXCEL_PATH, usecols=[0, 1, 2, 3])

# 列文字での指定 
# A列とC列からF列を読み込む
df = pandas.read_excel(READ_EXCEL_PATH, usecols="A,C:F")

# 特定の行をスキップ(除外)
# skiprows=3で最初の3行を、skipfooter=3で最後3行を読み込まない
df = pandas.read_excel(READ_EXCEL_PATH, skiprows=3, skipfooter=3)
# 1行目と3行目をスキップ
df = pandas.read_excel(READ_EXCEL_PATH, skiprows=[0, 2])

# インデックスを指定 
# index_col=0を指定することで、最初の列がインデックスとして使用され、データの一部ではなる
df = pandas.read_excel(READ_EXCEL_PATH, index_col=0)

# ヘッダ名称で日付列を指定
df = pandas.read_excel(READ_EXCEL_PATH, header=0, parse_dates=["日付"], sheet_name="売上")
print(df["日付"].dtype) # datetime64[ns]

Excelファイルへの書き込み

Excelファイルに書き込む方法として、2パターン紹介します

pandas.DataFrame.to_excelを使用する方法

■ 特徴

  • DataFrameをExcelファイルに書き込むためのメソッドです
  • 指定したパスにファイルが存在しない場合は、生成されます
  • 既に存在するファイル名を指定すると、既存のファイルのその内容を消去して上書きします
  • シンプルな使い方ができ、単一のシートへの書き込みに適しています
sample.py
import pandas

WRITE_EXCEL_PATH = r".\output.xlsx"

# 書き込みたいデータフレームを定義
df = pandas.DataFrame(
    [["リンゴ", 100, 150], ["バナナ", 80, 100], ["オレンジ", 50, 120], ["ぶどう", 30, 300], ["イチゴ", 20, 500]],
    index=["F001", "F002", "F003", "F004", "F005"],
    columns=["果物名", "在庫数", "価格"],
)

# データフレームをExcelファイルに書き込む
df.to_excel(WRITE_EXCEL_PATH, sheet_name="果物管理", index=False)

# 指定したカラムのみ書きむ
df.to_excel(WRITE_EXCEL_PATH, sheet_name="果物管理", columns=["果物名", "在庫数"])

■ 主なパラメータ

パラメータ  説明
index データフレームのインデックスをExcelに書き込むかどうかを指定。
デフォルトはTrue
header 列名(ヘッダー)を出力するかどうかを指定。ヘッダーに該当するのは「columns」。デフォルトはTrue
columns 出力する列をリストで指定。このパラメータを指定すると、特定の列のみを選択して書き込むことが可能。
startrow Excelシート内でデータを書き始める行番号を指定。
デフォルトは0(最初の行)
startcol Excelシート内でデータを書き始める列番号を指定。
デフォルトは0(最初の列)

pandas.ExcelWriterを使用する方法

■ 特徴

  • Excelファイルへの書き込みを管理するためのオブジェクトです
  • 複数のデータフレームを異なるシートに書き込む場合や、既存のExcelファイルに追記する際に非常に便利です
  • with文と組み合わせて使用することで、リソース管理が容易になり、複数シートへの出力が可能になります
  • 指定したパスにファイルが存在しない場合は生成されます
  • modeパラメータとif_sheet_existsパラメータを設定することにより、既存のExcelファイルに追記などが可能になります
samole.py
# 書き込みたいデータフレームを定義
df_vegetables = pandas.DataFrame(
    {"野菜名": ["キャベツ", "人参", "トマト"], "在庫数": [100, 80, 20], "価格": [300, 100, 200]}
)
df_fruit = pandas.DataFrame(
    {"果物名": ["リンゴ", "バナナ", "オレンジ"], "在庫数": [10, 50, 40], "価格": [150, 130, 100]}
)

# ExcelWriterを使用して複数シートに書き込む
# mode="a"で追記 if_sheet_exists="overlay"で既存のシートが存在した場合の動作を指定
with pandas.ExcelWriter(WRITE_EXCEL_PATH, mode="a", if_sheet_exists="overlay") as writer:
    df_vegetables.to_excel(writer, sheet_name="野菜", index=False)
    df_fruit.to_excel(writer, sheet_name="果物", index=False)

■ 主なパラメータ

パラメータ  説明
mode Excelファイルへの書き込みモードを指定。
デフォルトは'w'(書き込み専用)、既存のファイルに追記したい場合は'a'(追記)を指定。
if_sheet_exists シートが既に存在する場合の挙動を制御。
・error: エラーを発生させる(デフォルト)
・new: 新しいシート名を生成して追加
・replace: 既存シートを削除して新規作成
・overlay: 既存シートに上書き

固定長ファイルの操作

■ 固定長ファイルとは
固定長ファイルは、各レコードの長さが一定であり、各フィールドが決まった位置に配置される形式のテキストファイルです。1行が1つのレコードを表し、各レコードは複数のフィールドで構成されており、フィールドはそれぞれ固定された長さで区切られます。CSV形式などに比べて、高速にデータ取得が可能な点などが、メリットです。

サンプルの固定長ファイル.txt
顧客ID,名前,性別,生年月日,入金金額
    1 スズキM19800101  11000
    2 マツモトF19900202   1000
    3 タカハシM20000303   5000
    4 ナカムラF19850115    300
    5  アベM19950320  25000

shift-jisエンコード

固定長ファイルの読み込み

固定長ファイルを読み込む際は、pandas.read_fwf関数を使用します。

sample.py
import pandas

# ファイルパスの指定
READ_FILE_PATH = "固定長sample.txt"

# 各フィールドの開始位置と幅を指定
# shift-jisエンコードで半角カナは1文字1バイト
colspecs = [
    (0, 5),  # 顧客ID: 5バイト
    (5, 10),  # 名前: 5バイト
    (10, 11),  # 性別: 1バイト(MまたはF)
    (11, 19),  # 生年月日: 8バイト
    (19, 26),  # 入金額: 7バイト(固定長)
]

# 固定長ファイルの読み込み
df = pandas.read_fwf(
    READ_FILE_PATH,
    colspecs=colspecs,
    encoding="shift-jis",
    header=None
)

# カラム名の設定
df.columns = ["顧客ID", "氏名", "性別", "生年月日", "入金額"]

# 読み込んだデータの表示
print(df)

■ 主なパラメータ

パラメータ  説明
colspecs 各フィールドの開始位置と幅をタプル(int,int)として指定。
encoding エンコード形式を指定
header ヘッダー行の有無を指定。デフォルトでは、1行目がヘッダーとなる

■ colspecsの役割
colspecsは、各フィールドの開始位置と終了位置を指定するために使用されます。これにより、Pandasはどの部分をどのカラムにマッピングするかを決定するので、重要です。デフォルトでは、colspecs=inferとなり、最初の100行を解析し、カラムの幅を推測します。そのため、意図しないデータ抽出となる可能性が高いので、明示的に指定することが推奨されます。

固定長ファイルへの書き込み

pandasに、固定長ファイルへの出力をサポートする関数は記事投稿時点ではありませんでした。
下記は自作ではありますがDataFrame型を固定長ファイルに出力するサンプルコードです。要件に合わせて、自作する必要があります。

sample.py
ENCODING = "shift-jis"
# サンプルデータフレーム
df = pandas.DataFrame(
    [
        # 顧客ID,名前,性別,生年月日,金額
        [11, "キムラ", "M", 20120909, 11000],
        [12, "ササキ", "F", 20020512, 100000],
        [13, "サカモト", "M", 20000303, 160000],
        [14, "イガラシ", "F", 19991115, 11000],
        [15, "ハマダ", "M", 19950320, 11000],
    ]
)


# データの各カラムを固定長で書き込み
def write_file(df, filename, widths):
    with open(filename, "w", encoding=ENCODING) as f:
        # DataFrameの各行に対して処理を行う
        for index, row in df.iterrows():
            line = "".join(f"{str(value):>{width}}" for value, width in zip(row, widths))
            f.write(line + "\n")


column_widths = [5, 5, 1, 8, 7]  # 各カラムの幅を指定
write_file(df, "output.txt", column_widths)

CSVファイルの操作

CSVファイルの読み込み

CSVファイルを読み込む際は、pandas.read_csv 関数を使用します。

sample.py
import pandas

# 読み込みたいファイルのパス
READ_FILE_PATH = r".\sample.csv"

df = pandas.read_csv(READ_FILE_PATH)
print(df)

■ 大規模なCSVファイルの読み込み
大規模なCSVファイルを処理するためにchunksizeパラメータを使用することで、効率的にCSVファイルを読み込み、処理することも可能です。
chunkとは「大きな塊」という意味を持ち、大規模データを分割したひとまとまりの断片を指します。

sample.py
import pandas

# 読み込みたいファイルのパス
READ_FILE_PATH = r".\large_data.csv"
# チャンクサイズを指定
CHUNK_SIZE = 100000
# 処理されたチャンクをまとめるlist
results = []

def calculate_average(chunk):
    # chunkに対して、「入金額」列の平均値を計算する
    return chunk["入金額"].mean()


for chunk in pandas.read_csv(READ_FILE_PATH, chunksize=CHUNK_SIZE, header=0):
    result = calculate_average(chunk)
    print(result)
    results.append(result)

print(results)
# 全チャンクの結果を集計
final_result = sum(results) / len(results)
print(f"全体の平均: {final_result}")

■ 出力結果 (100万件のCSVデータの処理結果)

1:501539.41211
2:498556.5636
3:499330.59795
4:499743.16578
5:500456.37189
6:500491.45455
7:501505.33551
8:499123.46885
9:500569.98155
10:499867.45092
results:[np.float64(501539.41211), np.float64(498556.5636), np.float64(499330.59795), np.float64(499743.16578), np.float64(500456.37189), np.float64(500491.45455), np.float64(501505.33551), np.float64(499123.46885), np.float64(500569.98155), np.float64(499867.45092)]
全体の平均: 500118.380271

chunkに分けて処理することで、メモリ使用量を抑えながら大量のデータを分析することができます

CSVファイルへの書き込み

CSVファイルへ下記込む際は、pandas.DataFrame.to_csv関数を使用します。

sample.py
import pandas

# 読み込みたいファイルのパス
WRITE_FILE_PATH = r".\output.csv"
# データを辞書形式で定義
data = {
    "顧客ID": ["C000001", "C000002", "C000003", "C000004", "C000005"],
    "名前": ["伊藤 真綾", "石川 明美", "鈴木 千代", "伊藤 花子", "松本 零"],
    "入金額": [723575, 550149, 910995, 26118, 956292],
    "入金日": ["20240825", "20240407", "20240531", "20240816", "20241023"],
}

# DataFrameを初期化
df = pandas.DataFrame(data)

df.to_csv(WRITE_FILE_PATH, index=False)

■ modeパラメータの指定
modeプロパティを設定することにより、すでにCSVファイルが存在していた場合の動作を制御することができます。

  • mode=w :存在していた場合、一度削除 (デフォルト)
  • mode=a :ファイルが存在する場合はファイルの末尾に追加
  • mode=x :ファイルがすでに存在する場合は失敗

JSONファイルの操作

JSONファイルの読み込み

シンプルな構造のJSONファイルの読み込み

シンプルなJSONデータは、read_json関数を使用して簡単にDataFram変換できます。

sample.json
[
    {
        "id": 1,
        "name": "Alice",
        "age": 30
    },
    {
        "id": 2,
        "name": "Bob",
        "age": 25
    },
    {
        "id": 3,
        "name": "John",
        "age": 35
    }
]

sample01.py
import pandas

# ファイルパスの指定
READ_FILE_PATH = "json_sample.json"

df = pandas.read_json(READ_FILE_PATH)
print(df)

■ 出力結果

   id   name  age
0   1  Alice   30
1   2    Bob   25
2   3   John   35

一方、ネストされたJSON構造のファイルを読み込む際には注意が必要です。

sample.json
{
    "users": [
        {
            "id": 1,
            "contact": {
                "email": "alice@example.com",
                "phone": "123-456-7890"
            }
        },
        {
            "id": 2,
            "contact": {
                "email": "bob@example.com",
                "phone": "234-567-8901"
            }
        }
    ]
}

上記のネストしたJSONをsample01.pyで読み込んだ際の出力は下記のようになります。
■ 出力結果

                                                                                  users
0  {'id': 1, 'contactDetails': {'email': 'alice@example.com', 'phone': '123-456-7890'}}
1    {'id': 2, 'contactDetails': {'email': 'bob@example.com', 'phone': '234-567-8901'}}

この場合、読み込み後のDataFramを操作が難しくなったり、可読性の低下などがあります。
その解決策として、json_normalize関数を使用し、フラット化させる読み込み方法があります。

ネスト構造のJSONファイルの読み込み

sample02.py
import pandas
import json

# JSONファイルを開いてデータを読み込む
with open(READ_FILE_PATH, "r", encoding="utf-8") as file:
    data = json.load(file)

# pandasのDataFrameに変換
df = pandas.json_normalize(data["users"])

print(df)

■ 出力結果

   id contactDetails.email contactDetails.phone
0   1    alice@example.com         123-456-7890
1   2      bob@example.com         234-567-8901

json_normalize関数は、ネストされたJSONオブジェクトをフラットな形式に変換するために使用されます。下記の例では、data["users"]からユーザー情報を抽出し、各フィールドが独立したカラムとして展開されます。フラットな形式にすることで、データ分析や可視化が容易になります

JSONファイルへの書き込み

JSONファイルに書き込む際は、pandas.DataFrame.to_json関数を使用します。
引数に、出力先のパスを指定しない場合は、JSON形式の文字列に変換に変換されます。

sample.py
import pandas as pd

WRITE_FILE_PATH = r".\output.json"
# サンプルデータフレーム
df = pd.DataFrame({"id": [1, 2, 3], "name": ["Alice", "Bob", "John"], "age": [30, 25, 35]})
# output.jsonファイルが出力される
df.to_json(WRITE_FILE_PATH)

# DataFrameをJSON形式の文字列に変換
json_data = df.to_json()
# {"id":{"0":1,"1":2,"2":3},"name":{"0":"Alice","1":"Bob","2":"John"},"age":{"0":30,"1":25,"2":35}}
print(json_data) 

■ orientパラメータ
orienパラメータを指定することで、出力されるJSONの出力形式を指定することができます。

■ orienパラメータの種類

orienパラメータ  構造
split {index -> [index], columns -> [columns], data -> [values]}
records [{column -> value}, ...]
index {index -> {column -> value}}
columns(デフォルト) {column -> {index -> value}}
values 値のリスト
table {'schema': {schema}、'data': {data}} のような辞書
sample.py
# サンプルデータフレーム
df = pd.DataFrame({"id": [1, 2, 3], "name": ["Alice", "Bob", "John"], "age": [30, 25, 35]})
# output.jsonファイルが出力される
df.to_json(WRITE_FILE_PATH)

# DataFrameをJSON形式の文字列に変換
json_data = df.to_json()

# 各orientでJSONに変換して表示
print(f"split:\n{df.to_json(orient='split')}\n")
print(f"records:\n{df.to_json(orient='records')}\n")
print(f"index:\n{df.to_json(orient='index')}\n")
print(f"columns:\n{df.to_json(orient='columns')}\n")
print(f"values:\n{df.to_json(orient='values')}\n")
print(f"table:\n{df.to_json(orient='table')}\n")

■ 出力結果

split:
{"columns":["id","name","age"],"index":[0,1,2],"data":[[1,"Alice",30],[2,"Bob",25],[3,"John",35]]}

records:
[{"id":1,"name":"Alice","age":30},{"id":2,"name":"Bob","age":25},{"id":3,"name":"John","age":35}]

index:
{"0":{"id":1,"name":"Alice","age":30},"1":{"id":2,"name":"Bob","age":25},"2":{"id":3,"name":"John","age":35}}

columns:
{"id":{"0":1,"1":2,"2":3},"name":{"0":"Alice","1":"Bob","2":"John"},"age":{"0":30,"1":25,"2":35}}

values:
[[1,"Alice",30],[2,"Bob",25],[3,"John",35]]

table:
{"schema":{"fields":[{"name":"index","type":"integer"},{"name":"id","type":"integer"},{"name":"name","type":"string"},{"name":"age","type":"integer"}],"primaryKey":["index"],"pandas_version":"1.4.0"},"data":[{"index":0,"id":1,"name":"Alice","age":30},{"index":1,"id":2,"name":"Bob","age":25},{"index":2,"id":3,"name":"John","age":35}]}

pandasでは、さまざまな形式のファイルを読み込み、データ分析・集計を行った後、他のフォーマット形式に変換・出力する可能です。

Pandasについては、下記の記事でもまとめられています。ぜひご覧ください。

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?