爆炸熊猫数据框列

Posted

技术标签:

【中文标题】爆炸熊猫数据框列【英文标题】:exploding a pandas dataframe column 【发布时间】:2019-01-15 12:09:37 【问题描述】:

我有一个看起来像这样的 Pandas 数据框:

text = ["abcd", "efgh", "ijkl", "mnop", "qrst", "uvwx", "yz"]

labels = ["label_1, label_2", 
          "label_1, label_3, label_2", 
          "label_2, label_4", 
          "label_1, label_2, label_5", 
          "label_2, label_3", 
          "label_3, label_5, label_1, label_2", 
          "label_1, label_3"]

df = pd.DataFrame(dict(text=text, labels=labels))
df



   text                              labels
0  abcd                    label_1, label_2
1  efgh           label_1, label_3, label_2
2  ijkl                    label_2, label_4
3  mnop           label_1, label_2, label_5
4  qrst                    label_2, label_3
5  uvwx  label_3, label_5, label_1, label_2
6    yz                    label_1, label_3

我想把数据框格式化成这样:

text  label_1  label_2  label_3  label_4  label_5

abcd        1.0      1.0      0.0      0.0      0.0
efgh        1.0      1.0      1.0      0.0      0.0
ijkl        0.0      1.0      0.0      1.0      0.0
mnop        1.0      1.0      0.0      0.0      1.0
qrst        0.0      1.0      1.0      0.0      0.0
uvwx        1.0      1.0      1.0      0.0      1.0
yz          1.0      0.0      1.0      0.0      0.0

我怎样才能做到这一点? (我知道我可以拆分标签中的字符串并将它们转换为列表,方法是执行df.labels.str.split(",") 之类的操作,但不确定如何从那里继续。

(所以基本上我想将标签列中的这些关键字转换为自己的列,并在它们出现在预期输出中时填写 1)

【问题讨论】:

标签列中的值是否有最大数量? @MohitMotwani 不,它不是固定的,它可能会有所不同。 pandas: How do I split text in a column into multiple rows?的可能重复 @MohitMotwani 我试过了,它没有产生所需的解决方案 【参考方案1】:

如果列数是动态的,这将有助于找到可能的列。

unique = df['labels'].apply(lambda x: x.split(", ")).values.tolist()
unique = [i for sublist in unique for i in sublist]
unique = set(unique)

因此,现在是独一无二的。 'label_1'、'label_2'、'label_3'、'label_4'、'label_5'

max_label = len(unique)

这将为我们提供最大的列数。

回答

def labeller(labels):
    value = [0] * max_label
    for label in labels:
        value[int(label[-1])-1] = 1
    return value

df['labels'] = df['labels'].apply(lambda x: x.split(", ")).apply(labeller)

df[['label_' + str(i+1) for i in range(max_label)]] = df.labels.apply(pd.Series)
df.drop(['labels'], axis=1, inplace=True)

    text    label_1 label_2 label_3 label_4 label_5
0   abcd    1       1       0       0       0
1   efgh    1       1       1       0       0
2   ijkl    0       1       0       1       0
3   mnop    1       1       0       0       1
4   qrst    0       1       1       0       0
5   uvwx    1       1       1       0       1
6   yz      1       0       1       0       0

【讨论】:

【参考方案2】:

代码:

text = ["abcd", "efgh", "ijkl", "mnop", "qrst", "uvwx", "yz"]

labels = ["label_1, label_2",
          "label_1, label_3, label_2",
          "label_2, label_4",
          "label_1, label_2, label_5",
          "label_2, label_3",
          "label_3, label_5, label_1, label_2",
          "label_1, label_3"]

df = pd.DataFrame(dict(text=text, labels=labels))
df = df.drop('labels', axis=1).join(
             df.labels
             .str
             .split(', ', expand=True)
             .stack()
             .reset_index(drop=True, level=1)
             .rename('labels')
             )

df['value'] = 1
df_new = df.pivot(values = 'value', index='text', columns = 'labels').fillna(0)
print(df_new)

输出:

labels  text  label_1  label_2  label_3  label_4  label_5
0       abcd      1.0      1.0      0.0      0.0      0.0
1       efgh      1.0      1.0      1.0      0.0      0.0
2       ijkl      0.0      1.0      0.0      1.0      0.0
3       mnop      1.0      1.0      0.0      0.0      1.0
4       qrst      0.0      1.0      1.0      0.0      0.0
5       uvwx      1.0      1.0      1.0      0.0      1.0
6         yz      1.0      0.0      1.0      0.0      0.0

在这个主要的事情是拆分使用 (,) 与空间,因为你的字符串格式,如果你改变该格式而不是使用适当的拆分。

例如:

如果您像这样使用带有单个逗号的拆分

df = df.drop('labels', axis=1).join(
                 df.labels
                 .str
                 .split(',', expand=True)
                 .stack()
                 .reset_index(drop=True, level=1)
                 .rename('labels')
                 )

那么您将需要额外的代码来删除空格

df['labels'] = df['labels'].str.replace(" ", "")

其余代码将相同。

【讨论】:

【参考方案3】:

一个简单的解决方案是使用pd.get_dummies,如下所示:

pd.get_dummies(
    df.set_index('text')['labels'].str.split(', ', expand=True).stack()
).groupby('text').sum()

【讨论】:

【参考方案4】:

您可以使用pd.Series.str.get_dummies 并与text 系列结合使用:

dummies = df['labels'].str.replace(' ', '').str.get_dummies(',')
res = df['text'].to_frame().join(dummies)

print(res)

   text  label_1  label_2  label_3  label_4  label_5
0  abcd        1        1        0        0        0
1  efgh        1        1        1        0        0
2  ijkl        0        1        0        1        0
3  mnop        1        1        0        0        1
4  qrst        0        1        1        0        0
5  uvwx        1        1        1        0        1
6    yz        1        0        1        0        0

【讨论】:

以上是关于爆炸熊猫数据框列的主要内容,如果未能解决你的问题,请参考以下文章

如何迭代熊猫数据框列中的元素?

熊猫地图数据框列

熊猫数据框列计算

groupby之后的熊猫数据框列[重复]

如何将小时添加到熊猫数据框列

Apache Spark 数据框列爆炸为多列