目次

DataFrame読込時のメモリを節約 - pandas

Pythonの統計ライブラリpandasでは、データフレームを読み込む際、一度にメモリ上に展開するので、巨大なデータ&非力なPCではメモリが圧迫される。

また、ある程度は型推論してくれるが、多少メモリ効率の悪い部分がある。

もし読み込みたいカラムが限定されていたり、データ型が判明しているカラムがあれば、読み込み時に指定することで、メモリを削減できる。

read_csv()の引数

read_csv の引数の内、メモリ節約に効果のある以下の3つを紹介する。

usecols

読み込むカラムを指定し、不要なカラムを読み込まないようにする。引数として受け付けるデータは以下のいずれか。

sample.csv(整形)
name      , age , sex, weight, height
ドラえもん, -100, M  , 129.3 , 129.3
野比のび太, 10  , M  , 33.2  , 140.0
源静香    , 10  , F  ,       , 136.9

usecols = ['name', 'age', 'weight']
df = pd.read_csv('sample.csv', usecols=usecols)

print(df)
# => 指定したカラムのみからなるDataFrameができる
# name,        age,   weight
# ドラえもん,  -100,  129.3
# 野比のび太,  10,    140.0
# 源静香,      10,    nan

※数値は適当

dtypes

データ型を適切に指定する。受け付けるデータは以下のいずれか。

pandasでは、カラムがint型やfloat型と判定された場合、64bit環境ならnp.int64、np.float64が基本的には使われる。 取り得る最大値が大きくないなら、int8、int16、int32などを使うことで、メモリ量を削減できる。

文字列は、np.object型として読み込む。np.objectはpythonオブジェクトへのポインタを格納する、何でもアリな型。
メモリの節約からは話は逸れるが、「数値に見えるけど文字列として処理したい」カラムをはじめから文字列として読み込むのにも役立つ。

欠損値を含むint型

np.int型では整数しか表現できないため、int型を指定したカラムに欠損値が含まれる場合は読み込みエラーになる。

np.floatなら欠損値を表現できる。以下の選択肢を取ることになる。

# 2. カラムの欠損値を-1で埋め、int型にキャスト
df['aaa'] = df['aaa'].fillna(-1).astype(np.int32)

# 3. カラムの欠損値を除去し、int型にキャスト
df.dropna(subset=['aaa'], inplace=True)
df['aaa'] = df['aaa'].astype(np.int32)

chunksize

上記の節約をしても、とにかくレコード数が多すぎてままならないという場合は、chunksizeに整数値を指定すると、その数ずつ読み込んでくれる。

read_csv()の返値は、「chunksize個のレコードから成るDataFrameを逐次読み込むイテレータ」となる。

dfitr = pd.read_csv('sample.csv', chunksize=10000)

df = pd.DataFrame(columns=['A','B','C'])  # 処理結果を順次結合していくための空のDataFrame

for subdf in dfitr:
    # なんか処理
    
    # 必要なカラムのみ残してdfに結合 (A,B,Cカラムのみ残る)
    df = pd.concat([df, subdf], join='inner', ignore_index=True)

実装例

列挙型データのカウント

いくつかの決まった値しか取らないデータがそれぞれ何個存在するかを、chunksizeを用いながら集計する。
事前に取り得る値が全てわかっていなくても大丈夫。

counter = pd.Series(dtype=np.float64)

for df in pd.read_csv('sample.csv', chunksize=10000):
    counter = counter.add(df.groupby('enum')['id'].count(), fill_value=0)

counter = counter.astype(np.int64)

print(counter)
# ====
# enum
# cat      2
# dog      3
# rabbit   1
# Name: id, dtype: int64

pandasをさらに効率化するラッパツール

あるいは、以下のpandasのラッパを使うことで、巨大データに対する効率的な処理をやってくれるらしい(詳しくは調べていない)

また、後発の以下のようなツールもある。