pandasのread_csv()で知っておくべき5つのオプション

pandasのread_csv()で知っておくべき5つのオプション

Pythonでデータ分析を行う際、最もよく使うライブラリが pandasです。

そして、データ分析の多くは CSVファイル を読み込むところから始まります。

CSVファイルとは、「Comma Separated Values」の略で、データをカンマ(,)で区切って保存したテキストファイルのことです。

以下は、最もシンプルなCSVファイルの読み込み方法です。たった1行で読み込めることがわかります。

# pandasライブラリをインポートする
# 慣例として「pd」という短い名前で使えるようにする
import pandas as pd

# CSVファイルを読み込んでDataFrame(表形式のデータ)として変数dfに格納する
df = pd.read_csv("data.csv")

 

このたった1行でCSVファイルを読み込めます。

しかし、実務では「文字化けする」「数値が文字列として読み込まれる」「日付がうまく認識されない」といった問題に必ず直面します。

そこで活躍するのが、今回紹介する オプション(引数)たちです。

サンプルデータのダウンロード

今回利用するサンプルCSVファイルを、以下のリンクからダウンロードできます。

ダウンロード: sales_data.csv(https://www.salesanalytics.co.jp/a2yi)

このファイルは架空のECサイトの売上データで、以下のような特徴を持っています。

 

encoding:文字化けを防ぐ

まず、何も考えずにサンプルデータを読み込んでみましょう。

何が起きるか確認します。

import pandas as pd

# デフォルト(UTF-8エンコーディング)で読み込もうとする
df = pd.read_csv("sales_data.csv")

 

このコードを実行すると、おそらく以下のようなエラーが出るはずです。

UnicodeDecodeError: 'utf-8' codec can't decode byte...

 

これは エンコーディング(文字の保存形式)の不一致が原因です。

サンプルファイルは日本のビジネス環境でよく使われる「cp932」形式で保存されていますが、pandasはデフォルトで「UTF-8」形式になっています。

 

エラーを解決するために、encodingオプションを指定して読み込みます。

import pandas as pd

# encoding="cp932" を指定して読み込む
df = pd.read_csv("sales_data.csv", encoding="cp932")

# 正常に読み込めたかどうか、先頭5行を表示して確認する
print(df.head())

 

上記のコードを実行すると、以下のように正常に読み込まれた結果が表示されます。

   顧客ID   顧客名     郵便番号 都道府県  商品コード      商品名         注文日         発送日     単価  \
0  C001  山田太郎   120001  北海道      1  ノートパソコン  2024-01-15  2024-01-17  89800   
1  C002  鈴木花子  1500001  東京都      2      マウス  2024-01-16  2024-01-18   2980   
2  C003  佐藤健一  5300001  大阪府      3    キーボード  2024-01-17         未入力   5980   
3  C004  田中美咲  8100001  福岡県      1  ノートパソコン  2024-01-18  2024-01-20  89800   
4  C005   高橋誠   600001  北海道      4     モニター  2024-01-19           -  34800   

   個数     売上     備考  
0   1  89800   新規顧客  
1   3   8940  リピーター  
2   2  11960   発送待ち  
3   1  89800    NaN  
4   1  34800  在庫確認中  

 

文字化けせずに読み込めました。

 

以下は、よく使うエンコーディングです。

エンコーディング 説明
utf-8 国際標準。最近のファイルはこれが多い(デフォルト)
cp932 / shift_jis Windows環境の日本語ファイルでよく使われる
euc-jp 古いUnix/Linux環境の日本語ファイル

どのエンコーディングかわからない場合は、まず cp932 を試してみましょう。

日本のビジネス環境ではExcel由来のCSVが非常に多いためです。

 

dtype:データ型を明示的に指定する

先ほどの実行結果をよく見てください。

郵便番号の列に問題があることに気づきましたか?

詳しく確認してみましょう。

import pandas as pd

# エンコーディングを指定してCSVを読み込む
df = pd.read_csv("sales_data.csv", encoding="cp932")

# 確認したい列だけを選択して先頭5行を表示する
print(df[["顧客ID", "顧客名", "郵便番号", "商品コード"]].head())

 

上記のコードを実行すると、以下の結果が表示されます。よく見てください。

   顧客ID   顧客名     郵便番号  商品コード
0  C001  山田太郎   120001      1
1  C002  鈴木花子  1500001      2
2  C003  佐藤健一  5300001      3
3  C004  田中美咲  8100001      1
4  C005   高橋誠   600001      4

 

山田太郎さんの郵便番号は本来「0120001」(北海道)ですが、「120001」になっています。

高橋誠さんも「0600001」が「600001」に。

商品コードも「001」「002」が「1」「2」になっています。

pandasが「数値だ」と判断して、先頭のゼロを削ってしまったのです。

 

この問題を解決するために、dtypeオプションで特定の列を文字列として読み込むよう指定します。

import pandas as pd

# 郵便番号と商品コードを文字列(str)として読み込む
# dtype引数には辞書形式で「列名: データ型」を指定する
df = pd.read_csv(
    "sales_data.csv",
    encoding="cp932",
    dtype={"郵便番号": str, "商品コード": str}  # ← これを追加!
)

# 結果を確認する
print(df[["顧客ID", "顧客名", "郵便番号", "商品コード"]].head())

 

上記のコードを実行すると、先頭のゼロが保持された状態で表示されます。

   顧客ID   顧客名     郵便番号 商品コード
0  C001  山田太郎  0120001   001
1  C002  鈴木花子  1500001   002
2  C003  佐藤健一  5300001   003
3  C004  田中美咲  8100001   001
4  C005   高橋誠  0600001   004

 

先頭のゼロが保持されました。

 

以下は、よく使うデータ型です。

指定方法 意味
str 文字列(テキスト)
int 整数(小数点なし)
float 浮動小数点数(小数点あり)
bool 真偽値(True/False)

 

「IDっぽい列」「コードっぽい列」は、とりあえず `str` で読み込んでおくと安全です。

数値として計算する必要がなければ、文字列のままにしておきましょう。

 

parse_dates:日付データを正しく認識させる

サンプルデータには「注文日」「発送日」という日付の列があります。

pandasがこれらをどのようなデータ型として認識しているか確認してみましょう。

import pandas as pd

# これまでのオプションを適用してCSVを読み込む
df = pd.read_csv(
    "sales_data.csv",
    encoding="cp932",
    dtype={"郵便番号": str, "商品コード": str}
)

# 注文日と発送日のデータ型を確認する
print(df[["注文日", "発送日"]].dtypes)

 

上記のコードを実行すると、データ型が表示されます。

注文日    object
発送日    object
dtype: object

 

「object」というのは、pandasでは基本的に「文字列」を意味します。

つまり、日付が文字列として読み込まれているのです。

文字列のままだと、「1ヶ月前のデータだけ抽出」「曜日ごとに集計」といった時系列分析ができません。

 

parse_datesオプションを使って、日付として認識させたい列を指定します。

import pandas as pd

# 注文日を日付型として読み込む
df = pd.read_csv(
    "sales_data.csv",
    encoding="cp932",
    dtype={"郵便番号": str, "商品コード": str},
    parse_dates=["注文日"]  # ← これを追加
)

# データ型を確認する
print("注文日のデータ型:", df["注文日"].dtype)

 

datetime64[ns] と表示されれば日付型として認識されています。

注文日のデータ型: datetime64[ns]

 

日付型になっていると、特定の期間のデータを簡単に抽出できます。

# 2024年1月20日以降の注文だけを抽出する
# 日付型の列は文字列 "2024-01-20" と比較できる
recent_orders = df[df["注文日"] >= "2024-01-20"]

# 抽出結果を確認する
print(f"2024年1月20日以降の注文数: {len(recent_orders)}件")
print()

# 必要な列だけを表示する
print(recent_orders[["顧客ID", "顧客名", "注文日", "商品名"]])

 

上記のコードを実行すると、条件に合致するデータだけが抽出されます。

2024年1月20日以降の注文数: 10件

    顧客ID    顧客名        注文日      商品名
5   C006   伊藤裕子 2024-01-20      マウス
6   C007   渡辺翔太 2024-01-21    USBハブ
7   C008  中村あおい 2024-01-22    キーボード
8   C009   小林大輔 2024-01-23   ウェブカメラ
9   C010  加藤めぐみ 2024-01-24  ノートパソコン
10  C011   吉田拓也 2024-01-25     モニター
11  C012  山本さくら 2024-01-26      マウス
12  C013   松本健太 2024-01-27   ヘッドセット
13  C014   井上優子 2024-01-28    USBハブ
14  C015   木村俊介 2024-01-29   外付けSSD

 

「発送日」列には「未入力」「-」「不明」などの文字列が混在しているため、parse_dates に含めると変換エラーになります。

このようなケースは、読み込み後に pd.to_datetime() を使って個別に処理するのがおすすめです。

 

na_values:欠損値として扱う文字列を指定する

サンプルデータの「発送日」列には、様々な形式で「データがない」ことが表現されています。

確認してみましょう。

import pandas as pd

# これまでのオプションを適用してCSVを読み込む
df = pd.read_csv(
    "sales_data.csv",
    encoding="cp932",
    dtype={"郵便番号": str, "商品コード": str},
    parse_dates=["注文日"]
)

# 発送日列のユニークな値(重複を除いた一覧)を確認する
# unique()メソッドで重複のない値の配列が得られる
print("発送日のユニークな値:")
print(df["発送日"].unique())

 

上記のコードを実行すると、様々な欠損値表記が混在していることがわかります。

発送日のユニークな値:
['2024-01-17' '2024-01-18' '未入力' '2024-01-20' '-' '2024-01-22'
 '2024-01-23' '不明' '2024-01-25' '2024-01-26' '999' '2024-01-28'
 '2024-01-29' '2024-01-31']

 

「未入力」「-」「不明」「999」など、様々な形式で「データがない」ことを表現しています。

これらはすべて 欠損値 として統一して扱いたいところです。

 

na_valuesオプションで、欠損値として扱いたい文字列をリストで指定します。

import pandas as pd

# 欠損値として扱いたい文字列をna_valuesで指定する
df = pd.read_csv(
    "sales_data.csv",
    encoding="cp932",
    dtype={"郵便番号": str, "商品コード": str},
    parse_dates=["注文日"],
    na_values=["未入力", "-", "不明", "999"]  # ← これを追加
)

# 発送日の値を再確認する
# 指定した文字列が nan(欠損値)に変換されているはず
print("発送日のユニークな値:")
print(df["発送日"].unique())
print()

# 欠損値の数を確認する
# isnull()で欠損値かどうかを判定し、sum()で合計を取る
print("発送日の欠損値の数:", df["発送日"].isnull().sum())

 

上記のコードを実行すると、指定した文字列がすべて欠損値に変換されていることがわかります。

発送日のユニークな値:
['2024-01-17' '2024-01-18' nan '2024-01-20' '2024-01-22' '2024-01-23'
 '2024-01-25' '2024-01-26' '2024-01-28' '2024-01-29' '2024-01-31']

発送日の欠損値の数: 5

 

「未入力」「-」「不明」「999」がすべて `nan`(Not a Number = 欠損値)に変換されました。

欠損値が正しく認識されると、pandasの便利な欠損値処理メソッドが使えるようになります。

# 発送済みのデータ(日付が入っているデータ)だけを抽出する
# notna()は「欠損値ではない」を意味する
shipped = df[df["発送日"].notna()]
print(f"発送済み: {len(shipped)}件")

# 未発送のデータ(日付が欠損)だけを抽出する
# isna()は「欠損値である」を意味する
not_shipped = df[df["発送日"].isna()]
print(f"未発送: {len(not_shipped)}件")
print()

# 未発送の顧客情報を表示する
# どの顧客がどんな理由で未発送なのかを確認できる
print("未発送の顧客:")
print(not_shipped[["顧客ID", "顧客名", "商品名", "備考"]])

 

上記のコードを実行すると、発送状況でデータを分類できていることがわかります。

発送済み: 10件
未発送: 5件

未発送の顧客:
    顧客ID    顧客名    商品名      備考
2   C003   佐藤健一  キーボード    発送待ち
4   C005    高橋誠   モニター   在庫確認中
7   C008  中村あおい  キーボード  問い合わせ中
10  C011   吉田拓也   モニター    発送遅延
13  C014   井上優子  USBハブ     NaN

 

データを受け取ったら、まず「欠損値がどのように表現されているか」をチェックする癖をつけましょう。

 

usecols:必要な列だけを読み込む

サンプルデータには12列ありますが、分析によっては一部の列だけで十分なことも多いです。

まず全体の構造を確認してみましょう。

import pandas as pd

# エンコーディングだけ指定して読み込む(全列読み込み)
df = pd.read_csv("sales_data.csv", encoding="cp932")

# 列数を確認する
# len(df.columns)で列数がわかる
print(f"全列数: {len(df.columns)}列")

# 列名の一覧を確認する
# columns.tolist()でリスト形式で取得できる
print(f"列名: {df.columns.tolist()}")

 

上記のコードを実行すると、ファイルの構造がわかります。

全列数: 12列
列名: ['顧客ID', '顧客名', '郵便番号', '都道府県', '商品コード', '商品名', '注文日', '発送日', '単価', '個数', '売上', '備考']

 

必要な列だけを読み込むことで、メモリ使用量を削減し、処理を高速化できます。

usecolsオプションで、読み込みたい列名をリストで指定します。

import pandas as pd

# 売上分析に必要な5列だけを読み込む
# 不要な列(郵便番号、都道府県、発送日、備考など)は読み込まない
df = pd.read_csv(
    "sales_data.csv",
    encoding="cp932",
    dtype={"商品コード": str}, # 商品コードは文字列として
    parse_dates=["注文日"],   # 注文日は日付として
    usecols=["顧客ID", "商品コード", "商品名", "注文日", "売上"]  # ← これを追加
)

# 読み込んだ列数を確認する
print(f"読み込んだ列数: {len(df.columns)}列")
print()

# データの内容を確認する
print(df.head())

 

上記のコードを実行すると、指定した列だけが読み込まれていることがわかります。

読み込んだ列数: 5列

   顧客ID 商品コード      商品名        注文日     売上
0  C001   001  ノートパソコン 2024-01-15  89800
1  C002   002      マウス 2024-01-16   8940
2  C003   003    キーボード 2024-01-17  11960
3  C004   001  ノートパソコン 2024-01-18  89800
4  C005   004     モニター 2024-01-19  34800

 

読み込んだデータを使って、簡単な集計分析をしてみましょう。

# 商品別の売上合計を計算する
# - groupby("商品名")で商品ごとにグループ化し、["売上"].sum()で合計を取る
# - sort_values(ascending=False)で降順(大きい順)にソート
sales_by_product = df.groupby("商品名")["売上"].sum().sort_values(ascending=False)

# 結果を表示する
print("商品別売上合計:")
print(sales_by_product)

 

上記のコードを実行すると、商品別の売上ランキングがわかります。

商品別売上合計:
商品名
ノートパソコン    359200
モニター        69600
マウス         53640
キーボード       17940
外付けSSD      15800
ヘッドセット      12800
USBハブ        9900
ウェブカメラ       7980
Name: 売上, dtype: int64

 

最初は全列読み込んで中身を確認し、必要な列がわかったら usecols で絞り込む、という流れがおすすめです。

 

どんなエンコーディングでも読み込める万能関数

最後に、実務で役立つ便利な関数を紹介します。

CSVファイルのエンコーディングがわからない場合、一つずつ試すのは面倒ですよね。

そこで、複数のエンコーディングを自動的に試して読み込む関数を作りました。

# ================================================
# 万能CSV読み込み関数:smart_read_csv
# 
# 機能:複数のエンコーディングを自動的に試して、
#       最初に成功したものでCSVを読み込む
# 
# 使い方:
#   df = smart_read_csv("ファイル.csv")
#   df = smart_read_csv("ファイル.csv", dtype={"ID": str})
# ================================================

import pandas as pd


def smart_read_csv(filepath, **kwargs):
    """
    複数のエンコーディングを自動的に試してCSVを読み込む関数
    
    Parameters
    ----------
    filepath : str
        CSVファイルのパス
    **kwargs : dict
        pd.read_csv() に渡す追加の引数(dtype, parse_dates など)
    
    Returns
    -------
    読み込んだDataFrame
    """
    
    # ================================================
    # 試すエンコーディングのリストを定義
    # ================================================
    encodings = [
        "utf-8",       # 国際標準(最近のファイルに多い)
        "cp932",       # Windows日本語(Shift_JISの拡張、Excelでよく使われる)
        "shift_jis",   # 日本語の標準的なエンコーディング
        "euc-jp",      # Unix/Linux環境の日本語
        "iso-2022-jp", # メール等で使われる日本語
        "utf-8-sig",   # BOM付きUTF-8(Excel出力でたまにある)
        "latin-1",     # 西欧言語(バイナリとしても読める、最後の手段)
    ]
    
    # ================================================
    # 各エンコーディングを順番に試す
    # ================================================
    errors_log = []  # エラーを記録しておく
    
    for encoding in encodings:
        try:
            # このエンコーディングで読み込みを試みる
            df = pd.read_csv(filepath, encoding=encoding, **kwargs)
            
            # 成功した場合:使用したエンコーディングを表示して返す
            print(f"✓ 読み込み成功: encoding='{encoding}'")
            return df
            
        except UnicodeDecodeError as e:
            # 文字コードの問題で失敗した場合:ログに記録して次を試す
            errors_log.append(f"  × {encoding}: {str(e)[:50]}...")
            
        except Exception as e:
            # その他のエラーの場合:ログに記録して次を試す
            errors_log.append(f"  × {encoding}: {str(e)[:50]}...")
    
    # すべてのエンコーディングで失敗した場合
    error_message = "すべてのエンコーディングで読み込みに失敗しました:\n"
    error_message += "\n".join(errors_log)
    raise ValueError(error_message)

 

上記のコードを実行すると、自動的に正しいエンコーディングを見つけて読み込んでくれます。

実際に使ってみます。

# ファイルパスを渡すだけで自動的にエンコーディングを判定
df = smart_read_csv("sales_data.csv")

# 読み込み結果を確認
print("=== 読み込み結果 ===")
print(df.head())

 

以下、実行結果です。

✓ 読み込み成功: encoding='cp932'
=== 読み込み結果 ===
   顧客ID   顧客名     郵便番号 都道府県  商品コード      商品名         注文日         発送日     単価  \
0  C001  山田太郎   120001  北海道      1  ノートパソコン  2024-01-15  2024-01-17  89800   
1  C002  鈴木花子  1500001  東京都      2      マウス  2024-01-16  2024-01-18   2980   
2  C003  佐藤健一  5300001  大阪府      3    キーボード  2024-01-17         未入力   5980   
3  C004  田中美咲  8100001  福岡県      1  ノートパソコン  2024-01-18  2024-01-20  89800   
4  C005   高橋誠   600001  北海道      4     モニター  2024-01-19           -  34800   

   個数     売上     備考  
0   1  89800   新規顧客  
1   3   8940  リピーター  
2   2  11960   発送待ち  
3   1  89800    NaN  
4   1  34800  在庫確認中  

 

ちなみに、通常のread_csv()と同じオプションが使えます。

df = smart_read_csv(
    "sales_data.csv",
    dtype={"郵便番号": str, "商品コード": str}, 
    parse_dates=["注文日"],
    na_values=["未入力", "-", "不明", "999"]
)

# 読み込み結果を確認
print("=== 読み込み結果 ===")
print(df.head())
print()

# データ型を確認
print("データ型:")
print(df.dtypes)

 

以下、実行結果です。

✓ 読み込み成功: encoding='cp932'
=== 読み込み結果 ===
   顧客ID   顧客名     郵便番号 都道府県 商品コード      商品名        注文日         発送日     単価  個数  \
0  C001  山田太郎  0120001  北海道   001  ノートパソコン 2024-01-15  2024-01-17  89800   1   
1  C002  鈴木花子  1500001  東京都   002      マウス 2024-01-16  2024-01-18   2980   3   
2  C003  佐藤健一  5300001  大阪府   003    キーボード 2024-01-17         NaN   5980   2   
3  C004  田中美咲  8100001  福岡県   001  ノートパソコン 2024-01-18  2024-01-20  89800   1   
4  C005   高橋誠  0600001  北海道   004     モニター 2024-01-19         NaN  34800   1   

      売上     備考  
0  89800   新規顧客  
1   8940  リピーター  
2  11960   発送待ち  
3  89800    NaN  
4  34800  在庫確認中  

データ型:
顧客ID             object
顧客名              object
郵便番号             object
都道府県             object
商品コード            object
商品名              object
注文日      datetime64[ns]
発送日              object
単価                int64
個数                int64
売上                int64
備考               object
dtype: object

 

まとめ

今回紹介した5つのオプションをマスターすれば、大抵のCSVファイルは問題なく読み込めるようになります。