ビッグデータの活用が当たり前となった現代において、PythonのPandasはデータ解析のデファクトスタンダードとして君臨しています。
しかし、大規模なデータセットを扱う際に多くのエンジニアが直面するのが、メモリ不足による処理の遅延やクラッシュの問題です。
特にローカル環境やクラウドの限られたリソース内で効率的に分析を行うためには、メモリ使用量を正確に把握することが欠かせません。
本記事では、Pandasでデータフレームのメモリ使用量を確認する主要な方法であるinfo()メソッドとmemory_usage()メソッドの使い分けについて詳しく説明します。
さらに、単に確認するだけでなく、どのようにしてメモリ効率を改善していくかという実践的なテクニックについても深掘りしていきます。
Pandasにおけるメモリ管理の重要性
データ分析の現場では、数百万行、数千万行といったデータを扱うことが珍しくありません。
Pandasは非常に強力なライブラリですが、デフォルト設定のままでは必要以上にメモリを消費してしまう傾向があります。
これは、Pandasがデータの柔軟性を確保するために、各要素に対して余裕を持ったデータ型(dtype)を割り当てるためです。
メモリが不足するとスワップが発生して処理速度が極端に低下し、最悪の場合はプログラムが強制終了してしまいます。
そのため、データ分析の初期段階で現在のメモリ使用量を正確に測定し、最適化の余地を探ることが重要です。
2026年現在のモダンな開発環境においても、リソースの最適化はコスト削減とパフォーマンス向上の両面で極めて価値のある作業と言えます。
df.info()を用いた全体像の把握
データフレームのメモリ使用量を手軽に確認する最も一般的な方法は、df.info()メソッドを使用することです。
このメソッドは、データフレームの行数、列数、各列のデータ型、非欠損値の数、そしてメモリ使用量の要約を一度に表示してくれます。
info()の基本的な使い方
まずは、基本的なinfo()の実行例を見てみましょう。
import pandas as pd
import numpy as np
# サンプルデータの作成
df = pd.DataFrame({
'id': range(1000000),
'value': np.random.randn(1000000),
'category': ['A', 'B', 'C', 'D'] * 250000
})
# 基本的な情報の表示
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1000000 entries, 0 to 999999
Data columns (total 3 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 id 1000000 non-null int64
1 value 1000000 non-null float64
2 category 1000000 non-null object
dtypes: float64(1), int64(1), object(1)
memory usage: 22.9+ MB
出力結果の最後に表示される「memory usage」が、そのデータフレームが消費しているおおよそのメモリ量です。
正確なメモリ量を知るための「memory_usage=’deep’」
ただし、デフォルトのinfo()が表示するメモリ使用量は、推定値であることに注意が必要です。
特にobject型(文字列など)を含む場合、Pandasはポインタのサイズのみを計算し、実際に参照されている文字列の実体サイズを計算に含めません。
より正確なメモリ使用量を確認するには、引数にmemory_usage='deep'を指定する必要があります。
# より正確なメモリ使用量を表示
df.info(memory_usage='deep')
memory usage: 78.2 MB
先ほどの出力(22.9+ MB)に比べ、実際のメモリ使用量は約78.2 MBと、大きく異なることが分かります。
このように、文字列データを含む場合は必ず「deep」オプションを使用する習慣をつけましょう。
df.memory_usage()による詳細な分析
全体像ではなく、各列がどれだけのメモリを消費しているかを詳しく調べたい場合には、df.memory_usage()メソッドが適しています。
このメソッドは各カラムのメモリ使用量をバイト単位で返し、PandasのSeries形式で結果を取得できます。
カラムごとの消費量を特定する
特定の列がボトルネックになっていないかを確認する際に非常に便利です。
# 各カラムのメモリ使用量(バイト)を取得
mem = df.memory_usage(deep=True)
print(mem)
Index 128
id 8000000
value 8000000
category 66000000
dtype: int64
この結果から、category列が圧倒的に多くのメモリを消費していることが一目で分かります。
合計値を算出したい場合は、この結果に対して.sum()を適用するだけです。
# 合計メモリ使用量をMB単位で表示
total_mb = df.memory_usage(deep=True).sum() / (1024 ** 2)
print(f"Total Memory: {total_mb:.2f} MB")
インデックスのメモリ使用量
memory_usage()はデフォルトでインデックスのメモリ使用量も含めて計算します。
もしインデックスを除外してデータ本体のみを確認したい場合は、引数でindex=Falseを指定します。
ただし、大規模なマルチインデックスを使用している場合は、インデックス自体が無視できないメモリを消費することもあるため注意してください。
オブジェクト型と「deep=True」の重要性
なぜdeep=Trueが必要なのか、その理由をさらに深掘りしてみましょう。
Pandasのデータフレームにおいて、整数(int)や浮動小数点数(float)は固定長のメモリを占有します。
例えば、int64型は1要素あたり常に8バイトを消費するため、行数から容易にメモリ量を計算可能です。
一方で、文字列(object型)は可変長データであり、データフレームのセル内には文字列の実体への参照(ポインタ)のみが格納されています。
deep=False(デフォルト)の状態では、この「参照情報」のサイズのみがカウントされます。
これに対し、deep=Trueを指定すると、参照先のオブジェクトの実体まで再帰的に探索してサイズを計測します。
実務においては、この違いを理解していないと「メモリには余裕があるはずなのにプログラムが落ちる」という不可解な現象に悩まされることになります。
メモリ使用量を削減するための具体的なテクニック
メモリ使用量を確認した後は、それを最適化するフェーズに移ります。
ここでは、Pandasで即座に実践できる効果的な削減手法をいくつか紹介します。
1. データ型のダウンキャスト
Pandasはデフォルトでint64やfloat64を選択しますが、多くのデータはこれほどの精度や範囲を必要としません。
例えば、0から100までの値しか取らない列にint64(8バイト)を使うのは無駄であり、int8(1バイト)で十分です。
# 数値型のダウンキャスト
df['id'] = pd.to_numeric(df['id'], downcast='integer')
df['value'] = pd.to_numeric(df['value'], downcast='float')
print(df.memory_usage(deep=True))
これだけで、数値列のメモリ使用量を半分以下に削減できる場合があります。
2. カテゴリ型の活用
文字列データの種類(ユニーク数)が少ない場合は、category型に変換することが極めて有効です。
category型は内部で各文字列に整数値を割り当てて管理するため、重複の多い文字列データを効率的に圧縮できます。
# object型からcategory型への変換
df['category'] = df['category'].astype('category')
print(df.memory_usage(deep=True))
先ほどのサンプルデータでは、category列が66MBから約1MB程度まで劇的に削減されるはずです。
ただし、全ての値がユニークに近いようなデータ(ユーザーIDなど)に適用すると、逆にメモリ消費が増える可能性があるため注意してください。
3. 不要な列の削除と選択的読み込み
分析に使用しない列を保持し続けることは、メモリの浪費でしかありません。
drop()メソッドを使用して早めに不要な列を除去するか、データを読み込む時点で必要な列のみを指定しましょう。
# 読み込み時に列を絞り込む
use_cols = ['id', 'value']
df_limited = pd.read_csv('large_data.csv', usecols=use_cols)
大規模データを扱う際の読み込み時の工夫
メモリ不足でそもそもread_csvが成功しない場合は、一括読み込みを諦める必要があります。
そのような状況では、chunksize引数を利用したチャンク処理が有効です。
# 10万行ずつ読み込んで処理する
chunk_size = 100000
for chunk in pd.read_csv('huge_data.csv', chunksize=chunk_size):
# 各チャンクに対して集計処理などを行う
process(chunk)
この方法であれば、メモリ使用量を一定に保ちながら数ギガバイト規模のファイルを処理することが可能です。
また、最新のPandasや関連ライブラリ(PyArrowなど)をバックエンドに使用することで、読み込み速度とメモリ効率を同時に向上させることも検討してください。
まとめ
Pandasでのメモリ管理は、効率的なデータ分析を行うための必須スキルです。
まずはdf.info(memory_usage='deep')で全体の状況を把握し、df.memory_usage(deep=True)で細かな原因を特定しましょう。
その上で、データ型の最適化やcategory型への変換を適切に行うことで、メモリ消費量を劇的に抑えることができます。
リソースを賢く使うことは、単なる節約ではなく、より高度で高速な分析を可能にするための第一歩です。
日々のコーディングにおいて、データの型とサイズを常に意識する癖をつけておきましょう。
