如何为整列而不是每一列一次性编码 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