次の問題を処理するPythonの方法を探しています。
pandas.get_dummies()
メソッドは、データフレームのカテゴリ列からダミーを作成するのに最適です。たとえば、列の_['A', 'B']
_に値がある場合、get_dummies()
は2つのダミー変数を作成し、それに応じて0または1を割り当てます。
今、私はこの状況に対処する必要があります。単一の列(「ラベル」と呼びます)には、_['A', 'B', 'C', 'D', 'A*C', 'C*D']
_のような値があります。 get_dummies()
は6つのダミーを作成しますが、1つに複数の1を含めることができるように、そのうち4つだけが必要です。
これをPythonの方法で処理する方法はありますか?私はそれを取得するためのいくつかの段階的なアルゴリズムしか考えられませんでしたが、それはget_dummies()を含みません。ありがとう
編集済み、より明確であることを願っています!
この質問が聞かれてからしばらく経ちましたが、(少なくともnowがある)によってサポートされているワンライナーがあります- ドキュメント :
In [4]: df
Out[4]:
label
0 (a, c, e)
1 (a, d)
2 (b,)
3 (d, e)
In [5]: df['label'].str.join(sep='*').str.get_dummies(sep='*')
Out[5]:
a b c d e
0 1 0 1 0 1
1 1 0 0 1 0
2 0 1 0 0 0
3 0 0 0 1 1
私はややクリーンなソリューションを持っています。次のデータフレームを変換したいとします
pageid category
0 0 a
1 0 b
2 1 a
3 1 c
に
a b c
pageid
0 1 1 0
1 1 0 1
それを行う1つの方法は、scikit-learnのDictVectorizerを使用することです。しかし、他の方法について学ぶことに興味があります。
df = pd.DataFrame(dict(pageid=[0, 0, 1, 1], category=['a', 'b', 'a', 'c']))
grouped = df.groupby('pageid').category.apply(lambda lst: Tuple((k, 1) for k in lst))
category_dicts = [dict(tuples) for tuples in grouped]
v = sklearn.feature_extraction.DictVectorizer(sparse=False)
X = v.fit_transform(category_dicts)
pd.DataFrame(X, columns=v.get_feature_names(), index=grouped.index)
生データを使用してダミーデータフレームを生成し、特定のアトムを含む列を分離し、結果の一致をatom列に格納し直すことができます。
df
Out[28]:
label
0 A
1 B
2 C
3 D
4 A*C
5 C*D
dummies = pd.get_dummies(df['label'])
atom_col = [c for c in dummies.columns if '*' not in c]
for col in atom_col:
...: df[col] = dummies[[c for c in dummies.columns if col in c]].sum(axis=1)
...:
df
Out[32]:
label A B C D
0 A 1 0 0 0
1 B 0 1 0 0
2 C 0 0 1 0
3 D 0 0 0 1
4 A*C 1 0 1 0
5 C*D 0 0 1 1
この質問は、sklearnから MultiLabelBinarizer を見つけた後、更新された回答が必要だと思います。
これの使い方は次のように簡単です...
# Instantiate the binarizer
mlb = MultiLabelBinarizer()
# Using OP's original data frame
df = pd.DataFrame(data=['A', 'B', 'C', 'D', 'A*C', 'C*D'], columns=["label"])
print(df)
label
0 A
1 B
2 C
3 D
4 A*C
5 C*D
# Convert to a list of labels
df = df.apply(lambda x: x["label"].split("*"), axis=1)
print(df)
0 [A]
1 [B]
2 [C]
3 [D]
4 [A, C]
5 [C, D]
dtype: object
# Transform to a binary array
array_out = mlb.fit_transform(df)
print(array_out)
[[1 0 0 0]
[0 1 0 0]
[0 0 1 0]
[0 0 0 1]
[1 0 1 0]
[0 0 1 1]]
# Convert back to a dataframe (unnecessary step in many cases)
df_out = pd.DataFrame(data=array_out, columns=mlb.classes_)
print(df_out)
A B C D
0 1 0 0 0
1 0 1 0 0
2 0 0 1 0
3 0 0 0 1
4 1 0 1 0
5 0 0 1 1
これも非常に高速で、1000行と5万クラスにわたって実質的に時間(.03秒)を要しません。