Pandasで列データの前処理を行う小技集
PandasでNaNの列を処理する では NaN
のデータとなってしまう列データの処理に関して説明しました。
今回は、列のデータを前処理するために使う他の小技をまとめたいと思います。
列を0埋めする(zfill)
実はIDは5桁の数字なんだよ! といった 固定長の数値文字列 を扱う場面の話をします。
例えば、以下のようなデータがあるとします。
1import pandas as pd
2
3df = pd.read_csv('./sample.csv')
4df.head()
ID | 名前 | 年齢 | 性別 | 趣味 | |
---|---|---|---|---|---|
0 | 1 | 小林 | 20 | 男 | 野球観戦 |
1 | 2 | 田中 | 35 | 女 | 飲み会 |
2 | 3 | 佐藤 | 29 | 男 | NaN |
3 | 4 | 鈴木 | 44 | 女 | 編み物 |
元のCSVファイル中のID列が 00001
、 00002
のように数値文字列形式でデータを格納しているのであれば、
read_csv
関数実行時に、列のデータ型を dtype
オプションで指定してあげることで安全に取り出すことができます。
しかし、そもそもデータ的に欠落している場合にはどうしようもないので、自前で0埋め処理をする必要があります。
これには zfill
関数を使います。zfill
を行う前に astype
関数などで文字列型に変換した上で実施しましょう。
1# 0埋めで5桁の数字文字列に変更
2df['ID'].astype('str').str.zfill(5)
3
4> 0 00001
5> 1 00002
6> 2 00003
7> 3 00004
カテゴリ変数をワンホットエンコーディングする(get_dummies)
次にデータがカテゴリ変数で表現されている場合です。 カテゴリ変数とは、カテゴリを数値で表しているデータ のことを意味します。
例えば、以下のデータでは 性別
の列をカテゴリ変数として表しています。
ID | 名前 | 年齢 | 性別 | 趣味 | |
---|---|---|---|---|---|
0 | 1 | 小林 | 20 | 1 | 野球観戦 |
1 | 2 | 田中 | 35 | 2 | 飲み会 |
2 | 3 | 佐藤 | 29 | 1 | NaN |
3 | 4 | 鈴木 | 44 | 2 | 編み物 |
人間は「性別
の列は1が男性で2が女性かな(もしくはその逆)」と暗黙的に推測してしまいますが、機械はそうはいきません。
1と2が「カテゴリ」を表現する数字であることを知るよしがないのです。
そのため、カテゴリを表現するデータをそれぞれ別の列に分解する手法があります。 ワンホットエンコーディングと呼ばれています。
Pandas では get_dummies
関数を使って実現します。
1import pandas as pd
2
3pd.get_dummies(df['性別'], prefix='性別')
性別_1 | 性別_2 | |
---|---|---|
0 | 1 | 0 |
1 | 0 | 1 |
2 | 1 | 0 |
3 | 0 | 1 |
これで、性別の値が1かどうか、性別の値が2かどうか、の2つの列に分割することができました。
2進数の文字列を複数の列に分解する(from_records)
最後に 1
と 0
の2進数の文字列でデータを表現している場合です。
少しイメージが湧きにくいですが、例えば以下のように、1つの質問の中で、複数回答が可能なアンケートのデータを1列で表現している 場合のデータなどがそうでしょう。
1import pandas as pd
2
3df = pd.read_csv('./sample2.csv', dtype={'ID': 'int', '好きなスポーツ': 'str'})
4df.head()
ID | 好きなスポーツ | |
---|---|---|
0 | 1 | 10010 |
1 | 2 | 00111 |
2 | 3 | 10101 |
3 | 4 | 11111 |
選択した回答項目とビットの位置が連動しています。
ID=1
のユーザが 好きなスポーツ
の質問を以下のように回答したイメージです。
野球 サッカー 水泳 相撲 ラグビー
ただし、ID=1
のユーザも ID=3
のユーザも野球が好きにも関わらず、数字的に等しくない (10010 != 10101) ありません。
このようなバイナリ形式の文字列は特徴量として扱いにくいのです。
どうするかというと、DataFrame.from_records
関数を使って 1つ1つのビットを別の列として分解してあげれば 良いでしょう。
1import pandas as pd
2
3# 「好きなスポーツ」列を分割します
4sport = pd.DataFrame.from_records(df['好きなスポーツ'], columns=['野球', 'サッカー', '水泳', '相撲', 'ラグビー'])
5sport.head()
野球 | サッカー | 水泳 | 相撲 | ラグビー | |
---|---|---|---|---|---|
0 | 1 | 0 | 0 | 1 | 0 |
1 | 0 | 0 | 1 | 1 | 1 |
2 | 1 | 0 | 1 | 0 | 1 |
3 | 1 | 1 | 1 | 1 | 1 |
野球が好きかどうか、サッカーが好きかどうか、の列に分割することができました。
まとめ
列のデータがどのような形式か、意味かによって、適切に加工してあげるかは大切ですね。 他にも何かテクニックがあればまとめていきたいと思います。