将数据框字符串列转换为多列并根据标签重新排列每列
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}")
我想将具有多个标签的字符串列转换为每个标签的单独列,并重新排列相同标签在同一列中的数据框。例如:
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}")