web-dev-qa-db-ja.com

データフレーム全体でpandas.factorize

pandas.factorize は、入力値を列挙型またはカテゴリ変数としてエンコードします。

しかし、データフレームの多くの列を簡単かつ効率的に変換するにはどうすればよいですか?逆マッピング手順はどうですか?

例:このデータフレームには、「type 2」などの文字列値が含まれる列が含まれます。これらの列を数値に変換し、後で変換することもできます。

enter image description here

14
clstaudt

各列を個別にapplyする必要がある場合は、factorizeを使用できます。

df = pd.DataFrame({'A':['type1','type2','type2'],
                   'B':['type1','type2','type3'],
                   'C':['type1','type3','type3']})

print (df)
       A      B      C
0  type1  type1  type1
1  type2  type2  type3
2  type2  type3  type3

print (df.apply(lambda x: pd.factorize(x)[0]))
   A  B  C
0  0  0  0
1  1  1  1
2  1  2  1

同じ文字列値に同じ数値が必要な場合:

print (df.stack().rank(method='dense').unstack())
     A    B    C
0  1.0  1.0  1.0
1  2.0  2.0  3.0
2  2.0  3.0  3.0

一部の列にのみ関数を適用する必要がある場合は、サブセットを使用します。

df[['B','C']] = df[['B','C']].stack().rank(method='dense').unstack()
print (df)
       A    B    C
0  type1  1.0  1.0
1  type2  2.0  3.0
2  type2  3.0  3.0

factorize を使用したソリューション:

stacked = df[['B','C']].stack()
df[['B','C']] = pd.Series(stacked.factorize()[0], index=stacked.index).unstack()
print (df)
       A  B  C
0  type1  0  0
1  type2  1  2
2  type2  2  2

map by dictを使用して、元に戻すことができます。この場合、 drop_duplicates

vals = df.stack().drop_duplicates().values
b = [x for x in df.stack().drop_duplicates().rank(method='dense')]

d1 = dict(Zip(b, vals))
print (d1)
{1.0: 'type1', 2.0: 'type2', 3.0: 'type3'}

df1 = df.stack().rank(method='dense').unstack()
print (df1)
     A    B    C
0  1.0  1.0  1.0
1  2.0  2.0  3.0
2  2.0  3.0  3.0

print (df1.stack().map(d1).unstack())
       A      B      C
0  type1  type1  type1
1  type2  type2  type3
2  type2  type3  type3
25
jezrael

また、この回答は非常に有用であることがわかりました: https://stackoverflow.com/a/20051631/4643212

Pandas DataFrame( 'SrcIP'という名前のIPアドレスのリスト)の既存の列から値を取得し、新しい列( 'ID'という名前のこの例)。

解決:

df['ID'] = pd.factorize(df.SrcIP)[0]

結果:

        SrcIP | ID    
192.168.1.112 |  0  
192.168.1.112 |  0  
192.168.4.118 |  1 
192.168.1.112 |  0
192.168.4.118 |  1
192.168.5.122 |  2
192.168.5.122 |  2
...
4
Gabe F.

私の答えをリダイレクトしたい: https://stackoverflow.com/a/32011969/1694714

古い答え

結果のDataFrame全体でカテゴリの一貫性を保ちたい場合、この問題の別の読み取り可能なソリューションは、replaceを使用しています。

def categorise(df):
    categories = {k: v for v, k in enumerate(df.stack().unique())}
    return df.replace(categories)

@jezraelの例よりもパフォーマンスはわずかに劣りますが、読みやすくなっています。また、大規模なデータセットの方がエスカレートしやすい場合があります。誰かが興味を持っている場合、適切なテストを行うことができます。

0
tbrittoborges