TL;DR
Python pandas の DataFrame を使っていると、いつもどうでもいい感じな初歩的なところではまります。
(わたしだけ...?)
このあたりの Tips がまとまっている素晴らしいサイトも多いのですが、なぜか、うまーい具合にわたしがやりたいことにピッタリはまらないことが多いので半分自分用にまとめておきました。
蛇足的な考察ですが、pandas DataFrame は、データ指向のデータ屋さんが使いやすいように作られているからかな、と思います。 わたしみたいなオブジェクト指向(≒機能指向)よりなプログラマだと、そもそもの発想がロジックよりになるためそれが原因で使いづらいことが多い気がします。
ということで、どちらかというと、わたしみたいなプログラマよりのTipsになります。
データ屋さんとプログラマの考え方の違い 例
データ屋さんは、SQL の inner/outer join とかで頑張って表を結合します。
プログラマは、表を2つ読み込んで for文とif文でぐるぐる回すロジックで解決したくなります...
静的に考えるか、動的に考えるかの差がけっこうあります。
さっそくTips
DataFrameを作ってみる
import pandas as pd
a_df = pd.DataFrame()
print(a_df)
↓↓↓ 結果
Empty DataFrame
Columns: []
Index: []
空のDataFrameが出来ました!
まずはこれが基本。
Pythonでデータ分析していると、
DataFrame
とかnparray
とかSeries
とか色々と型を行き来することが多くなります。 なので、ハンガリアン記法的に{わかりやすい名前}_df
とか書いておいて、この変数がDataFrameであることを明示しておくと何かと楽です。
初期値のはいっているDataFrameを作ってみる
init_df = pd.DataFrame( [[10,20],[30,40]], columns=['A','B'] )
print(init_df)
↓↓↓ 結果
A B
0 10 20
1 30 40
できました。 が、実際に何かしようと思ったときにデータをベタ書き(ハードコーディング)することはあまりないので... この書き方は実務ではあまり使わないかもしれないですね。 read_csv
というもので簡単に csv を読み込めるのですでに出来上がったデータを分析したいときはこちらを使いましょう。
型(カラム)だけ決まっているDataFarmeに値(行)を追加していく
これです! とにかくわたしが頻繁にやりたいことがこれです。
例えば、外部サービスのAPIを呼び出して取得した json を元に DataFrame を作りたい、とかいう場合です。
json のデータに対してfor文でぐるぐるまわしながら1行ずつ追加したいですよね。
そういう場合はこんな風にします。
list_df = pd.DataFrame( columns=['A','B'] )
for i in [0,1,2,3,4,5]:
tmp_se = pd.Series( [ i, i*i ], index=list_df.columns )
list_df = list_df.append( tmp_se, ignore_index=True )
print( list_df )
↓↓↓ 結果
A B
0 0 0
1 1 1
2 2 4
3 3 9
4 4 16
5 5 25
ちょっと直観的じゃない部分もありますが、これでできます。
型(カラム)が決まっているタイプのデータでしたらこのパターンでだいたい実装可能です。
上では、行名(index)は、何も指定していませんが、もし何か指定しければ以下のようにしてください。
list_df = pd.DataFrame( columns=['A','B'] )
for i in [0,1,2,3,4,5]:
tmp_se = pd.Series( [ i, i*i ], index=list_df.columns, name='No.' + str(i) )
list_df = list_df.append( tmp_se )
print( list_df )
↓↓↓ 結果
A B
No.0 0 0
No.1 1 1
No.2 2 4
No.3 3 9
No.4 4 16
No.5 5 25
Seriesを作る時に name
を指定しているのがポイントになります。
コードの補足(読み飛ばしOK)
上のコードで動くと思うので大丈夫ですがすこしだけ補足しておきます。
まず、カラムが A B の空のDataFrameを作っています。
list_df = pd.DataFrame( columns=['A','B'] )
次に、DataFrameに入れたいデータを使って、Series
という1次元配列みたいなものを一回作ります。
tmp_se = pd.Series( [ i, i*i ], index=list_df.columns )
ここが少しだけトリッキーで、本来は、行(横方向)を追加したいのに、列(縦方向)のデータを作ってるようにみえます。本当はこういうデータのイメージなんですが、
A | B | |
---|---|---|
- | 1 | 2 |
一回こういうデータを作る感じです。
- | |
---|---|
A | 1 |
B | 2 |
なのですが、実はSeries
は1次元の配列(ベクトル)なので縦とか横とか言う概念がないので、縦でも横でも同じことをさしているのだそうです。
追加するデータが出来たところでもとのDataFrameにappendします。
list_df = list_df.append( tmp_se, ignore_index=True )
ここも要注意ポイントで、.append
は戻り値で新しいインスタンスを返します。 なので、代入しなおしてください。
このあたりがデータ屋さん的というか、Immutableな変数を使おうとする関数型的な思想が見えてドキドキします。
カラム(型)が決まってない可変のデータの場合
たまにありますよね。こういうことも。そういう場合のやりざまです。
最初の json から json_data を作っている部分はサンプルで、本当はAPIとかからとってきてるイメージでいてください。
import json
###### ここからダミーデータ作成
json_str = '''
{
"values" : [
{ "col1" : 1, "col2" : 2, "col3" : 3 },
{ "col1" : 4, "col2" : 5, "col3" : 6 },
{ "col1" : 7, "col2" : 8, "col3" : 9 }
]
}
'''
json_data = json.loads(json_str)
###### ここまでダミーデータ作成
var_df = pd.DataFrame()
for value in json_data['values']:
keys = []
vals = []
for k, v in value.items():
keys.append( k )
vals.append( v )
tmp_se = pd.Series( vals, index=keys )
var_df = var_df.append( tmp_se, ignore_index=True )
print( var_df )
↓↓↓ 結果
col1 col2 col3
0 1.0 2.0 3.0
1 4.0 5.0 6.0
2 7.0 8.0 9.0
コードは単純ですね。
結局のところ Series に一回いれてから、DataFrameにappendする、をやるだけです。
さいごに
もしこのコードサンプルで少しでもみなさまのお役に立つことがあれば。
いいね でも押していってくださいませ m__m
他にも欲しいパターンがあったらコメントなりTwitterからのDMなりください!