Kaggleで実用|Pandasの機械学習用の使い方メモ

Pocket

機械学習のためのPandas利用

機械学習のための言語はPython,Pandas,Numpy,Scikit-learn等を使うことが多いです。
データの前処理のためには、特にPandasを使うことが多いので、よく使うものやこれはいいなと思うものを自分用のメモとしてここに残すことにします。




使い方集

具体的なデータがあったほうがいいので、3つのDataFrameを使って覚えた使い方を羅列していきます。
DataFrameは学校の生徒6人分のいろんなデータを扱うことにして、

  • df:ID、氏名、クラス、身長
  • df1:ID、住んでる駅、生年月日
  • df2:ID、好きな色

といったデータをそれぞれのDataFrameに格納します。
コマンドは全てIPython上で実行しています。

データ作成~中身調べ

データは実際はcsvとかsqlの結果とかをDataFrameに変換するのが通常ですが簡易的なデータが欲しいので作成します。

import pandas as pd
df = pd.DataFrame({'id'    : [100, 101, 102, 103, 104, 105],
                   'name'  : ['tom', 'kei', 'jasmin', 'chris', 'ford', 'marie'],
                   'class' : ['A', 'A', 'A', 'B', 'B', 'C'],
                   'height': [170, 162, 157, 177, 180, 156]},
                   index=[0, 1, 2, 3, 4, 5])
  
df1 = pd.DataFrame({'id'      : [100, 101, 102, 103, 104, 105],
                    'station' : ['harborfront', 'orchard', 'marina bay', 'orchard', 'bugis', 'bugis'],
                    'birthday': ['1992-05-01 12:10:05', '1992-04-04 20:50:39', '1991-01-07 07:28:00', '1992-10-21 08:17:59', '1992-09-27 03:50:25', '1992-06-04 02:23:41']},
                     index=[0, 1, 2, 3, 4, 5])
                     
df2 = pd.DataFrame({'id'             : [100, 100, 101, 101, 102, 102, 103, 104, 105, 105, 105],
                    'color' : ['red', 'black', 'pink', 'orange', 'green', 'red', 'blue', 'white', 'gray', 'yellow', 'red']},
                     index=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])

データをパッと見たい時は.head()
最初の5レコード分を表示します。

In [2]: df.head()
Out[2]: 
  class  height   id    name
0     A     170  100     tom
1     A     162  101     kei
2     A     157  102  jasmin
3     B     177  103   chris
4     B     180  104    ford

指定した列にどんな内容のデータがそれぞれいくつあるのかを調べるとき。

In [3]: df['class'].value_counts()
Out[3]: 
A    3
B    2
C    1
Name: class, dtype: int64

DataFrameの各データの型なんかを知りたいときは.info()

In [4]: df.info()

Int64Index: 6 entries, 0 to 5
Data columns (total 4 columns):
class     6 non-null object
height    6 non-null int64
id        6 non-null int64
name      6 non-null object
dtypes: int64(2), object(2)
memory usage: 240.0+ bytes

複数DataFrameのマージ

複数DataFrameを特定の列の値でもってマージする場合は.merge()でできます。
複数のDataFrameでキーを共有している場合に使えます。
第一、第二引数に結合するDataFrameを指定、howはインナージョインか、アウタージョインか、レフトアウタージョインか、ライトアウタージョインか。(この例だとどれを指定しても変わらないです。キーは両方のDataFrameで同じものを1つずつもっているから)
onにマージするためのキーを指定。

In [5]: df = pd.merge(df, df1, on='id')

In [6]: df
Out[6]: 
  class  height   id    name             birthday      station
0     A     170  100     tom  1992-05-01 12:10:05  harborfront
1     A     162  101     kei  1992-04-04 20:50:39      orchard
2     A     157  102  jasmin  1991-01-07 07:28:00   marina bay
3     B     177  103   chris  1992-10-21 08:17:59      orchard
4     B     180  104    ford  1992-09-27 03:50:25        bugis
5     C     156  105   marie  1992-06-04 02:23:41        bugis

行列の削除

行単位、列単位での削除は.drop()です。
axis=1を指定すると列単位での削除になります。

In [10]: df.drop(['station'], axis=1)
Out[10]: 
  class  height   id    name             birthday
0     A     170  100     tom  1992-05-01 12:10:05
1     A     162  101     kei  1992-04-04 20:50:39
2     A     157  102  jasmin  1991-01-07 07:28:00
3     B     177  103   chris  1992-10-21 08:17:59
4     B     180  104    ford  1992-09-27 03:50:25
5     C     156  105   marie  1992-06-04 02:23:41

重複の操作

重複する値が複数レコードにまたがってあり、その中の一行だけ残す時は.drop_duplicates
keep=hogehogeでどの行を残すかを指定できます。
クラスの代表をIDの数字の若い順で決めるとして、各クラスの代表一覧を欲しかったら下記のように行います。

In [11]: df.drop_duplicates(['class'],keep='first')
Out[11]: 
  class  height   id   name      station
0     A     170  100    tom  harborfront
3     B     177  103  chris      orchard
5     C     156  105  marie        bugis

重複する複数レコードをぎゅっとまとめて、その上で何かの値を得たいときは.froupby()
所属しているクラスの人数をカウントしてみます。
A、B、Cクラスそれぞれ3レコード、2レコード、1レコードなのでその値を得ます。

In [19]: df.groupby(['class'])['id'].transform('count')
Out[19]: 
0    3
1    3
2    3
3    2
4    2
5    1
dtype: int64

.transform()で指定した列の値に対して何かを行いますが(上の例だとID)
クラス毎の身長の最大値を求めたりもできます(最小値とか平均値とかもmin、mean等で取得できます。)

In [20]: df.groupby(['class'])['height'].transform('max')
Out[20]: 
0    170
1    170
2    170
3    180
4    180
5    156
dtype: int64

この後.drop_duplicatesを行えば、1クラス1レコードのDataFrameを得ることができるので、クラスごとの平均身長のみを取り出す、といったことができます。

時間の操作

時間の操作はまず.to_datetime()で型を変換します。

In [13]: time = pd.to_datetime(df1['birthday'])

In [14]: time.map(lambda x: x.strftime('%d-%m-%Y'))
Out[14]: 
0    01-05-1992
1    04-04-1992
2    07-01-1991
3    21-10-1992
4    27-09-1992
5    04-06-1992
Name: birthday, dtype: object

時間の一部を切り取るときは式を定義して下記のように行います。

In [15]: time.map(lambda x: x.strftime('%H'))
Out[15]: 
0    12
1    20
2    07
3    08
4    03
5    02
Name: birthday, dtype: object

同じキーが重複する複数レコードを他のDataFrameに渡す

df2で定義した生徒毎の好きな色(複数個あるのでレコードも複数行)
をdfに渡してあげるときには、一旦df2で.groupby()しつつ情報をぎゅっとまとめて、dfにマージした後にまとまった情報を再度広げます。

idをキーにまとめつつ、生徒毎の複数ある好きな色をまとめて一つのカラムに格納します。

In [11]: df2 = df2.groupby('id')['color'].apply(lambda x: " ".join(set("color:" + str(s) for s in x )))

In [12]: df2
Out[12]: 
id
100                color:black color:red
101              color:orange color:pink
102                color:green color:red
103                           color:blue
104                          color:white
105    color:red color:yellow color:gray
Name: color, dtype: object

dfに新しい列を追加。.groupby()した後のデータ型はDataFrameではなくSeriesになっているので、ここでは.merge()ではなく.map()を使います。

In [18]: df['color'] = df['id'].map(df2)

In [19]: df
Out[19]: 
  class  height   id    name             birthday      station  \
0     A     170  100     tom  1992-05-01 12:10:05  harborfront   
1     A     162  101     kei  1992-04-04 20:50:39      orchard   
2     A     157  102  jasmin  1991-01-07 07:28:00   marina bay   
3     B     177  103   chris  1992-10-21 08:17:59      orchard   
4     B     180  104    ford  1992-09-27 03:50:25        bugis   
5     C     156  105   marie  1992-06-04 02:23:41        bugis   

                               color  
0              color:black color:red  
1            color:orange color:pink  
2              color:green color:red  
3                         color:blue  
4                        color:white  
5  color:red color:yellow color:gray  

そして追加したcolorという列を、半角スペースで区切って複数のレコードに分けます。
例えばクラスで生徒に”好きな色のアンケート(複数個回答可能)”をとって、それをクラスごとに集計した、と考えると下記のような方法になります。

In [22]: df_color = pd.concat([pd.Series(row['class'], row['color'].split(' '))for _, row in df.iterrows()]).reset_index()

In [23]: df_color.columns = ['color', 'class']

In [24]: df_color
Out[24]: 
           color class
0    color:black     A
1      color:red     A
2   color:orange     A
3     color:pink     A
4    color:green     A
5      color:red     A
6     color:blue     B
7    color:white     B
8      color:red     C
9   color:yellow     C
10    color:gray     C


 

Pocket

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です