自分が主催をしている Pandas 勉強会で read_csv について学んだことの一部をここに記載します。結論を言ってしまうと、 csv を受け取る時は列の型を聞いておく必要があるよねという話です。最後に、勉強会で、 pd.read_csv の引数である keep_date_col についても勉強したのでそれも記載します。
本題に入る前に ー テキストを csv ファイル形式で扱う方法
本題に入る前にテキストを csv ファイル形式で扱う方法について記載します。これは Pandas ではなく標準 Python のモジュールの話です。csv ファイルの読み込みの練習をする時には、ソースコード上に直接記載されている csv を仮想的にファイルとして扱えるようにできると便利です。以下のように io モジュールを使用するとメモリ上のデータをあたかもファイル上のデータであるかのように扱うことができます。(ただし、全く同じではありませんので注意してください)
import pandas as pd import io t = '''col1,col2,col3,col4,col5,col6 2019,10/1,1,2,3,NA 2020,11/1,,6,7,A 2021,12/1,9,10,11,X''' f = io.StringIO(t) print(f.read())
col1,col2,col3,col4,col5,col6
2019,10/1,1,2,3,NA
2020,11/1,,6,7,A
2021,12/1,9,10,11,X
Pandas で csv ファイルを読みこむ方法
ここから本題ですが、Pandas で csv ファイルを読みこむ方法は以下になります。pd.read_csv 関数でファイルを読み込みます。 変数 f は io.StringIO で作成したファイルオブジェクトのようなものです。
f = io.StringIO(t)
df = pd.read_csv(f)
print(df)
col1 col2 col3 col4 col5 col6
0 2019 10/1 1.0 2 3 NaN
1 2020 11/1 NaN 6 7 A
2 2021 12/1 9.0 10 11 X
読み込んだ列の型(dtype)について
print 関数で df を 表示しました。ここで気になるのは、例えば 1列目が文字列なのか日付型なのか、はたまた整数型なのかということです。これを調べるために以下を実行します。 DataFrame の applymap メソッドを使用し全ての要素に type 関数を適用して型を調べています。
# 全ての要素の型を調べる df.applymap(lambda x: type(x))
col1 | col2 | col3 | col4 | col5 | col6 | |
---|---|---|---|---|---|---|
0 | <class 'int'> | <class 'str'> | <class 'float'> | <class 'int'> | <class 'int'> | <class 'float'> |
1 | <class 'int'> | <class 'str'> | <class 'float'> | <class 'int'> | <class 'int'> | <class 'str'> |
2 | <class 'int'> | <class 'str'> | <class 'float'> | <class 'int'> | <class 'int'> | <class 'str'> |
実行結果を見ると、 col1 の先頭行の要素は 2019 となっており整数型になっていることがわかります。 col3 の要素は整数かと思いきや 浮動少数点型になっています(未入力の要素がありそれが NaN (浮動小数点型)になるため、その列の他の要素もそれになっているのかもしれません)。このように、 pd.read_csv 関数をデフォルトの状態で使用してデータを読み込んだ場合、想定する型と違うことになっていることがあるかもしれないということに注意が必要です。これは、csv は型の情報を含まないデータフォーマットであるためです。csv をちゃんと処理したい場合は、列の型の情報は知っていなければならないということです。csv のデータを他の人から受け取る時には列の型について聞いておくようにします。これは Pandas や Python に関係のない話です。
keep_date_col について
ここからの話は、おまけです。
勉強会では教科書(Python for Data Analysis)に記載されている引数について一つづつ確認して行ったのですが、ここでは、他の人が記事あまりにしていないもの keep_date_col について紹介しようと思います(需要はあまりないと思いますが)。以下のように parse_dates 引数と一緒に使用します(parse_dates引数に2次元リストを渡していることに注目)。 parse_dates 引数に2次元リストを渡すことで、日付列の集合を併合できます。この時、併合前の列を消す(デフォルトの動作)か保持するかを keep_date_col 引数で決めることができます。
keep_date_col=False (デフォルト)の時
f = io.StringIO(t) df = pd.read_csv(f, parse_dates=[[0, 1]], keep_date_col=False) df
col1_col2 | col3 | col4 | col5 | col6 | |
---|---|---|---|---|---|
0 | 2019-10-01 | 1.0 | 2 | 3 | NaN |
1 | 2020-11-01 | NaN | 6 | 7 | A |
2 | 2021-12-01 | 9.0 | 10 | 11 | X |
まず、 keep_date_col=False (デフォルト)の場合 parse_dates 引数で指定した列番号が日付パーサーで一つの列として併合されます。 parse_dates 引数で指定する列は複数列を指定する時は2次元配列として指定することに注意してください。
keep_date_col=True の時
f = io.StringIO(t) df = pd.read_csv(f, parse_dates=[[0, 1]], keep_date_col=True) df
col1_col2 | col1 | col2 | col3 | col4 | col5 | col6 | |
---|---|---|---|---|---|---|---|
0 | 2019-10-01 | 2019 | 10/1 | 1.0 | 2 | 3 | NaN |
1 | 2020-11-01 | 2020 | 11/1 | NaN | 6 | 7 | A |
2 | 2021-12-01 | 2021 | 12/1 | 9.0 | 10 | 11 | X |
keep_date_col=True の時は併合前の日付列が保持されていることがわかります。
date_parser で複数の列の集合を併合する
parse_dates 引数で指定する列は複数列を指定する時は2次元配列を指定するのでした。これは以下のように複数の列の集合を併合できるようしているからです。
まずテーブルを定義して、普通に読み込んだものを表示します。
t = '''col1,col2,col3,col4,col5,col6,col7,col8,col9,col10,col11,co12 2019,10/1,1.0,2,3,,2019,1/1,1.0,2,3, 2020,11/1,,6,7,A,2020,2/1,,6,7,A 2021,12/1,9.0,10,11,X,2021,3/1,9.0,10,11,X ''' f = io.StringIO(t) df = pd.read_csv(f) df
col1 | col2 | col3 | col4 | col5 | col6 | col7 | col8 | col9 | col10 | col11 | co12 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2019 | 10/1 | 1.0 | 2 | 3 | NaN | 2019 | 1/1 | 1.0 | 2 | 3 | NaN |
1 | 2020 | 11/1 | NaN | 6 | 7 | A | 2020 | 2/1 | NaN | 6 | 7 | A |
2 | 2021 | 12/1 | 9.0 | 10 | 11 | X | 2021 | 3/1 | 9.0 | 10 | 11 | X |
次に、 parse_dates で複数の列の集合を指定してみます。
f = io.StringIO(t) df = pd.read_csv(f, parse_dates=[[0, 1], [6, 7]], keep_date_col=False) df
col1_col2 | col7_col8 | col3 | col4 | col5 | col6 | col9 | col10 | col11 | co12 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 2019-10-01 | 2019-01-01 | 1.0 | 2 | 3 | NaN | 1.0 | 2 | 3 | NaN |
1 | 2020-11-01 | 2020-02-01 | NaN | 6 | 7 | A | NaN | 6 | 7 | A |
2 | 2021-12-01 | 2021-03-01 | 9.0 | 10 | 11 | X | 9.0 | 10 | 11 | X |
parse_dates 引数で指定した列の集合それぞれに対して併合が行われていることがわかります。
以上です。おやすみなさい。