遅くなりましてすみません。。。
前置き
前回に続いて、csvをいじくっていこうと思います。
前回では生Pythonのcsv処理と、csvモジュールを使ったcsvの処理を書いてきました。
どちらも楽になる部分、実装上考慮しなければならない部分がそれぞれあるので、その時々で都合のいいほうを採用するといい、という感じで締めたと思います。
今回は、Pandasというライブラリを使ったcsv読み込みを紹介します。
本当は書き込みに関してのメソッドもあるのですが、業務内でほぼ使う機会がなかったことと、それに伴ってよくわかってないのが正直なところなので省略させてください。
(使ってない=そこまで必須でもない、と無理にこじつけてみる)
ただ、読み込みに関しては大いに助けになったのでそちらに関しては書こうと思います。
##本編
まずはオプションとかつけないで普通に書いてみます。
import pandas as pd
# DataFrame型でcsvを読み込む
reader = pd.read_csv('../data/sample.csv')
print(reader)
"""
BLANK_ HEADER_1 HEADER_2 HEADER_3 HEADER_4 HEADER_5 HEADER_6 HEADER_7 \
0 INDEX_1 1_1 1_2 1_3 1_4 1_5 1_6 1_7
1 INDEX_2 2_1 2_2 2_3 2_4 2_5 2_6 2_7
2 INDEX_3 3_1 3_2 3_3 3_4 3_5 3_6 3_7
3 INDEX_4 4_1 4_2 4_3 4_4 4_5 4_6 4_7
4 INDEX_5 5_1 5_2 5_3 5_4 5_5 5_6 5_7
5 INDEX_6 6_1 6_2 6_3 6_4 6_5 6_6 6_7
6 INDEX_7 7_1 7_2 7_3 7_4 7_5 7_6 7_7
7 INDEX_8 8_1 8_2 8_3 8_4 8_5 8_6 8_7
8 INDEX_9 9_1 9_2 9_3 9_4 9_5 9_6 9_7
9 INDEX_10 10_1 10_2 10_3 10_4 10_5 10_6 10_7
HEADER_8 HEADER_9 HEADER_10
0 1_8 1_9 1_10
1 2_8 2_9 2_10
2 3_8 3_9 3_10
3 4_8 4_9 4_10
4 5_8 5_9 5_10
5 6_8 6_9 6_10
6 7_8 7_9 7_10
7 8_8 8_9 8_10
8 9_8 9_9 9_10
9 10_8 10_9 10_10
"""
このとき、readerはDataFrameという型です。
例に倣ってコメントに出力結果を書いてますが、一番左端の列に数字が出力されています。
これがpandasの仕様の一つで、自動的にインデックスの番号が付与されます。
もともとサンプルには便宜上のINDEX_が書いてありましたが、pandasはその辺優しいです。
for分などでイテレーションかける時も楽になります。
あと、横に列が多い場合、自動的に改行のような形式になって出力されているのがわかります。
次は、行数を指定して実行する場合です。
# chunksizeで行数を決定して自動的にイテレーションによる読み込みを実施する
reader = pd.read_csv('../data/sample.csv', chunksize=1)
for r in reader:
print(r)
"""
BLANK_ HEADER_1 HEADER_2 HEADER_3 HEADER_4 HEADER_5 HEADER_6 HEADER_7 \
0 INDEX_1 1_1 1_2 1_3 1_4 1_5 1_6 1_7
HEADER_8 HEADER_9 HEADER_10
0 1_8 1_9 1_10
BLANK_ HEADER_1 HEADER_2 HEADER_3 HEADER_4 HEADER_5 HEADER_6 HEADER_7 \
1 INDEX_2 2_1 2_2 2_3 2_4 2_5 2_6 2_7
HEADER_8 HEADER_9 HEADER_10
1 2_8 2_9 2_10
BLANK_ HEADER_1 HEADER_2 HEADER_3 HEADER_4 HEADER_5 HEADER_6 HEADER_7 \
2 INDEX_3 3_1 3_2 3_3 3_4 3_5 3_6 3_7
HEADER_8 HEADER_9 HEADER_10
2 3_8 3_9 3_10
BLANK_ HEADER_1 HEADER_2 HEADER_3 HEADER_4 HEADER_5 HEADER_6 HEADER_7 \
3 INDEX_4 4_1 4_2 4_3 4_4 4_5 4_6 4_7
HEADER_8 HEADER_9 HEADER_10
3 4_8 4_9 4_10
BLANK_ HEADER_1 HEADER_2 HEADER_3 HEADER_4 HEADER_5 HEADER_6 HEADER_7 \
4 INDEX_5 5_1 5_2 5_3 5_4 5_5 5_6 5_7
HEADER_8 HEADER_9 HEADER_10
4 5_8 5_9 5_10
BLANK_ HEADER_1 HEADER_2 HEADER_3 HEADER_4 HEADER_5 HEADER_6 HEADER_7 \
5 INDEX_6 6_1 6_2 6_3 6_4 6_5 6_6 6_7
HEADER_8 HEADER_9 HEADER_10
5 6_8 6_9 6_10
BLANK_ HEADER_1 HEADER_2 HEADER_3 HEADER_4 HEADER_5 HEADER_6 HEADER_7 \
6 INDEX_7 7_1 7_2 7_3 7_4 7_5 7_6 7_7
HEADER_8 HEADER_9 HEADER_10
6 7_8 7_9 7_10
BLANK_ HEADER_1 HEADER_2 HEADER_3 HEADER_4 HEADER_5 HEADER_6 HEADER_7 \
7 INDEX_8 8_1 8_2 8_3 8_4 8_5 8_6 8_7
HEADER_8 HEADER_9 HEADER_10
7 8_8 8_9 8_10
BLANK_ HEADER_1 HEADER_2 HEADER_3 HEADER_4 HEADER_5 HEADER_6 HEADER_7 \
8 INDEX_9 9_1 9_2 9_3 9_4 9_5 9_6 9_7
HEADER_8 HEADER_9 HEADER_10
8 9_8 9_9 9_10
BLANK_ HEADER_1 HEADER_2 HEADER_3 HEADER_4 HEADER_5 HEADER_6 HEADER_7 \
9 INDEX_10 10_1 10_2 10_3 10_4 10_5 10_6 10_7
HEADER_8 HEADER_9 HEADER_10
9 10_8 10_9 10_10
"""
csv全体の行数に対して、chunksizeを指定してやることで分割処理ができます。
行数が多いファイルなどはこれによりメモリエラーを回避することができます。
(もちろん、一回に指定できるchunksizeが大きいほど全体の時間は短縮できるので、メモリの上限と相談しつつ決めましょう。)
###列単位の処理
さらに、pandasならではの処理を紹介。
# 列単位で取得
reader = pd.read_csv('../data/sample.csv', chunksize=5)
for r in reader:
for index, row in r.iteritems():
print(index, row)
"""
BLANK_ 0 INDEX_1
1 INDEX_2
2 INDEX_3
3 INDEX_4
4 INDEX_5
Name: BLANK_, dtype: object
HEADER_1 0 1_1
1 2_1
2 3_1
3 4_1
4 5_1
Name: HEADER_1, dtype: object
HEADER_2 0 1_2
1 2_2
2 3_2
3 4_2
4 5_2
Name: HEADER_2, dtype: object
HEADER_3 0 1_3
1 2_3
2 3_3
3 4_3
4 5_3
Name: HEADER_3, dtype: object
HEADER_4 0 1_4
1 2_4
2 3_4
3 4_4
4 5_4
Name: HEADER_4, dtype: object
HEADER_5 0 1_5
1 2_5
2 3_5
3 4_5
4 5_5
Name: HEADER_5, dtype: object
HEADER_6 0 1_6
1 2_6
2 3_6
3 4_6
4 5_6
Name: HEADER_6, dtype: object
HEADER_7 0 1_7
1 2_7
2 3_7
3 4_7
4 5_7
Name: HEADER_7, dtype: object
HEADER_8 0 1_8
1 2_8
2 3_8
3 4_8
4 5_8
Name: HEADER_8, dtype: object
HEADER_9 0 1_9
1 2_9
2 3_9
3 4_9
4 5_9
Name: HEADER_9, dtype: object
HEADER_10 0 1_10
1 2_10
2 3_10
3 4_10
4 5_10
Name: HEADER_10, dtype: object
BLANK_ 5 INDEX_6
6 INDEX_7
7 INDEX_8
8 INDEX_9
9 INDEX_10
Name: BLANK_, dtype: object
HEADER_1 5 6_1
6 7_1
7 8_1
8 9_1
9 10_1
Name: HEADER_1, dtype: object
HEADER_2 5 6_2
6 7_2
7 8_2
8 9_2
9 10_2
Name: HEADER_2, dtype: object
HEADER_3 5 6_3
6 7_3
7 8_3
8 9_3
9 10_3
Name: HEADER_3, dtype: object
HEADER_4 5 6_4
6 7_4
7 8_4
8 9_4
9 10_4
Name: HEADER_4, dtype: object
HEADER_5 5 6_5
6 7_5
7 8_5
8 9_5
9 10_5
Name: HEADER_5, dtype: object
HEADER_6 5 6_6
6 7_6
7 8_6
8 9_6
9 10_6
Name: HEADER_6, dtype: object
HEADER_7 5 6_7
6 7_7
7 8_7
8 9_7
9 10_7
Name: HEADER_7, dtype: object
HEADER_8 5 6_8
6 7_8
7 8_8
8 9_8
9 10_8
Name: HEADER_8, dtype: object
HEADER_9 5 6_9
6 7_9
7 8_9
8 9_9
9 10_9
Name: HEADER_9, dtype: object
HEADER_10 5 6_10
6 7_10
7 8_10
8 9_10
9 10_10
Name: HEADER_10, dtype: object
"""
ヘッダーに指定されている列単位で読み込み、なんてこともできます。
データ処理などは、どのような範囲でどのような処理をかましたいかが様々にかんがえうるため、こういう方法も押さえておくと便利です。
行単位の処理
列単位があるなら行単位ももちろんあります。
# 行単位で取得
reader = pd.read_csv('../data/sample.csv', chunksize=1)
for r in reader:
# row_index部分は本来のインデックスの番号が入る(INDEX_とは別)
# row[0]に「INDEX_」、row[1]~には1_1 ~ 1_10と入っている(行数分イテレーションされる)
for row_index, row in r.iterrows():
for element in row[1:]: # row[0]以外でイテレーションすると各要素を取り出せる
print(element)
"""
1_1
1_2
1_3
1_4
1_5
1_6
1_7
1_8
1_9
1_10
2_1
2_2
2_3
2_4
2_5
2_6
2_7
2_8
2_9
2_10
3_1
3_2
3_3
3_4
3_5
3_6
3_7
3_8
3_9
3_10
4_1
4_2
4_3
4_4
4_5
4_6
4_7
4_8
4_9
4_10
5_1
5_2
5_3
5_4
5_5
5_6
5_7
5_8
5_9
5_10
6_1
6_2
6_3
6_4
6_5
6_6
6_7
6_8
6_9
6_10
7_1
7_2
7_3
7_4
7_5
7_6
7_7
7_8
7_9
7_10
8_1
8_2
8_3
8_4
8_5
8_6
8_7
8_8
8_9
8_10
9_1
9_2
9_3
9_4
9_5
9_6
9_7
9_8
9_9
9_10
10_1
10_2
10_3
10_4
10_5
10_6
10_7
10_8
10_9
10_10
"""
上記では行単位の処理に加え、
- pandas特有のインデックス番号
- サンプルに書いていたインデックス番号
- サンプルに書いていたヘッダー
それぞれを排除して出力できるようにしてあります。
pandasそのものの仕様と、データに最初から書いてあるインデックス・ヘッダー名はごちゃごちゃしやすいので、都度確認しながら実装する必要があります。
最初は思うようにデータ抽出をするのが難しいですが、慣れてしまえば相当使いやすいはずです。
まとめ Pandasのここがすごい
- 大容量ファイルの処理に最も効果を発揮する
- csvをcsvらしく考えることができる