【问题标题】:Pandas column of lists to separate columns列表的 Pandas 列以分隔列
【发布时间】:2017-11-23 06:23:03
【问题描述】:

问题

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

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

  categories
0  [A, B, C]
1     [B, C]
2        [A]

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

#desired output

   A  B  C
0  1  1  1
1  0  1  1
2  1  0  0

尝试

带有 LabelEncoder 的 OneHotEncoder 会卡住,因为它们不处理单元格中的列表。目前使用嵌套的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

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

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

【问题讨论】:

  • 避免在 cmets 中回答问题。

标签: python numpy encoding scikit-learn


【解决方案1】:

解决方案:

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

工作原理:

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

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

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

准备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

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

所以上面的解决方案在 MultiIndex 的这个级别上求和。

编辑:

%timeit 结果:

在原始数据帧上

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

提供的解决方案: 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)

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

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

【讨论】:

  • 优秀的细分。我从来没有想过get_dummies 会是一个单独的名称用于此目的的函数。谢谢!
  • @user1717828 是的,我认为它是“获取虚拟变量”的缩写,这可能更直观。
【解决方案2】:

您可以尝试使用 map 追加行,如果输入 dataframe row 中存在该列,则默认情况下它将设置为 0 并更新为 1

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

输出:

   categories
0  [A, B, C]
1     [B, C]
2        [A]

对于输出dataframe

categories = np.unique(np.concatenate(df['categories']))
#make empty data frame
binary_df = pd.DataFrame(columns=[c for c in categories],
                     index=df.index).dropna()

for index, row in df.iterrows():
    row_elements = row['categories']
    default_row = {item:0 for item in categories}
    # update corresponding row value by updating dictionary
    for i in row_elements:
        default_row[i] = 1
    binary_df = binary_df.append(default_row, ignore_index=True)

print(binary_df)

输出:

     A    B    C
0  1.0  1.0  1.0
1  0.0  1.0  1.0
2  1.0  0.0  0.0

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-25
    • 2018-06-09
    • 2023-03-14
    • 2022-01-01
    • 1970-01-01
    相关资源
    最近更新 更多