使用 .split() 和 .strip() 从 DataFrame 对象列中提取字符串

Extract strings from dataframe object column with .split() and .strip()

提问人:Maze 提问时间:10/10/2023 最后编辑:OCaMaze 更新时间:10/11/2023 访问量:183

问:

我有一个超过 17000 行和一列的数据帧。在此列中,多个条目显示为一个长字符串,用 和 分隔。'merged_tstbr''ID'';'\n

下面是此列中单元格的示例:

XDX_AbCd_XY_2415;\
XDX_AbCd_XY_3335;\
XDX_AbCd_XY_3351;\
XDX_AbCd_XY_3354

我使用以下脚本检查“ID”列中的所有行,如果 ID 在my_list中,则将其添加到新列表“tstbr_anf”中:

my_list = ['XDX_AbCd_XY_3351', 'XDX_AbCd_XY_3335'] # (and so on, 250 elements in total)
for index, row in merged_tstbr.iterrows():
    row_values = [value.strip() for value in row['ID'].split('\n')]       
    matching = [value for value in row_values if value in my_list]
    tstbr_anf.extend(matching)

在 250 个元素中,有 6 个未显示在 中。txtbr_anf

我在 excel 的“ID”列中检查了它们的存在,它们在这里,但不知何故没有被添加到 .它们也存在于my_list中。txtbr_anf

造成这种情况的可能原因是什么。

如何使用 Pandas 在 Python 中在 DataFrame 的一列中搜索一列中的任何和所有值 另一个数据帧的后续

Python pandas 列表 循环成员 资格

评论

1赞 Matthias Huschle 10/10/2023
你不剥离?;
0赞 mozway 10/10/2023
你能提供一个DataFrame构造函数的例子吗?另外,你有多少件物品?my_list
0赞 Maze 10/10/2023
@mozway我在my_list中有 250 件物品。我有来自另一个函数的merged_tstbr,并过滤了其他列中的 crtain 值
0赞 Maze 10/10/2023
@OCa 是的。从领域知识来看,我知道所有元素都应该与列表匹配。我检查了 excel 中的“ID”列中是否存在缺少的 ID [我转换为数据帧合并的 excel),它们在这里,但不知何故没有添加到tstbr_anf中。它们也存在于my_list中。
1赞 phydev 10/11/2023
如果提供未显示的 6 个元素,则除了最小的可重现代码示例外,它还有助于调试。

答:

1赞 OCa 10/10/2023 #1

我用来尝试重现您的问题的输入数据

  • 它基于您发布的单元格的内容,
  • 我添加了第二行,其中包含简单修改的数字。
my_list = ['XDX_AbCd_XY_3351', 'XDX_AbCd_XY_3335']

merged_tstbr = pd.DataFrame({'ID': ['XDX_AbCd_XY_2415;\nXDX_AbCd_XY_3335;\nXDX_AbCd_XY_3351;\nXDX_AbCd_XY_3354',
                                    'XDX_AbCd_XY_1234;\nXDX_AbCd_XY_4565;\nXDX_AbCd_XY_3579;\nXDX_AbCd_XY_7592']})

输入数据帧中的每个单元格都包含一个字符串中的多个 ID

                                                  ID
0  XDX_AbCd_XY_2415;\nXDX_AbCd_XY_3335;\nXDX_AbCd...
1  XDX_AbCd_XY_1234;\nXDX_AbCd_XY_4565;\nXDX_AbCd...

请确认这与你的输入匹配,否则提供数据帧构造函数。


问题:

你似乎认为这会删除分号,但事实并非如此,除非你强迫它这样做。您可以使用(在下面的代码中注释掉)来验证这一点:您正在测试成员资格,仍然有关于它们的分号.strip()printrow_values

['XDX_AbCd_XY_2415;', 'XDX_AbCd_XY_3335;', 'XDX_AbCd_XY_3351;', 'XDX_AbCd_XY_3354']

快速修复:

  1. 要么将其添加到 ,则不需要:.split().strip()
for index, row in merged_tstbr.iterrows():
    row_values = [value for value in row['ID'].split(';\n')]       
    #print(row_values)
    matching = [value for value in row_values if value in my_list]
    tstbr_anf.extend(matching)
  1. 或者强迫关心:.strip()
    row_values = [value.strip(';') for value in row['ID'].split('\n')]

两者都将输出为:tstbr_anf

['XDX_AbCd_XY_3335', 'XDX_AbCd_XY_3351']

现在为什么这个问题只出现在 6 个 ID 上,我们只能知道您何时提供更大的输入数据。可能是分号只存在于少数单元格中。

如果您的数据看起来与您上一个问题中的任何问题类似:如何使用 Pandas 在 Python 中搜索数据帧列中的任何和所有值,那么实际上并非所有 ID 都有分号,但它也可能是其他不需要的字符。


备选建议

下面的两步过程将提取这些 ID,并在列表中保留仅存在于my_list中的 ID。然后,您可以直接分配给 。tstbr_anf

  1. 清理 ID
    • 生成列表列表,从该 DataFrame 列中按单元格生成一个子列表)
    • 分号的计数可能并非在所有情况下都存在
L = merged_tstbr['ID'].str.split(pat = ';\n|\n', regex=True)

0    [XDX_AbCd_XY_2415, XDX_AbCd_XY_3335, XDX_AbCd_...
1    [XDX_AbCd_XY_1234, XDX_AbCd_XY_4565, XDX_AbCd_...
  1. 下一步同时执行两件事:
    • 将“子列表列表”展平为一个简单的列表
    • 并根据my_list进行筛选
my_set = set(my_list) # sets allow faster membership search

tstbr_anf = [item 
             for sublist in L
             for item in sublist 
             if item in my_set]

最终输出:

['XDX_AbCd_XY_3335', 'XDX_AbCd_XY_3351']

正如你所看到的,我们已经去掉了中间列表,它是代码中每行迭代的临时产物。matching

引用

0赞 mozway 10/10/2023 #2

假设您想查找列表和系列中所有项的全局交集,我将使用交集和正则表达式拆分:set

my_list = ['XDX_AbCd_XY_3351', 'XDX_AbCd_XY_3335']
my_set = set(my_list)

out = my_set.intersection(merged_tstbr['ID'].str.split('[;\n]+').explode())

# or
out = my_set.intersection(set().union(*merged_tstbr['ID'].str.split('[;\n]+')))

输出示例:{'XDX_AbCd_XY_3335', 'XDX_AbCd_XY_3351'}

如果您想要每行的交集:

import re

my_set = set(my_list)
out = [my_set.intersection(re.split('[;\n]+', s)) for s in merged_tstbr['ID']]

对于新列:

merged_tstbr['new'] = [my_set.intersection(re.split('[;\n]+', s))
                       for s in merged_tstbr['ID']]

输出示例:

                                                                          ID                                   new
0  XDX_AbCd_XY_2415;\nXDX_AbCd_XY_3335;\nXDX_AbCd_XY_3351;\nXDX_AbCd_XY_3354  {XDX_AbCd_XY_3335, XDX_AbCd_XY_3351}
1                     XDX_AbCd_XY_2416;\nXDX_AbCd_XY_3336;\nXDX_AbCd_XY_3351                    {XDX_AbCd_XY_3351}

使用的输入:

merged_tstbr = pd.DataFrame({'ID': ['XDX_AbCd_XY_2415;\nXDX_AbCd_XY_3335;\nXDX_AbCd_XY_3351;\nXDX_AbCd_XY_3354',
                                    'XDX_AbCd_XY_2416;\nXDX_AbCd_XY_3336;\nXDX_AbCd_XY_3351']})

评论

0赞 Maze 10/10/2023
出现属性错误:“str”对象没有属性“intersection”
0赞 mozway 10/10/2023
@Maze所以不能是,请再次检查您是否没有使用我的确切代码。S = set(my_list)Sstr
0赞 Maze 10/10/2023
将我的代码粘贴到下面
0赞 Maze 10/10/2023
s = set(self.bsm_rel_list) out = [s.intersection(re.split('[;\n]+', s)) for s in merged_tstbr['RQID']] for index, row in merged_tstbr_nr.iterrows(): print('Anzahl Testbarer Anforderungen', len(set(out)))
0赞 mozway 10/10/2023
你重用/我有的地方/(注意不同的情况!为了清楚起见,我将变量名称更改为。ssSsmy_set