PandasでExcel作業を効率化!ファイル読み書きの基本テクニック


PandasでExcel作業を効率化!ファイル読み書きの基本から応用まで

はじめに:なぜExcel作業にPandasを使うべきか?

ビジネスの世界では、Excelは依然として最も広く利用されているデータ管理・分析ツールの一つです。日々の業務でExcelファイルと向き合っている方は多いでしょう。しかし、手作業でのデータ入力、コピー&ペースト、数式の修正、複数のファイルの集計といった作業は、時間と労力がかかり、ヒューマンエラーも発生しやすいという課題があります。

ここで強力な味方となるのが、Pythonのデータ分析ライブラリである「Pandas」です。Pandasは、表形式データ(Excelのシートのような構造)を効率的に操作するための様々な機能を提供します。特に、Excelファイルの読み込みや書き出しに関しては、手作業では考えられないほどの柔軟性とスピードで処理を行うことができます。

  • 大量データの処理: 手作業やExcelのマクロでは困難な大量データも高速に処理できます。
  • 自動化: 定型的なExcel作業をスクリプトとして一度書いてしまえば、繰り返し実行できます。これにより、作業時間の劇的な短縮とミスの削減が実現します。
  • 複雑なデータ変換・集計: Pandasが提供する豊富なデータ操作機能(フィルタリング、ソート、グループ化、結合など)を組み合わせて、複雑な集計や分析を簡単に実現できます。
  • 他のライブラリとの連携: Pandasで読み込んだデータを、MatplotlibやSeabornで可視化したり、scikit-learnで機械学習モデルに投入したりと、Pythonのエコシステム全体を活用できます。

この記事では、Pandasを使ったExcelファイルの読み込み(pd.read_excel)と書き出し(DataFrame.to_excelpd.ExcelWriter)に焦点を当て、その基本的な使い方から、実務で役立つ応用テクニックまでを詳細に解説します。この記事を読めば、Excel作業の多くの部分を自動化し、より創造的で生産的な業務に時間を使えるようになるはずです。

実行環境の準備

Pandasを使ってExcelファイルを扱うためには、いくつかのライブラリが必要です。

  1. Python: まずPython自体がインストールされている必要があります。データ分析用途であれば、科学計算ライブラリ(Pandas, NumPyなど)やJupyter NotebookなどがセットになったAnacondaディストリビューションの利用が推奨されます。
  2. Pandas: Pandasライブラリ本体です。
  3. Excelファイル操作ライブラリ: PandasはExcelファイルの読み書きに内部的に他のライブラリを使用します。
    • openpyxl: .xlsx形式の読み書きに推奨されます。
    • xlsxwriter: .xlsx形式の書き出しに推奨されます。特に書式設定に強いライブラリです。
    • xlrd: .xls形式の読み込みに使用されていましたが、セキュリティ上の理由から新しいバージョンではデフォルトで無効になっています。.xlsファイルを扱う場合は注意が必要です。

ターミナルやコマンドプロンプトを開き、以下のコマンドを実行して必要なライブラリをインストールします。Anacondaを使っている場合は、Anaconda Promptを開いてください。

“`bash
pip install pandas openpyxl xlsxwriter

もし古い.xlsファイルも扱う場合は、xlrdもインストールする

pip install xlrd

“`

この記事では、対話的にコードを実行できるJupyter NotebookやJupyterLabでの実行を想定しています。こちらもAnacondaに含まれていることが多いです。

Excelファイルの読み込み (pd.read_excel)

ExcelファイルをPandas DataFrameとして読み込むには、pd.read_excel()関数を使用します。この関数には非常に多くの引数があり、様々な形式のExcelファイルに対応できるよう柔軟な読み込みが可能です。

まずは最も基本的な使い方から見ていきましょう。

基本的な読み込み

現在のディレクトリにある sample.xlsx という名前のファイルを読み込む場合、以下のようになります。

“`python
import pandas as pd

sample.xlsx というファイルを読み込む

df = pd.read_excel(‘sample.xlsx’)

読み込んだデータフレームの最初の5行を表示して確認

print(df.head())
“`

pd.read_excel() は、Excelファイルの最初のシートをDataFrameとして読み込みます。ファイルパスは絶対パスでも相対パスでも指定可能です。

  • 絶対パスの例: pd.read_excel('/Users/your_name/Documents/data/sample.xlsx')
  • 相対パスの例: pd.read_excel('../data/sample.xlsx') (一つ上の階層にあるdataフォルダ内のファイル)

読み込まれたデータは DataFrame と呼ばれるPandasのオブジェクトになります。これは、列と行を持つ二次元のラベル付きデータ構造で、Excelのシートをイメージすると分かりやすいでしょう。

シートの指定 (sheet_name)

Excelファイルには複数のシートが含まれていることがよくあります。pd.read_excel() はデフォルトでは最初のシート(インデックス 0)を読み込みますが、sheet_name 引数を使って読み込むシートを指定できます。

  • シート名を指定: 特定の名前のシートを読み込みます。

    “`python

    ‘商品リスト’ という名前のシートを読み込む

    df_products = pd.read_excel(‘sample.xlsx’, sheet_name=’商品リスト’)
    print(df_products.head())
    “`

  • シートインデックスを指定: 0から始まるインデックスでシートを指定します。

    “`python

    2番目のシート(インデックスは1)を読み込む

    df_sales = pd.read_excel(‘sample.xlsx’, sheet_name=1)
    print(df_sales.head())
    “`

  • 複数のシートを読み込む: シート名のリストを指定すると、指定した複数のシートを一度に読み込めます。この場合、戻り値はシート名をキー、DataFrameを値とする辞書型になります。

    “`python

    ‘商品リスト’と’売上データ’の2つのシートを読み込む

    dfs_dict = pd.read_excel(‘sample.xlsx’, sheet_name=[‘商品リスト’, ‘売上データ’])

    結果は辞書型になる

    print(type(dfs_dict))

    各シートのDataFrameにアクセス

    df_products = dfs_dict[‘商品リスト’]
    df_sales = dfs_dict[‘売上データ’]

    print(“\n— 商品リスト —“)
    print(df_products.head())
    print(“\n— 売上データ —“)
    print(df_sales.head())
    “`

  • すべてのシートを読み込む: sheet_name=None と指定すると、ファイル内のすべてのシートを読み込みます。この場合も戻り値はシート名をキーとする辞書型になります。

    “`python

    すべてのシートを読み込む

    all_sheets = pd.read_excel(‘sample.xlsx’, sheet_name=None)

    辞書のキー(シート名)を確認

    print(“読み込んだシート:”, all_sheets.keys())

    例: 最初のシートのDataFrameにアクセス

    first_sheet_name = list(all_sheets.keys())[0]
    df_first = all_sheets[first_sheet_name]
    print(f”\n— ‘{first_sheet_name}’ シート —“)
    print(df_first.head())
    “`

ヘッダーの指定 (header)

Excelファイルでは、データの最初の行が列名(ヘッダー)になっているのが一般的です。pd.read_excel() はデフォルトでファイルの最初の行をヘッダーとして認識します (header=0)。しかし、ヘッダー行がない場合や、ヘッダーが複数行にわたる場合など、状況に応じて header 引数を調整する必要があります。

  • ヘッダー行がない場合: データが最初の行から始まっており、ヘッダー行が存在しない場合は header=None を指定します。Pandasは自動的に0から始まる連番を列名として割り当てます。

    “`python

    ヘッダーがないファイルを読み込む

    df_no_header = pd.read_excel(‘data_no_header.xlsx’, header=None)
    print(df_no_header.head())

    列名は 0, 1, 2, … となる

    print(df_no_header.columns)
    “`

  • ヘッダー行を指定: ヘッダー行が最初の行ではない場合(例えば2行目から始まる場合)は、その行の0から始まるインデックスを指定します。

    “`python

    ヘッダーが2行目にある場合 (インデックスは1)

    df_header_row1 = pd.read_excel(‘data_with_info.xlsx’, header=1)
    print(df_header_row1.head())
    “`

  • 複数行をヘッダーとして使用 (MultiIndex): ヘッダーが複数行に分かれている場合(例えば、大分類と小分類で階層的なヘッダーになっている場合)は、使用する行のインデックスをリストで指定します。これにより、MultiIndex(階層的な列名)が作成されます。

    “`python

    1行目と2行目をヘッダーとして使用 (インデックスは0と1)

    df_multi_header = pd.read_excel(‘data_multi_header.xlsx’, header=[0, 1])
    print(df_multi_header.head())

    列名がタプルで構成されていることを確認

    print(df_multi_header.columns)
    “`

インデックス列の指定 (index_col)

DataFrameでは、各行を一意に識別するための「インデックス」があります。デフォルトでは、Pandasは0から始まる連番をインデックスとして使用します。しかし、Excelファイル中の特定の列をDataFrameのインデックスとして使用したい場合があります(例えば、顧客IDや商品コードなど)。これは index_col 引数で指定できます。

  • 特定の列をインデックスとして指定: インデックスとして使用したい列の0から始まるインデックスまたは列名を指定します。

    “`python

    最初の列(インデックスは0)をインデックスとして使用

    df_indexed = pd.read_excel(‘sample.xlsx’, index_col=0)
    print(df_indexed.head())
    print(df_indexed.index) # インデックスがその列の値になっていることを確認
    “`

    または列名で指定:

    “`python

    ‘商品コード’ 列をインデックスとして使用

    df_indexed_by_name = pd.read_excel(‘sample.xlsx’, index_col=’商品コード’)
    print(df_indexed_by_name.head())
    print(df_indexed_by_name.index)
    “`

  • 複数の列をインデックスとして使用 (MultiIndex): 複数列の組み合わせをインデックスにしたい場合は、列のインデックスまたは列名のリストを指定します。これによりMultiIndex(階層的なインデックス)が作成されます。

    “`python

    ‘カテゴリ’ 列と ‘商品コード’ 列を組み合わせてインデックスとして使用

    df_multi_indexed = pd.read_excel(‘sample.xlsx’, index_col=[‘カテゴリ’, ‘商品コード’])
    print(df_multi_indexed.head())
    print(df_multi_indexed.index) # MultiIndexになっていることを確認
    “`

特定の列だけを読み込む (usecols)

Excelファイルには多くの列が含まれている場合がありますが、分析や処理に必要なのはそのうちの一部だけかもしれません。usecols 引数を使うと、読み込む列を限定できます。これにより、メモリの使用量を抑えたり、不要な列を読み込まないことで処理速度を向上させたりできます。

  • 列名で指定: 読み込みたい列名のリストを指定します。

    “`python

    ‘商品名’, ‘価格’, ‘在庫数’ の3列だけを読み込む

    df_subset_cols = pd.read_excel(‘sample.xlsx’, usecols=[‘商品名’, ‘価格’, ‘在庫数’])
    print(df_subset_cols.head())
    print(df_subset_cols.columns) # 指定した列だけが読み込まれていることを確認
    “`

  • 列インデックスで指定: 読み込みたい列の0から始まるインデックスのリストを指定します。

    “`python

    1番目、3番目、5番目の列(インデックスは0, 2, 4)を読み込む

    df_subset_cols_idx = pd.read_excel(‘sample.xlsx’, usecols=[0, 2, 4])
    print(df_subset_cols_idx.head())
    print(df_subset_cols_idx.columns) # デフォルトの列名 (0, 2, 4) になるか、ヘッダーがあればその列名になる
    “`

  • 文字列形式で指定: Excelの列指定と同じような形式(’A’, ‘C:E’など)で指定することも可能です。これは内部的に openpyxlxlsxwriter がサポートしている機能を利用します。

    “`python

    1列目 (A), 3列目から5列目 (CからE) を読み込む

    df_subset_cols_str = pd.read_excel(‘sample.xlsx’, usecols=’A,C:E’)
    print(df_subset_cols_str.head())
    ``
    **注意**: この文字列形式の指定は、
    pd.read_excelが内部で使用するエンジンの機能に依存します。openpyxl` エンジンがデフォルトで使用されることが多いですが、環境によっては異なる場合があるため、確実なのは列名または列インデックスでの指定です。

  • 関数で指定: 列名を引数に取り、その列を読み込むかどうかをブール値で返す関数を指定することもできます。これは、特定のパターンに一致する列だけを読み込みたい場合などに便利です。

    “`python

    列名が ‘数量_’ で始まる列だけを読み込む

    df_filtered_cols = pd.read_excel(‘sample.xlsx’, usecols=lambda x: x.startswith(‘数量_’))
    print(df_filtered_cols.head())
    print(df_filtered_cols.columns) # ‘数量_’ で始まる列だけが読み込まれていることを確認
    “`

特定の行だけを読み込む (nrows, skiprows)

ファイル全体を読み込む必要がない場合、読み込む行数を限定したり、特定の行をスキップしたりすることができます。

  • 最初のN行を読み込む (nrows): ファイルの先頭から指定した行数だけを読み込みます。大きなファイルの内容を少しだけ確認したい場合などに便利です。ヘッダー行も行数に含まれることに注意してください。

    “`python

    最初の10行だけを読み込む (ヘッダー行を含む)

    df_first_10_rows = pd.read_excel(‘large_data.xlsx’, nrows=10)
    print(df_first_10_rows)
    “`

  • 特定の行をスキップする (skiprows): ファイルの特定の位置にある行(例えばファイル先頭にあるコメント行や説明文など)を読み飛ばすことができます。スキップしたい行の0から始まるインデックス、またはスキップしたい行数のリスト/範囲を指定します。

    “`python

    最初の行と3行目、6行目 (インデックスは0, 2, 5) をスキップして読み込む

    df_skip = pd.read_excel(‘data_with_comments.xlsx’, skiprows=[0, 2, 5])
    print(df_skip.head())
    “`

    または、ファイルの先頭からN行をスキップしたい場合は、その行数を指定します。

    “`python

    先頭から5行をスキップして読み込む

    注意: skiprowsに整数を指定した場合、それはヘッダー行の_後に_スキップする行数として解釈されることがあります。

    意図した動作にならない場合は、行インデックスのリストを指定するのが確実です。

    例: skiprows=range(1, 6) は1行目から5行目(インデックス0, 1, 2, 3, 4)をスキップ

    または、ヘッダー行を含む最初のN行をスキップしたい場合は、skiprows=[i for i in range(N)] のようにリストで指定します。

    df_skip_first_N = pd.read_excel(‘data_with_intro.xlsx’, skiprows=4) # 最初の4行をスキップして、5行目をヘッダーとして読み込む動作になる可能性あり

    確実に最初の4行 (インデックス 0, 1, 2, 3) をスキップしたい場合は:

    df_skip_first_4 = pd.read_excel(‘data_with_intro.xlsx’, skiprows=[0, 1, 2, 3])
    print(df_skip_first_4.head())
    ``skiprows`に整数を指定した場合の挙動は文脈依存で混乱しやすいため、スキップしたい具体的な行インデックスのリストを指定するのが最も明確で推奨される方法です。

データ型の指定 (dtype)

Pandasはデータを読み込む際に各列のデータ型(数値、文字列、日付など)を自動的に推測します。しかし、Excelのセルには様々なデータが含まれている可能性があり、意図しない型として読み込まれることがあります。例えば、数値のみで構成されている列でも、先頭にゼロが付くIDや郵便番号などは文字列として扱いたい場合があります。このような場合は dtype 引数を使って明示的にデータ型を指定できます。

dtype には、列名をキー、指定したいデータ型を値とする辞書を指定します。

“`python

‘商品コード’ 列を文字列として、’価格’ 列を浮動小数点数として読み込む

df_dtype = pd.read_excel(‘sample.xlsx’, dtype={‘商品コード’: str, ‘価格’: float})
print(df_dtype.dtypes) # 各列のデータ型を確認
print(df_dtype.head())
“`

日付/時刻列のパース (parse_dates)

日付や時刻を表す列が、読み込み後に文字列として扱われてしまうことがあります。parse_dates 引数に日付/時刻としてパースしたい列名をリストで指定すると、Pandasはこれらの列を datetime64[ns] という日付/時刻型に変換しようと試みます。

“`python

‘購入日’ 列を日付型として読み込む

df_dates = pd.read_excel(‘sample.xlsx’, parse_dates=[‘購入日’])
print(df_dates.dtypes) # ‘購入日’ が datetime64 型になっていることを確認
print(df_dates.head())
“`

複数の列を指定したり、複数の列を組み合わせて単一の日付/時刻列としてパースしたりすることも可能です。

欠損値の扱い (na_values)

Excelファイルでは、欠損値が空のセルとして表現されることが多いですが、特定の文字列(例: ‘-‘, ‘N/A’, ‘欠損’)で表現されている場合もあります。Pandasはデフォルトでいくつかの一般的な表現(空文字など)を欠損値 (NaN) として扱いますが、それ以外の文字列を欠損値として認識させたい場合は na_values 引数にその文字列、または文字列のリストを指定します。

“`python

‘-‘ と ‘N/A’ を欠損値として読み込む

df_na = pd.read_excel(‘data_with_na.xlsx’, na_values=[‘-‘, ‘N/A’])
print(df_na)
“`

その他の便利な引数

pd.read_excel() には、他にも様々な状況に対応するための引数があります。

  • comment: 指定した文字列で始まる行をコメントとして扱い、読み込みをスキップします。
  • skipfooter: ファイルの末尾から指定した行数をスキップします。
  • engine: 読み込みに使用するエンジンを指定します。通常は指定する必要はありませんが、特定のエンジンを使いたい場合や問題が発生した場合に 'openpyxl''xlrd' などを指定できます。

エラーハンドリング

ファイル操作では、ファイルが存在しない、ファイル形式が違うといったエラーが発生する可能性があります。最低限、ファイルが見つからない場合の FileNotFoundError は考慮しておくと良いでしょう。

python
try:
df = pd.read_excel('non_existent_file.xlsx')
print(df.head())
except FileNotFoundError:
print("エラー: 指定されたファイルが見つかりません。ファイルパスを確認してください。")
except Exception as e:
print(f"ファイルの読み込み中に予期せぬエラーが発生しました: {e}")

DataFrameの基本的な操作(読み込み後)

ExcelファイルをPandas DataFrameとして読み込んだら、次はデータを操作する段階です。Pandas DataFrameは非常に多機能ですが、ここでは読み込み後にまず行う可能性のある基本的な操作を紹介します。

  • データフレームの確認:

    • .head(n): 先頭n行を表示 (デフォルトは5行)
    • .tail(n): 末尾n行を表示 (デフォルトは5行)
    • .info(): データフレームの概要(行数、列数、各列の名前と非Null値の数、データ型、メモリ使用量など)を表示
    • .describe(): 数値列の基本統計量(平均、標準偏差、最小値、最大値、四分位数など)を計算して表示
    • .shape: データフレームの形状(行数、列数)をタプルで取得
    • .columns: 列名のリストを取得
    • .index: インデックスを取得
    • .dtypes: 各列のデータ型を取得

    python
    df = pd.read_excel('sample.xlsx')
    print(df.info())
    print("\n--- 統計量 ---")
    print(df.describe())
    print("\n--- 列名 ---")
    print(df.columns)

  • 列の選択:

    • 単一の列: df['列名'] または df.列名 (列名がPythonの変数名として有効な場合)
    • 複数の列: df[['列名A', '列名B', ...]]

    “`python

    ‘商品名’ 列を選択

    product_names = df[‘商品名’]
    print(product_names.head())

    ‘価格’ と ‘在庫数’ 列を選択

    price_stock = df[[‘価格’, ‘在庫数’]]
    print(price_stock.head())
    “`

  • 行の選択:

    • .loc[行ラベル, 列ラベル]: ラベル(インデックス名や列名)で選択
    • .iloc[行インデックス, 列インデックス]: 整数ベースのインデックスで選択

    “`python

    インデックスラベル ‘A101’ の行を選択 (index_col=’商品コード’で読み込んだ場合)

    df_indexed = pd.read_excel(‘sample.xlsx’, index_col=’商品コード’)

    print(df_indexed.loc[‘A101’])

    3番目の行 (インデックスは2) を選択

    print(df.iloc[2])

    1行目から3行目まで (インデックス 0, 1, 2) の ‘商品名’ と ‘価格’ 列を選択

    print(df.loc[0:2, [‘商品名’, ‘価格’]])
    print(df.iloc[0:3, [1, 2]]) # 商品名が2列目(idx 1), 価格が3列目(idx 2)と仮定
    “`

  • 条件による抽出 (Boolean Indexing): 特定の条件を満たす行だけを抽出します。

    “`python

    価格が1000円以上の商品を抽出

    high_price_items = df[df[‘価格’] >= 1000]
    print(high_price_items)

    在庫数が0の商品、かつ、カテゴリが’食品’の商品を抽出

    out_of_stock_food = df[(df[‘在庫数’] == 0) & (df[‘カテゴリ’] == ‘食品’)]
    print(out_of_stock_food)
    “`

これらの基本的な操作は、Excelファイルを読み込んだ後のデータ分析・加工の出発点となります。

Excelファイルへの書き出し (DataFrame.to_excel)

Pandas DataFrameで加工・集計した結果をExcelファイルとして保存するには、DataFrameの .to_excel() メソッドを使用します。

基本的な書き出し

DataFrame dfoutput.xlsx という名前のファイルに書き出す最も基本的な方法は以下の通りです。

“`python

df は Pandas DataFrame オブジェクトとする

output.xlsx という名前でファイルに書き出す

df.to_excel(‘output.xlsx’)
print(“output.xlsx が作成されました。”)
“`

このコマンドを実行すると、現在のディレクトリに output.xlsx ファイルが作成されます(同名のファイルがある場合は上書きされます)。デフォルトでは、DataFrameのインデックスも新しいファイルの最初の列として書き出されます。

シートの指定 (sheet_name)

書き出すシートの名前を指定するには sheet_name 引数を使用します。デフォルトは 'Sheet1' です。

“`python

‘集計結果’ という名前のシートに書き出す

df_summary.to_excel(‘summary_report.xlsx’, sheet_name=’集計結果’)
“`

インデックス、ヘッダーの書き出し有無 (index, header)

DataFrameのインデックスや列名(ヘッダー)をExcelファイルに含めたくない場合があります。

  • インデックスを書き出さない (index=False): DataFrameのインデックス列を除外して書き出します。

    “`python

    インデックスを書き出さない

    df.to_excel(‘output_no_index.xlsx’, index=False)
    “`

  • ヘッダーを書き出さない (header=False): DataFrameの列名を除外して、データの最初の行から書き出します。

    “`python

    ヘッダーを書き出さない

    df.to_excel(‘output_no_header.xlsx’, header=False)
    “`

もちろん、両方を同時に False にすることも可能です。

“`python

インデックスもヘッダーも書き出さない

df.to_excel(‘output_raw_data.xlsx’, index=False, header=False)
“`

特定の列だけを書き出す

.to_excel() メソッド自体に usecols のような引数はありません。書き出す列を限定したい場合は、.to_excel() を呼び出す前にDataFrameから必要な列だけを選択した新しいDataFrameを作成します。

“`python

‘商品コード’ と ‘商品名’ の列だけを選択して書き出す

df_subset = df[[‘商品コード’, ‘商品名’]]
df_subset.to_excel(‘output_subset_cols.xlsx’, index=False)
“`

書き出し開始位置の指定 (startrow, startcol)

Excelファイルの特定のセルから書き出しを開始したい場合があります。これは、ファイルの上部にタイトルや説明文を既に書いておき、その下にデータを書き込みたい場合などに便利です。startrowstartcol 引数で、0から始まる行・列インデックスを指定します。

“`python

3行目、2列目 (インデックスは 2, 1) から書き出しを開始

Excelでいうと C4 セルから始まる位置になります

df.to_excel(‘output_start_pos.xlsx’, startrow=2, startcol=1)
``
デフォルトでは、
startrow=0,startcol=0` となります。

欠損値の扱い (na_rep)

DataFrame中の欠損値 (NaN) をExcelファイルに書き出す際に、空のセルではなく特定の文字列で表現したい場合があります。na_rep 引数にその文字列を指定します。

“`python

欠損値を ‘データなし’ と表示して書き出す

df_with_na.to_excel(‘output_na_rep.xlsx’, na_rep=’データなし’)
“`

エンジンの指定 (engine)

読み込み時と同様に、書き出しに使用するエンジンを指定できます。'openpyxl' または 'xlsxwriter' がよく使われます。デフォルトでは、Pandasはファイルの拡張子(.xlsx)やインストールされているライブラリに基づいて適切なエンジンを選択しますが、明示的に指定することも可能です。特に、後述する書式設定を行いたい場合は 'xlsxwriter' を指定する必要があります。

“`python

xlsxwriter エンジンを使って書き出す

df.to_excel(‘output_xlsxwriter.xlsx’, engine=’xlsxwriter’)
“`

既存ファイルへの追記/上書きの注意点

.to_excel() メソッドは、指定したファイルが既に存在する場合、デフォルトではそのファイルを上書きし、指定したシートのみを含む新しいファイルを作成します。既存のファイルに新しいシートを追加したり、既存のシートの一部を更新したりする場合は、.to_excel() を単独で使うのではなく、後述する pd.ExcelWriter オブジェクトを使用する必要があります。

複数のシート/DataFrameの書き出し (ExcelWriter)

一つのExcelファイル内に複数のシートを作成したい、または複数のDataFrameをそれぞれ異なるシートに書き出したい場合は、pd.ExcelWriter クラスを使用します。

ExcelWriter オブジェクトは、開かれたExcelファイルへの「書き込みセッション」を管理します。このオブジェクトに対して各DataFrameの .to_excel() メソッドを呼び出し、最後にセッションを終了してファイルを保存します。

推奨されるのは with ステートメントを使う方法です。これにより、エラーが発生した場合でも確実にファイルが閉じられます。

“`python
import pandas as pd

仮のDataFrameを2つ作成

df1 = pd.DataFrame({‘col1’: [1, 2], ‘col2’: [3, 4]})
df2 = pd.DataFrame({‘colA’: [‘a’, ‘b’, ‘c’], ‘colB’: [‘x’, ‘y’, ‘z’]})

ExcelWriter オブジェクトを作成 (エンジンは xlsxwriter が書式設定に強いので推奨)

既存ファイルに追記したい場合は、mode=’a’, if_sheet_exists=’overlay’ or ‘replace’ などを検討する

(注意: openpyxl エンジンのみが既存ファイルへの追記モード (mode=’a’) を完全にサポートしています)

with pd.ExcelWriter(‘multi_sheet_output.xlsx’, engine=’xlsxwriter’) as writer:
# 最初のDataFrameを ‘Sheet1′ という名前のシートに書き出す
df1.to_excel(writer, sheet_name=’Sheet1’, index=False)

# 2番目のDataFrameを '別のシート' という名前のシートに書き出す
# 必要に応じて startrow/startcol や index=False など他の引数も指定可能
df2.to_excel(writer, sheet_name='別のシート', index=False, startrow=1, startcol=1)

with ブロックを抜けると、ファイルは自動的に保存・閉じられる

print(“multi_sheet_output.xlsx が作成されました。”)
“`

既存ファイルへの追記

pd.ExcelWritermode 引数で動作を指定できます。
* mode='w' (デフォルト): ファイルが存在すれば上書きし、存在しなければ新規作成。
* mode='a': ファイルが存在すれば追記モードで開き、存在しなければ新規作成。

ただし、mode='a' は主に openpyxl エンジンで使用可能であり、既存のシートの内容を部分的に更新する機能は限られます。基本的に to_excelmode='a' で呼び出すと、指定した sheet_name が既存ファイルにあればそのシート全体が上書きされ、なければ新しいシートとして追加されます。既存のシートの特定の部分だけを更新したい場合は、Pandasの機能だけでは難しく、openpyxl ライブラリを直接操作する必要が出てきます。

既存ファイルに新しいシートを追加する場合:

“`python
import pandas as pd

df_new_sheet = pd.DataFrame({‘新規データ’: [10, 20, 30]})

既存ファイル ‘existing_file.xlsx’ に新しいシート ‘新規シート’ を追加

openpyxl エンジンを使用し、モードを ‘a’ (append) に設定

sheet_name が既存の場合の挙動を if_sheet_exists で指定 (‘replace’, ‘new’, ‘overlay’, ‘error’)

try:
with pd.ExcelWriter(‘existing_file.xlsx’, engine=’openpyxl’, mode=’a’, if_sheet_exists=’replace’) as writer:
df_new_sheet.to_excel(writer, sheet_name=’新規シート’, index=False)
print(“既存ファイルにシートを追加しました。”)
except FileNotFoundError:
print(“エラー: 追記対象の既存ファイルが見つかりません。”)
except Exception as e:
print(f”追記中にエラーが発生しました: {e}”)

if_sheet_exists=’replace’ はデフォルトですが、明示すると意図が明確になります。

if_sheet_exists=’new’ を指定すると、同名シートがあればエラーになります。

if_sheet_exists=’overlay’ は同名シートに上書きしますが、DataFrameのサイズによっては既存のセルをクリアしません。注意が必要です。

“`

既存ファイルの操作(特に部分的な更新)は、pd.ExcelWritermode='a' だけでは限界があることを理解しておきましょう。

応用テクニック:Excelの書式設定 (xlsxwriter)

Pandasの .to_excel() メソッドは、基本的にはデータをExcelファイルに書き出す機能に特化しています。しかし、レポートとして見栄えを整えたい場合など、セルやシートに書式設定を適用したいことがあります。

書式設定は、xlsxwriter エンジンを使用した場合に pd.ExcelWriter オブジェクトを通じて行うことができます。xlsxwriter エンジンで ExcelWriter を作成すると、そのオブジェクトは内部的に xlsxwriter.Workbook オブジェクトと xlsxwriter.Worksheet オブジェクトを保持します。これらにアクセスすることで、xlsxwriter ライブラリが提供する豊富な書式設定機能を利用できます。

注意: xlsxwriter エンジンは書き出し専用であり、既存ファイルを読み込んで更新することはできません。書式設定を伴う書き出しは、通常、新しいファイルを作成するか、既存ファイルを完全に上書きする場合に行います。

書式設定を行う基本的な流れは以下の通りです。

  1. pd.ExcelWriterengine='xlsxwriter' で作成する。
  2. DataFrameを .to_excel() で書き出す。このとき writer オブジェクトを渡す。
  3. writer.bookwriter.sheets['シート名'] を通じて xlsxwriter の Workbook/Worksheet オブジェクトにアクセスする。
  4. これらのオブジェクトのメソッドを使って書式設定を適用する。
  5. writer.close() または with ブロックの終了でファイルを保存する。

以下に具体的な書式設定の例を示します。

“`python
import pandas as pd

df = pd.DataFrame({
‘商品コード’: [‘A101’, ‘B205’, ‘C310’, ‘D450’],
‘商品名’: [‘りんご’, ‘バナナ’, ‘みかん’, ‘ぶどう’],
‘価格’: [150, 200, 120, 300],
‘在庫数’: [50, 0, 30, 100],
‘更新日’: pd.to_datetime([‘2023-10-01’, ‘2023-10-05’, ‘2023-10-02’, ‘2023-10-03’])
})

output_file = ‘formatted_report.xlsx’

with pd.ExcelWriter(output_file, engine=’xlsxwriter’) as writer:
# DataFrameをシートに書き出す (インデックスは不要、ヘッダーは必要)
df.to_excel(writer, sheet_name=’商品データ’, index=False, startrow=1, startcol=0)
# startrow=1 とすることで、1行目(インデックス0)を空けておき、タイトルなどを書けるようにする

# xlsxwriter の Workbook オブジェクトと Worksheet オブジェクトを取得
workbook = writer.book
worksheet = writer.sheets['商品データ']

# --- タイトルを追加 ---
title_format = workbook.add_format({
    'bold': True,
    'font_size': 16,
    'align': 'center',
    'valign': 'vcenter',
    'fg_color': '#D7E4BC' # 薄緑色の背景
})
# 最初のセル (A1, インデックス 0,0) にタイトルを書き込み、セルを結合
worksheet.merge_range('A1:E1', '商品在庫レポート', title_format) # A1からE1まで結合

# --- ヘッダーに書式設定 ---
header_format = workbook.add_format({
    'bold': True,
    'text_wrap': True, # テキストを折り返す
    'valign': 'top',
    'fg_color': '#F2F2F2', # 薄い灰色の背景
    'border': 1 # 罫線
})
# DataFrameのヘッダーは startrow=1 なので、2行目 (インデックス 1) に書き出されている
# ヘッダーのセル範囲は A2 から E2
for col_num, value in enumerate(df.columns.values):
    worksheet.write(1, col_num, value, header_format)

# --- 列の幅を調整 ---
# 列のインデックス(0から始まる)と幅を指定
worksheet.set_column(0, 0, 15) # '商品コード' (A列) 幅 15
worksheet.set_column(1, 1, 25) # '商品名' (B列) 幅 25
worksheet.set_column(2, 2, 10) # '価格' (C列) 幅 10
worksheet.set_column(3, 3, 10) # '在庫数' (D列) 幅 10
worksheet.set_column(4, 4, 15) # '更新日' (E列) 幅 15

# --- 特定の列に書式設定 (例: 価格列に通貨形式、在庫数列に数値形式) ---
currency_format = workbook.add_format({'num_format': '#,##0"円"'})
number_format = workbook.add_format({'num_format': '#,##0'})
date_format = workbook.add_format({'num_format': 'yyyy/mm/dd'})

# データは startrow=1 なので、3行目 (インデックス 2) から始まる
# '価格' 列 (C列, インデックス 2) のデータ範囲に書式を適用
worksheet.set_column(2, 2, None, currency_format)
# '在庫数' 列 (D列, インデックス 3) のデータ範囲に書式を適用
worksheet.set_column(3, 3, None, number_format)
# '更新日' 列 (E列, インデックス 4) のデータ範囲に書式を適用
worksheet.set_column(4, 4, None, date_format)

# --- 条件付き書式 (例: 在庫数が0のセルを赤く表示) ---
# 条件付き書式を適用するセル範囲を指定 ('D3:D' + str(len(df) + 2)) はデータの最終行まで
# DataFrameが startrow=1 (2行目) から書き出されているので、データは3行目 (インデックス 2) から
# '在庫数' 列は D列 (インデックス 3)
data_start_row = 2
data_end_row = data_start_row + len(df) - 1
worksheet.conditional_format(f'D{data_start_row+1}:D{data_end_row+1}', {
    'type': 'cell',
    'criteria': '==',
    'value': 0,
    'format': workbook.add_format({'bg_color': '#FFC7CE', 'font_color': '#9C0006'}) # 薄赤色の背景と濃赤色の文字
})

# --- ウィンドウ枠の固定 (Freeze Panes) ---
# データのヘッダー行 (2行目) と最初の列 (商品コード) で固定
# 固定したい行・列の「次の」行・列のセルを指定
worksheet.freeze_panes('B3') # B3セルを指定 -> 1行目・2行目と A列 が固定される

# --- オートフィルターの設定 ---
# オートフィルターをかける範囲を指定
# ヘッダー行を含むデータの全範囲 'A2:E' + str(len(df) + 1)
worksheet.autofilter(f'A2:E{len(df) + 1}')

with ブロックを抜けるとファイルが保存される

print(f”{output_file} に書式付きで書き出しました。”)
“`

上記コードは、xlsxwriter の強力な書式設定機能のほんの一例です。セル結合、フォント、色、罫線、数値形式、条件付き書式、ウィンドウ枠の固定、オートフィルターなど、Excelの多くの機能をPandasと組み合わせて自動化できます。これらの機能の詳細については、xlsxwriterの公式ドキュメントを参照してください。

実践例:複数のExcelファイルを読み込み、集計して一つのファイルに書き出す

Pandasを使ったExcel作業自動化の典型的なシナリオとして、複数のExcelファイル(例えば、日別/店舗別の売上ファイル)からデータを読み込み、それらを結合・集計して、最終的なレポートとして一つのExcelファイルに書き出す、という処理があります。

ここでは、以下のようなシナリオを想定します。

  • data/sales_20231001.xlsx, data/sales_20231002.xlsx, … という形式で日別の売上データファイルがある。
  • 各ファイルは同じ列構造を持っている(例: 日付, 店舗ID, 商品コード, 売上金額, 数量)。
  • これらのファイルをすべて読み込み、日付ごとの総売上金額と総数量を計算したい。
  • 集計結果を daily_sales_summary.xlsx というファイルに書き出したい。

“`python
import pandas as pd
import glob # ファイルパス検索のためのモジュール
import os # OS関連の操作 (フォルダ作成など)

データファイルがあるフォルダを指定

data_folder = ‘data’

出力ファイル名を指定

output_file = ‘daily_sales_summary.xlsx’

— 1. 複数のファイルを読み込む —

指定したフォルダ内の、特定のパターンに一致するファイルリストを取得

例: dataフォルダ内の sales_YYYYMMDD.xlsx という名前のファイルすべて

file_pattern = os.path.join(data_folder, ‘sales_*.xlsx’)
excel_files = glob.glob(file_pattern)

if not excel_files:
print(f”エラー: 指定されたパターン ‘{file_pattern}’ に一致するファイルが見つかりません。”)
else:
print(f”以下のファイルを読み込みます: {excel_files}”)

# すべてのDataFrameを格納するリスト
all_dfs = []

# 各ファイルをループして読み込み、リストに追加
for file_path in excel_files:
    try:
        # ファイルを読み込む
        # 日付列を適切にパースすることを忘れずに
        df = pd.read_excel(file_path, parse_dates=['日付'])
        all_dfs.append(df)
        print(f"{file_path} を読み込みました。")
    except FileNotFoundError:
        print(f"警告: {file_path} が見つかりませんでした。スキップします。")
    except Exception as e:
        print(f"警告: {file_path} の読み込み中にエラーが発生しました: {e} スキップします。")

# 読み込んだすべてのDataFrameを一つに結合
if all_dfs:
    combined_df = pd.concat(all_dfs, ignore_index=True)
    print("\nすべてのファイルを結合しました。")
    print(combined_df.info())

    # --- 2. データを集計する ---
    # 日付ごとにグループ化し、売上金額と数量を合計
    daily_summary = combined_df.groupby('日付').agg({
        '売上金額': 'sum',
        '数量': 'sum'
    }).reset_index() # groupbyでできたインデックスを通常列に戻す

    # 日付でソート (必要に応じて)
    daily_summary = daily_summary.sort_values('日付')

    print("\n日別集計結果:")
    print(daily_summary.head())

    # --- 3. 集計結果をExcelファイルに書き出す ---
    # ExcelWriter を使用して、書式設定も行う場合
    try:
        with pd.ExcelWriter(output_file, engine='xlsxwriter') as writer:
            # 集計結果を書き出す (インデックスは不要)
            daily_summary.to_excel(writer, sheet_name='日別サマリー', index=False, startrow=1)

            # xlsxwriter の Workbook/Worksheet オブジェクトを取得
            workbook = writer.book
            worksheet = writer.sheets['日別サマリー']

            # ヘッダーの書式設定
            header_format = workbook.add_format({'bold': True, 'fg_color': '#FFFFCC', 'border': 1})
            for col_num, value in enumerate(daily_summary.columns):
                 # ヘッダーは startrow=1 なので 2行目 (インデックス 1) に書き込まれている
                worksheet.write(1, col_num, value, header_format)

            # 日付列の書式設定
            date_format = workbook.add_format({'num_format': 'yyyy/mm/dd'})
            worksheet.set_column(0, 0, 15, date_format) # '日付' 列 (A列, インデックス 0)

            # 数値列の書式設定
            number_format = workbook.add_format({'num_format': '#,##0'})
            worksheet.set_column(1, 1, 15, number_format) # '売上金額' 列 (B列, インデックス 1)
            worksheet.set_column(2, 2, 10, number_format) # '数量' 列 (C列, インデックス 2)

            # タイトル追加
            title_format = workbook.add_format({'bold': True, 'font_size': 14})
            worksheet.write('A1', '日別売上サマリー', title_format)


        print(f"\n集計結果を {output_file} に書き出しました。")

    except Exception as e:
         print(f"書き出し中にエラーが発生しました: {e}")

else:
    print("\n読み込むべきファイルがありませんでした。集計と書き出しはスキップされます。")

“`

この例を実行するには、まず data フォルダを作成し、その中にいくつか sales_YYYYMMDD.xlsx という名前でダミーのExcelファイルを作成しておく必要があります。

例:ダミーファイルの作成(Pythonで)

“`python

このコードは上記のコードとは別に実行してください

import pandas as pd
import os

data_folder = ‘data’
os.makedirs(data_folder, exist_ok=True) # dataフォルダがなければ作成

dates = pd.to_datetime([‘2023-10-01’, ‘2023-10-02’, ‘2023-10-03’])

for date in dates:
df_day = pd.DataFrame({
‘日付’: date,
‘店舗ID’: [f’S{i:03d}’ for i in range(1, 6)],
‘商品コード’: [‘A101’, ‘B205’, ‘C310’, ‘A101’, ‘B205’],
‘売上金額’: [1500, 2400, 1200, 300, 400],
‘数量’: [10, 12, 10, 2, 2]
})
# 日によってデータを少し変える
if date.day == 2:
df_day.loc[0, ‘売上金額’] = 1600
df_day.loc[1, ‘数量’] = 15
elif date.day == 3:
df_day = df_day.drop(index=[3, 4]) # 3日目はデータ少なめ
df_day[‘売上金額’] = df_day[‘売上金額’] * 0.8 # 少し割引

file_path = os.path.join(data_folder, date.strftime('sales_%Y%m%d.xlsx'))
df_day.to_excel(file_path, index=False)
print(f"ダミーファイル {file_path} を作成しました。")

“`

上記のコードを実行すると、data フォルダ内に3つのダミーファイルが作成されます。その後に最初の実践例コードを実行すると、これらのファイルを読み込み、集計し、整形された daily_sales_summary.xlsx が作成されるはずです。

この実践例は、Pandasを使ったExcel自動化の基本的な流れを示しています。ファイルリストの取得 (glob, os)、複数ファイルの読み込みと結合 (pd.read_excel, pd.concat)、データ集計 (groupby, agg)、そして結果の書き出しと書式設定 (pd.ExcelWriter, xlsxwriter) といった要素が含まれています。実際の業務では、これに加えてデータクリーニング、欠損値処理、データの型変換など、より複雑な処理が必要になることが多いでしょう。

トラブルシューティング

PandasでExcelファイルを扱う際に遭遇しやすい問題とその解決策をいくつか紹介します。

  • ModuleNotFoundError: No module named 'openpyxl' または 'xlsxwriter':

    • 原因: Excelファイルの読み書きに必要なライブラリ(openpyxlxlsxwriter)がインストールされていません。
    • 解決策: ターミナルまたはAnaconda Promptで pip install openpyxl xlsxwriter を実行してください。
  • FileNotFoundError: [Errno 2] No such file or directory: 'your_file.xlsx':

    • 原因: 指定したファイルパスにファイルが見つかりません。
    • 解決策:
      • ファイル名や拡張子が正しいか確認してください。
      • ファイルパスが正しいか確認してください。現在のスクリプトからの相対パスか、絶対パスを指定しているかを確認し、ファイルが存在する場所と一致しているか確認してください。os.getcwd() で現在の作業ディレクトリを確認すると良いでしょう。
      • ファイル名やフォルダ名に日本語や特殊文字が含まれている場合、文字コードの問題が発生することがあります。可能であれば英数字のみの名前を使用するか、パス指定に問題がないか慎重に確認してください。
  • XLRDError: Excel xlsx file; not supported:

    • 原因: 古い.xlsファイルを開こうとしており、新しいバージョンのxlrdがインストールされているか、セキュリティ上の理由で無効化されている場合に発生します。
    • 解決策: 新しいバージョンのPandasでは.xlsファイルの読み込みにはopenpyxlは使えません。xlrdをインストールする必要がありますが、新しいxlrd.xls形式をデフォルトではサポートしていません。非公式な回避策として、xlrdの特定の古いバージョン(例: pip install xlrd==1.2.0)をインストールすることで読み込めるようになる場合がありますが、セキュリティリスクがあるため推奨されません。可能であれば、Excelで.xlsファイルを.xlsx形式に変換して保存し直してから読み込むのが最も確実です。
  • BadZipFile: File is not a zip file:

    • 原因: ファイルが破損しているか、Excelファイル(.xlsx形式は実体としてはZIPファイル)として認識できない形式になっています。
    • 解決策: 元のExcelファイルがExcelで開けるか確認してください。ファイルが破損している場合は、可能な限り元のファイルを取得し直すか、バックアップから復元してください。
  • データ型が正しく読み込まれない: (例: 数値として読み込まれるべき列が文字列になっている、日付が文字列になっている)

    • 原因: Pandasの自動型推論が意図通りに行われなかった。Excelファイル内で、数値と文字列が混在している、日付の形式が不統一である、先頭に余分な空白が含まれているなどの問題がある。
    • 解決策:
      • pd.read_excel()dtype 引数を使って、読み込み時に明示的にデータ型を指定します。
      • 日付列は parse_dates 引数を使ってパースを試みます。
      • 読み込み後に、.astype() メソッドを使って型変換を行うか、文字列操作 (.str.strip(), .str.replace()) や数値変換 (pd.to_numeric()) を使ってデータをクレンジングします。
      • 元のExcelファイルを確認し、データの入力形式を統一することを検討します。
  • メモリ不足 (MemoryError):

    • 原因: 非常に大きなExcelファイルを一度に読み込もうとした場合に発生します。
    • 解決策:
      • pd.read_excel()nrowsusecols 引数を使って、必要なデータだけを読み込むようにします。
      • chunksize 引数を使って、ファイルを小さなチャンク(塊)に分割して読み込み、少しずつ処理します。これは、集計など、データ全体を一度にメモリに保持する必要がない場合に有効です。

    “`python

    chunksize を指定して大きなファイルを分割読み込み

    chunk_size = 10000 # 例: 10000行ずつ読み込む
    all_chunks = []
    try:
    for chunk in pd.read_excel(‘very_large_file.xlsx’, chunksize=chunk_size):
    # 各チャンクに対して処理を行う (例: 集計、加工など)
    # この例では単にリストに追加するだけですが、実際にはここで集計などを進める
    all_chunks.append(chunk)
    print(f”チャンク {len(all_chunks)} を読み込みました。行数: {len(chunk)}”)

    # 必要であれば、すべてのチャンクを結合する (ただしメモリに収まる場合のみ)
    # large_df = pd.concat(all_chunks, ignore_index=True)
    # print("\nすべてのチャンクを結合しました。")
    # print(large_df.info())
    

    except Exception as e:
    print(f”分割読み込み中にエラーが発生しました: {e}”)
    “`
    * より高性能なコンピューターを使用するか、不要なメモリ消費を抑えるコード最適化を行います。

  • 書き出し時にファイルがロックされている:

    • 原因: 書き出し対象のExcelファイルが、Excelや他のアプリケーションで開かれている場合に発生します。
    • 解決策: 対象のExcelファイルを閉じ、再度スクリプトを実行してください。

まとめ

この記事では、Pandasを使ったExcelファイルの読み込み (pd.read_excel) と書き出し (DataFrame.to_excel, pd.ExcelWriter) の基本から応用までを詳しく解説しました。

  • pd.read_excel を使うことで、ファイルパス、シート、ヘッダー、インデックス、読み込む列や行、データ型、欠損値などを細かく指定してExcelファイルをDataFrameとして柔軟に読み込めること。
  • 読み込んだDataFrameに対して、.head(), .info(), 列選択、行選択、条件抽出といった基本的なデータ操作が行えること。
  • .to_excel メソッドでDataFrameをExcelファイルに書き出せること。シート名、インデックス/ヘッダーの書き出し有無、開始位置などを指定できること。
  • pd.ExcelWriter を使うことで、一つのExcelファイルに複数のシートを書き出したり、xlsxwriter エンジンと組み合わせて豊富な書式設定を適用したりできること。
  • 複数のExcelファイルを読み込み、集計して一つのファイルに書き出すといった実践的なシナリオ。
  • Excel操作における一般的なトラブルシューティング。

Pandasは、ExcelのGUI操作やマクロでは実現が難しいような、大量データの高速処理、複雑なデータ変換、定型作業の完全自動化を可能にします。最初は慣れないPythonのコーディングに戸惑うかもしれませんが、一度習得すれば、日々のExcel作業から解放され、データ分析やレポート作成の効率が飛躍的に向上するはずです。

ぜひ、この記事で学んだ内容を参考に、あなたのExcel作業をPandasで自動化してみてください。

参考資料

これらの公式ドキュメントは、さらに詳細な情報や、この記事で触れられなかった応用的な機能(例えば、xlsxwriterでのグラフ作成やデータ検証など)を知る上で非常に役立ちます。


: 約5000語という指定に合わせて、各セクションを非常に詳細に記述しました。特に read_excelto_excel の引数、ExcelWriter を使った複数シート書き出しや書式設定のパートに重点を置いて説明とコード例を豊富に含めました。実践例やトラブルシューティングも、具体的なシナリオと解決策を盛り込みました。単語数は目安であり、正確に5000語を保証するものではありませんが、内容は十分に詳細かつ網羅的であるはずです。

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール