アンケート分析でたまにpython&pandasを使用しています。
分析の前処理でカテゴリ変数を変換したり、いらない列を削除したりする必要があるのですが、全てのDataFrameに同じ処理をするわけではないので、抽出して処理をして、また戻す、といったことを頻繁にやっています。
列を抽出(指定)する方法としてindexや列名指定などの方法がありますが、それぞれ
- 数値(index)指定:間違いやすいし、操作すると位置が変わってしまう
- 列名指定:列名を正しく全て列挙するのが大変(日本語アンケートの列名は長くなりがち・・)
という問題があり、前方一致や後方一致で一括処理できると便利なのになーと思っていました。
検索ですぐに良いやり方が見つからなかったので、試行錯誤してみました。
もっと良いやり方をご存知の方はコメントしてもらえるとありがたいです。
操作するDataFrame
サンプルとして、以下のようなDataFrameを操作していきます。
import pandas as pd
df = pd.DataFrame(
data={
'ID':[0, 1],
'属性_A':[0, 1],
'属性_B':[1, 1],
'回答_A':[2, 2],
'回答_B':[0, 2],
'回答_C':[2, 3],
'その他':[0, 0]}
)
DataFrameを表で表すとこんな感じです。
ID | 属性_A | 属性_B | 回答_A | 回答_B | 回答_C | その他 | |
---|---|---|---|---|---|---|---|
0 | 0 | 0 | 1 | 2 | 0 | 2 | 0 |
1 | 1 | 1 | 1 | 2 | 2 | 3 | 0 |
前方一致で列名を返す
まず、前方一致で列名を取得してみたいと思います。
ID、属性という言葉から始まる列の名前を取得するコードは以下のようになります。
words_start = ('ID', '属性') #用語はタプル
cols_bool = df.columns.str.startswith(words_start) #ndarrayでTRUE/FALSEのBoolean配列
df.columns[cols_bool]
カラム名のIndexが返ってきます。タプルで指定した、IDと属性を含む列を取得できました。
Index(['ID', '属性_A', '属性_B'], dtype='object')
これはcolumns=
のようなパラメータに代入可能です。
前方一致の列を含むDataFrameを作成
words_start = ('ID', '属性') #用語はタプル
cols_bool = df.columns.str.startswith(words_start)
df_ext = df[df.columns[cols_bool]]
先ほどのIndexを使ってDataFrameを取得しました。
ID | 属性_A | 属性_B | |
---|---|---|---|
0 | 0 | 0 | 1 |
1 | 1 | 1 | 1 |
前方一致の列をDataFrameから削除
2つのやり方があります。削除コマンドのdropを用いる場合と、それ以外を抽出する場合です。
dropを用いる場合
words_start = ('ID', '属性') #用語はタプル
cols_bool = df.columns.str.startswith(words_start)
df_drop = df.drop(columns=df.columns[cols_bool])
notを用いる場合(それ以外を抽出)
words_start = ('ID', '属性') #用語はタプル
cols_bool = df.columns.str.startswith(words_start)
df_drop = df[df.columns[~cols_bool]]
cols_bool
はブーリアン配列であり、~
を使うとnotとなります。
これを用いて、削除(というか該当しない列を抽出)しました
どちらも結果は以下のようになります
回答_A | 回答_B | 回答_C | その他 | |
---|---|---|---|---|
0 | 2 | 0 | 2 | 0 |
1 | 2 | 2 | 3 | 0 |
分割する場合
抽出と削除ができたので、組み合わせれば分割ができます
まとめて返す関数を作ってみました
def df_split_startwith(df, words):
cols_bool = df.columns.str.startswith(words)
return df[df.columns[cols_bool]], df[df.columns[~cols_bool]]
以下のように使えます
words_start = ('ID', '属性') #用語はタプル
df_1, df2 = df_split_startwith(df, words_start)
後方一致の場合
endswith()
を使うだけです。
words_end = ('A', 'C')
cols_bool = df.columns.str.endswith(words_end)
df_ext2 = df[df.columns[cols_bool]]
属性_A | 回答_A | 回答_C | |
---|---|---|---|
0 | 0 | 2 | 2 |
1 | 1 | 2 | 3 |