はじめに
Pythonではpandas.DataFrameで二次元の表データを扱うことができます。 他言語の配列相当であるlist,tuple以上に表データを扱いやすいのですが、その処理速度も基本的にはlist,tuple以上に速いのです。 そんなDataFrameの強さと弱点を実際にプログラムを動かしながら見ていきましょう。実行環境・条件
実行環境 ・windows10 Home 64bit 条件 ・使用データ:10000行のCSVデータ ・使用データの列:index,学生ID,A-E 5教科の点数(0-10000) ※ある試験を受けた学生10000人の成績一覧をモデルとしていますDataFrameの強さ
DataFrameの強さは簡単な処理で、かつ高速でデータを処理できる点です。平均値を求める場合
後ろに列を追加して、平均値を代入する処理を実装します。 listだと下記の処理を組むことになります。for idx, row in enumerate(list):
row.extend('0')
row[7] = str((float(row[2]) + float(row[3]) + float(row[4]) + float(row[5]) + float(row[6]))/5.0)
他の言語と書き方が似ています。
これでもいいのですが…DataFrameで実装すると以下の1行で済みます。
# オリジナル
df['average'] = (df['subjectA'] + df['subjectB'] + df['subjectC'] + df['subjectD'] + df['subjectE'])/5
# 編集後
df['average'] = (df[['subjectA', 'subjectB', 'subjectC', 'subjectD', 'subjectE']].sum(axis=1))/5
※編集リクエスト者:siruku6さん
1行分操作のイメージで書けるためコーディングミスのリスクが少ないです。
ソートする場合
上記の平均値降順でソートを行う場合、listだと下記の処理を組むことになります。list = sorted(list, key=lambda x: x[7], reverse=True)
ソートに関しては、listでも1行で実装できますね。
これをDataFrameで実装するとこちらも1行で済みます。
df.sort_values('average', ascending=False)
条件で絞り込みをする場合
平均点が50点以上のデータのみを絞り込む場合、listだと下記の処理を組むことになります。list2 = []
for idx, row in enumerate(list):
if 50 <= float(row[7]):
list2.append(row)
平均算出時と同様に、forループを使います。
これをDataFrameで実装すると、…予想がつくと思いますが1行で済みます。
df2 = df[50 < df['average']]
各処理の速度は…
これら各処理の速度を計測し、10回平均を取ると以下の通りとなります。処理名 | 10回平均所要時間(list)[sec] | 10回平均所要時間(DataFrame)[sec] |
---|---|---|
平均計算 | 0.764768385887146 | 0.01179955005645752 コード変更後 : 0.007805347442626953 |
ソート | 0.030899477005004884 | 0.011399650573730468 |
絞り込み | 0.04529948234558105 | 0.006699275970458984 |
DataFrameによる実装はコードが簡潔なだけでなく、その速度が速いこともわかります。 |
DataFrameの弱点
DataFrameの弱点はforループです。 もし平均値をforループで作成する場合は下記のコードを使います。for idx in range(len(df)):
df.iat[idx, 6] = str((float(df.iat[idx, 1]) + float(df.iat[idx, 2])
+ float(df.iat[idx, 3]) + float(df.iat[idx, 4]) + float(df.iat[idx, 5])/5.0))
その所要時間は10回平均2.33[s]で、listの場合よりも遅いです。
従ってDataFrameを扱う際は、極力forを使わないことが望ましいです。