如何为整列而不是每一列一次性编码 pandas 数据帧?
How do I one-hot encode pandas dataframe for whole columns, not for each column?
我想为整列而不是每一列一次性编码 pandas 数据帧。
如果有如下数据框:
df = pd.DataFrame({'A': ['A1', 'A1', 'A1', 'A1', 'A4', 'A5'], 'B': ['A2', 'A2', 'A2', 'A3', np.nan, 'A6], 'C': ['A4', 'A3', 'A3', 'A5', np.nan, np.nan]})
df =
A B C
0 A1 A2 A4
1 A1 A2 A3
2 A1 A2 A3
3 A1 A3 A5
4 A4 NaN NaN
5 A5 A6 NaN
我想像下面这样编码:
df =
A1 A2 A3 A4 A5 A6
0 1 1 0 1 0 0
1 1 1 1 0 0 0
2 1 1 1 0 0 0
3 1 0 1 0 1 0
4 0 0 0 1 0 0
5 0 0 0 0 1 1
但是,如果我编写如下代码,结果如下:
df = pd.get_dummies(df, sparse=True)
df =
A_A1 A_A4 A_A5 B_A2 B_A3 B_A6 C_A3 C_A4 C_A5
0 1 0 0 1 0 0 0 1 0
1 1 0 0 1 0 0 1 0 0
2 1 0 0 1 0 0 1 0 0
3 1 0 0 0 1 0 0 0 1
4 0 1 0 0 0 0 0 0 0
5 0 0 1 0 0 1 0 0 0
如何对整列进行一次性编码?
如果我使用 prefix = '',它还会生成 _A1 _A4 _A5 _A2 _A3 _A6 _A3 _A4 _A5 等列。
(我希望使用 pandas 或 numpy 库编写代码,而不是 for-loop 朴素代码,因为我的数据非常庞大;16000000 行,因此迭代 for-loop 朴素代码将需要很长的计算时间)。
你的情况
df.stack().str.get_dummies().sum(level=0)
Out[116]:
A1 A2 A3 A4 A5 A6
0 1 1 0 1 0 0
1 1 1 1 0 0 0
2 1 1 1 0 0 0
3 1 0 1 0 1 0
4 0 0 0 1 0 0
5 0 0 0 0 1 1
或者用 prefix
修复你的 pd.get_dummies
pd.get_dummies(df, prefix='',prefix_sep='').sum(level=0,axis=1)
Out[118]:
A1 A4 A5 A2 A3 A6
0 1 1 0 1 0 0
1 1 0 0 1 1 0
2 1 0 0 1 1 0
3 1 0 1 0 1 0
4 0 1 0 0 0 0
5 0 0 1 0 0 1
更快
# Pandas 0.24 or greater use `.to_numpy()` instead of `.values`
v = df.values
n, m = v.shape
j, cols = pd.factorize(v.ravel()) # -1 when `np.nan`
# Used to grab only non-null values
mask = j >= 0
i = np.arange(n).repeat(m)[mask]
j = j[mask]
out = np.zeros((n, len(cols)), dtype=int)
# Useful when not one-hot. Otherwise use `out[i, j] = 1`
np.add.at(out, (i, j), 1)
pd.DataFrame(out, df.index, cols)
A1 A2 A4 A3 A5 A6
0 1 1 1 0 0 0
1 1 1 0 1 0 0
2 1 1 0 1 0 0
3 1 0 0 1 1 0
4 0 0 1 0 0 0
5 0 0 0 0 1 1
不快
这是为了表明您可以加入行值然后使用 str.get_dummies
df.stack().groupby(level=0).apply('|'.join).str.get_dummies()
A1 A2 A3 A4 A5 A6
0 1 1 0 1 0 0
1 1 1 1 0 0 0
2 1 1 1 0 0 0
3 1 0 1 0 1 0
4 0 0 0 1 0 0
5 0 0 0 0 1 1
sklearn
from sklearn.preprocessing import MultiLabelBinarizer as MLB
mlb = MLB()
out = mlb.fit_transform([[*filter(pd.notna, x)] for x in zip(*map(df.get, df))])
pd.DataFrame(out, df.index, mlb.classes_)
A1 A2 A3 A4 A5 A6
0 1 1 0 1 0 0
1 1 1 1 0 0 0
2 1 1 1 0 0 0
3 1 0 1 0 1 0
4 0 0 0 1 0 0
5 0 0 0 0 1 1
我想为整列而不是每一列一次性编码 pandas 数据帧。
如果有如下数据框:
df = pd.DataFrame({'A': ['A1', 'A1', 'A1', 'A1', 'A4', 'A5'], 'B': ['A2', 'A2', 'A2', 'A3', np.nan, 'A6], 'C': ['A4', 'A3', 'A3', 'A5', np.nan, np.nan]})
df =
A B C
0 A1 A2 A4
1 A1 A2 A3
2 A1 A2 A3
3 A1 A3 A5
4 A4 NaN NaN
5 A5 A6 NaN
我想像下面这样编码:
df =
A1 A2 A3 A4 A5 A6
0 1 1 0 1 0 0
1 1 1 1 0 0 0
2 1 1 1 0 0 0
3 1 0 1 0 1 0
4 0 0 0 1 0 0
5 0 0 0 0 1 1
但是,如果我编写如下代码,结果如下:
df = pd.get_dummies(df, sparse=True)
df =
A_A1 A_A4 A_A5 B_A2 B_A3 B_A6 C_A3 C_A4 C_A5
0 1 0 0 1 0 0 0 1 0
1 1 0 0 1 0 0 1 0 0
2 1 0 0 1 0 0 1 0 0
3 1 0 0 0 1 0 0 0 1
4 0 1 0 0 0 0 0 0 0
5 0 0 1 0 0 1 0 0 0
如何对整列进行一次性编码? 如果我使用 prefix = '',它还会生成 _A1 _A4 _A5 _A2 _A3 _A6 _A3 _A4 _A5 等列。 (我希望使用 pandas 或 numpy 库编写代码,而不是 for-loop 朴素代码,因为我的数据非常庞大;16000000 行,因此迭代 for-loop 朴素代码将需要很长的计算时间)。
你的情况
df.stack().str.get_dummies().sum(level=0)
Out[116]:
A1 A2 A3 A4 A5 A6
0 1 1 0 1 0 0
1 1 1 1 0 0 0
2 1 1 1 0 0 0
3 1 0 1 0 1 0
4 0 0 0 1 0 0
5 0 0 0 0 1 1
或者用 prefix
pd.get_dummies
pd.get_dummies(df, prefix='',prefix_sep='').sum(level=0,axis=1)
Out[118]:
A1 A4 A5 A2 A3 A6
0 1 1 0 1 0 0
1 1 0 0 1 1 0
2 1 0 0 1 1 0
3 1 0 1 0 1 0
4 0 1 0 0 0 0
5 0 0 1 0 0 1
更快
# Pandas 0.24 or greater use `.to_numpy()` instead of `.values`
v = df.values
n, m = v.shape
j, cols = pd.factorize(v.ravel()) # -1 when `np.nan`
# Used to grab only non-null values
mask = j >= 0
i = np.arange(n).repeat(m)[mask]
j = j[mask]
out = np.zeros((n, len(cols)), dtype=int)
# Useful when not one-hot. Otherwise use `out[i, j] = 1`
np.add.at(out, (i, j), 1)
pd.DataFrame(out, df.index, cols)
A1 A2 A4 A3 A5 A6
0 1 1 1 0 0 0
1 1 1 0 1 0 0
2 1 1 0 1 0 0
3 1 0 0 1 1 0
4 0 0 1 0 0 0
5 0 0 0 0 1 1
不快
这是为了表明您可以加入行值然后使用 str.get_dummies
df.stack().groupby(level=0).apply('|'.join).str.get_dummies()
A1 A2 A3 A4 A5 A6
0 1 1 0 1 0 0
1 1 1 1 0 0 0
2 1 1 1 0 0 0
3 1 0 1 0 1 0
4 0 0 0 1 0 0
5 0 0 0 0 1 1
sklearn
from sklearn.preprocessing import MultiLabelBinarizer as MLB
mlb = MLB()
out = mlb.fit_transform([[*filter(pd.notna, x)] for x in zip(*map(df.get, df))])
pd.DataFrame(out, df.index, mlb.classes_)
A1 A2 A3 A4 A5 A6
0 1 1 0 1 0 0
1 1 1 1 0 0 0
2 1 1 1 0 0 0
3 1 0 1 0 1 0
4 0 0 0 1 0 0
5 0 0 0 0 1 1