Pandas 列表的列以分隔列

use*_*828 2 python encoding numpy scikit-learn

问题

传入数据是 0+ 类别的列表:

#input data frame
df = pd.DataFrame({'categories':(list('ABC'), list('BC'), list('A'))})

  categories
0  [A, B, C]
1     [B, C]
2        [A]
Run Code Online (Sandbox Code Playgroud)

我想将其转换为一个 DataFrame,每个类别一列,每个单元格中有一个 0/​​1:

#desired output

   A  B  C
0  1  1  1
1  0  1  1
2  1  0  0
Run Code Online (Sandbox Code Playgroud)

试图

OneHotEncoder 和 LabelEncoder 会陷入困境,因为它们不处理单元格中的列表。当前通过嵌套循环实现了预期的结果for

#get unique categories ['A','B','C']
categories = np.unique(np.concatenate(x['categories']))

#make empty data frame
binary_df = pd.DataFrame(columns=[c for c in categories],
                         index=x.index)

print(binary_df)
     A    B    C
0  NaN  NaN  NaN
1  NaN  NaN  NaN
2  NaN  NaN  NaN


#fill data frame
for i in binary_df.index:
    for c in categories:
        binary_df.loc[i][c] = 1 if c in np.concatenate(x.loc[i]) else 0
Run Code Online (Sandbox Code Playgroud)

我担心的是,循环表明这是处理大型数据集(数十个类别、数万行或更多行)的极其低效的方法。

有没有办法通过内置的 Numpy/Scikit 函数来实现结果?

EFT*_*EFT 6

解决方案:

pd.get_dummies(pd.DataFrame(df['categories'].tolist()).stack()).sum(level=0)
Out[98]: 
   A  B  C
0  1  1  1
1  0  1  1
2  1  0  0
Run Code Online (Sandbox Code Playgroud)

怎么运行的:

pd.DataFrame(df['categories'].tolist())
Out[100]: 
   0     1     2
0  A     B     C
1  B     C  None
2  A  None  None
Run Code Online (Sandbox Code Playgroud)

将一系列列表转换为数据帧。

pd.DataFrame(df['categories'].tolist()).stack()
Out[101]: 
0  0    A
   1    B
   2    C
1  0    B
   1    C
2  0    A
dtype: object
Run Code Online (Sandbox Code Playgroud)

为以后做好准备get_dummies,同时保留索引。

pd.get_dummies(pd.DataFrame(df['categories'].tolist()).stack())
Out[102]: 
     A  B  C
0 0  1  0  0
  1  0  1  0
  2  0  0  1
1 0  0  1  0
  1  0  0  1
2 0  1  0  0
Run Code Online (Sandbox Code Playgroud)

差不多了,但是包含了初始列表中值索引的垃圾信息。

因此,上面的解决方案对这个级别的多索引求和。

编辑:

%timeit结果:

在原始数据框上

df = pd.DataFrame({'categories':(list('ABC'), list('BC'), list('A'))})
Run Code Online (Sandbox Code Playgroud)

有问题提供的解决方案: 100 loops, best of 3: 3.24 ms per loop

这个解决方案: 100 loops, best of 3: 2.29 ms per loop

300行

df = pd.concat(100*[df]).reset_index(drop=True)
Run Code Online (Sandbox Code Playgroud)

有问题提供的解决方案: 1 loop, best of 3: 252 ms per loop

这个解决方案: 100 loops, best of 3: 2.45 ms per loop