将数据框字符串列转换为多列并根据标签重新排列每列

Converting a dataframe stringcolumn into multiple columns and rearrange each column based on the labels

我想将具有多个标签的字符串列转换为每个标签的单独列,并重新排列相同标签在同一列中的数据框。例如:

ID Label
0 apple, tom, car
1 apple, car
2 tom, apple

ID Label 0 1 2
0 apple, tom, car apple car tom
1 apple, car apple car None
2 tom, apple apple None tom
df["Label"].str.split(',',3, expand=True)
0 1 2
apple tom car
apple car None
tom apple None

我知道如何拆分字符串列,但我真的不知道如何对标签列进行排序,尤其是因为每个样本的标签数量不同。

你的程序目标不明确。如果您对不同行中存在哪些元素感到好奇,那么我们可以将它们全部获取并像这样堆叠数据框:

df = pd.DataFrame({'label': ['apple, banana, grape', 'apple, banana', 'banana, grape']})
final_df = df['label'].str.split(', ', expand=True).stack()
final_df.reset_index(drop=True, inplace=True)
>>> final_df
0     apple
1    banana
2     grape
3     apple
4    banana
5    banana
6     grape

此时我们可以删除重复项或计算每个重复项的出现次数,具体取决于您的用例。

尝试:

df = df.assign(xxx=df.Label.str.split(r"\s*,\s*")).explode("xxx")
df["Col"] = df.groupby("xxx").ngroup()
df = (
    df.set_index(["ID", "Label", "Col"])
    .unstack(2)
    .droplevel(0, axis=1)
    .reset_index()
)
df.columns.name = None
print(df)

打印:

   ID            Label      0    1    2
0   0  apple, tom, car  apple  car  tom
1   1       apple, car  apple  car  NaN
2   2       tom, apple  apple  NaN  tom

这是一种方法。

首先调用 df['Label'].apply() 以用列表替换 csv 字符串,并将 Python 字典映射标签填充到新的列索引值。

然后创建第二个数据框 df2 来填充问题中指定的新标签列。

最后,水平连接两个 DataFrame 并删除 'Label' 列。

import pandas as pd
import numpy as np
df = pd.DataFrame({
    'ID' : [0,1,2],
    'Label' : ['apple, tom, car', 'apple, car', 'tom, apple']
})

labelInfo = [labels := {}, curLabelIdx := 0]
def foo(x, labelInfo):
    theseLabels = [s.strip() for s in x.split(',')]
    labels, curLabelIdx = labelInfo
    for label in theseLabels:
        if label not in labels:
            labels[label] = curLabelIdx
            curLabelIdx += 1
    labelInfo[1] = curLabelIdx
    return theseLabels
df['Label'] = df['Label'].apply(foo, labelInfo=labelInfo)
df2 = pd.DataFrame(np.array(df['Label'].apply(lambda x: [s if s in x else 'None' for s in labels]).to_list()), 
    columns = list(labels.values()))
df = pd.concat([df, df2], axis=1).drop(columns=['Label'])

print(df)

输出:

   ID      0     1     2
0   0  apple   tom   car
1   1  apple  None   car
2   2  apple   tom  None

如果您希望使用它们包含的标签命名新列,您可以将 df2 赋值行替换为:

df2 = pd.DataFrame(np.array(df['Label'].apply(lambda x: [s if s in x else 'None' for s in labels]).to_list()), 
    columns = list(labels))

现在输出是:

   ID  apple   tom   car
0   0  apple   tom   car
1   1  apple  None   car
2   2  apple   tom  None

我相信你想要的是这样的:

import pandas as pd

data = {'Label': ['apple, tom, car', 'apple, car', 'tom, apple']}
df = pd.DataFrame(data)
print(f"df: \n{df}")

def norm_sort(series):
    mask = []
    for line in series:
        mask.extend([l.strip() for l in line.split(',')])
    mask = sorted(list(set(mask)))
    labels = []
    for line in series:
        labels.append(', '.join([m if m in line else 'None' for m in mask]))
    return labels

df.Label = norm_sort(df.loc[:, 'Label'])
df = df.Label.str.split(', ', expand=True)
print(f"df: \n{df}")