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オブジェクト の辞書
(複数のシートを読み込む場合)が返ってきます。
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
を指定することで、全てのシートを読み込みます。
# 配列で指定すると複数シート読み込み
df_dict = pandas.read_excel(READ_EXCEL_PATH, sheet_name=["Sheet1", "Sheet2"])
print(df_dict)
print(type(df_dict)) # <class 'dict'>
read_excel関数の主なパラメータ
# ヘッダー行の指定
# 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ファイルに書き込むためのメソッドです
- 指定したパスにファイルが存在しない場合は、生成されます
- 既に存在するファイル名を指定すると、既存のファイルのその内容を消去して上書きします
- シンプルな使い方ができ、単一のシートへの書き込みに適しています
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ファイルに追記などが可能になります
# 書き込みたいデータフレームを定義
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形式などに比べて、高速にデータ取得が可能な点などが、メリットです。
顧客ID,名前,性別,生年月日,入金金額
1 スズキM19800101 11000
2 マツモトF19900202 1000
3 タカハシM20000303 5000
4 ナカムラF19850115 300
5 アベM19950320 25000
shift-jisエンコード
固定長ファイルの読み込み
固定長ファイルを読み込む際は、pandas.read_fwf関数
を使用します。
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型
を固定長ファイルに出力するサンプルコードです。要件に合わせて、自作する必要があります。
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 関数
を使用します。
import pandas
# 読み込みたいファイルのパス
READ_FILE_PATH = r".\sample.csv"
df = pandas.read_csv(READ_FILE_PATH)
print(df)
■ 大規模なCSVファイルの読み込み
大規模なCSVファイルを処理するためにchunksize
パラメータを使用することで、効率的にCSVファイルを読み込み、処理することも可能です。
chunk
とは「大きな塊」という意味を持ち、大規模データを分割したひとまとまりの断片を指します。
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関数
を使用します。
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変換できます。
[
{
"id": 1,
"name": "Alice",
"age": 30
},
{
"id": 2,
"name": "Bob",
"age": 25
},
{
"id": 3,
"name": "John",
"age": 35
}
]
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構造のファイルを読み込む際には注意が必要です。
{
"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ファイルの読み込み
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形式の文字列に変換に変換されます。
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}} のような辞書 |
# サンプルデータフレーム
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については、下記の記事でもまとめられています。ぜひご覧ください。