如何将Pandas DataFrame中的列表列中的分隔字符串展开?

4

我有一个带有一个列表列的 pandas DataFrame,例如:

df = pd.DataFrame({"pairs": [["A|B", "B|C", "C|D", "D|F"], ["A|D", "D|F", "F|G", "G|D"], ["C|D", "D|X"]]})

pairs列中的列表总是包含连续的一对,其中一对元素由 | 分隔。我希望将这些列中的列表“展平”,即不再存储一对元素,而是按照相同的顺序存储一对元素的各个元素。因此,期望得到的DataFrame如下所示:

elements
[A, B, C, D, F]
[A, D, F, G, D]
[C, D, X]

(编辑:我还希望在结果列表中多次出现元素,比如第二行中的D
这看起来很简单,我不敢相信没有一个有效的解决方案,但到目前为止,我还没有找到任何能够帮助我的Python方法。
2个回答

2
最简单的方法是使用双重explode和groupby+unique:

df['pairs'].explode().str.split("|").explode().groupby(level=0).unique()

0    [A, B, C, D, F]
1       [A, D, F, G]
2          [C, D, X]
Name: pairs, dtype: object

将其分配回去:

df['elements'] = df['pairs'].explode().str.split("|").explode().groupby(level=0).unique()

编辑:

如果只考虑连续的重复项,请使用:

s = df['pairs'].explode().str.split("|").explode()
out = s[s.ne(s.shift())].groupby(level=0).agg(list)

如果列表中出现多个相同的配对,这个方法还能正常工作吗?例如,如果我们有[A|B, B|C, C|D, D|C],那么这个方法会返回[A, B, C, D, C]吗? - Peter
@Peter,我更新了我的答案,以回应你的评论。 - anky
非常抱歉我之前表达有些迟缓,并没有特别提及。如果您能帮我找到一个同时适用于这种情况的解决方案,我将接受您的答案。 - Peter
@Peter 请查看编辑部分。我现在已根据您的评论进行了更新。 - anky
谢谢您的编辑!运行需要大量时间,但我会检查它是否有效。 - Peter

2
您可以使用集合推导式:
df["elements"] = df["pairs"].apply(
    lambda x: {ww for w in x for ww in w.split("|")}
)
print(df)

输出:

                  pairs         elements
0  [A|B, B|C, C|D, D|F]  {B, C, D, A, F}
1       [A|D, D|F, F|G]     {G, D, F, A}
2            [C|D, D|X]        {X, C, D}

如果您想要列表:
df["elements"] = df["pairs"].apply(
    lambda x: list({ww for w in x for ww in w.split("|")})
)
print(df)

                  pairs         elements
0  [A|B, B|C, C|D, D|F]  [D, F, A, C, B]
1       [A|D, D|F, F|G]     [G, D, A, F]
2            [C|D, D|X]        [X, D, C]

编辑:为了维护秩序:
def fn(x):
    seen = set()
    out = []
    for v in x:
        for w in v.split("|"):
            if not w in seen:
                seen.add(w)
                out.append(w)
    return out


df["elements"] = df["pairs"].apply(fn)
print(df)

输出:

                  pairs         elements
0  [A|B, B|C, C|D, D|F]  [A, B, C, D, F]
1  [A|D, D|F, F|G, G|D]     [A, D, F, G]
2            [C|D, D|X]        [C, D, X]


编辑:为保留多个元素和顺序:
from itertools import groupby, chain

def fn(x):
    return [v for v, _ in groupby(chain.from_iterable(v.split("|") for v in x))]

df["elements"] = df["pairs"].apply(fn)
print(df)

输出:

                  pairs         elements
0  [A|B, B|C, C|D, D|F]  [A, B, C, D, F]
1  [A|D, D|F, F|G, G|D]  [A, D, F, G, D]
2            [C|D, D|X]        [C, D, X]

如果列表中出现多个相同的配对,这个方法还能正常工作吗?例如,如果我们有[A|B, B|C, C|D, D|C],那么这个方法会返回[A, B, C, D, C]吗? - Peter
你的答案没有保持元素对的顺序,这是非常重要的。你有解决方案吗? - Peter
1
@Peter 我已经编辑了我的答案以保持顺序。 - Andrej Kesely
1
@Peter 我还添加了一个解决方案,以保留结果中的多个元素。 - Andrej Kesely

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接