【问题标题】:In Pandas Dataframe error: nothing to repeat at position 17217在 Pandas Dataframe 中出现错误:在 17217 位置没有重复内容
【发布时间】:2021-12-03 00:47:10
【问题描述】:

我正在尝试使用str.contains 在另一个数据框的另一列中识别数据框一列的元素。代码如下:

pattern = fr"(?:{'|'.join(strategic_accounts['Account Name'])})"
all_leads['in_strategic_list'] = all_leads['Company'].str.contains(pattern).astype(int)

这是两个数据帧的头部以及all_leads 数据帧的位置 17271。我不明白这个错误,因为它看起来在 17217 位置没有任何异常。此外,所有在线相关错误似乎都指向error nothing to repeat at position 0,这似乎是一个不同的错误,因为我的错误出现在 loc 17217 .任何见解表示赞赏!谢谢!

这个模拟示例与相同的代码完美配合:

df1 = pd.DataFrame({'name': ['Marc', 'Jake', 'Sam', 'Brad', 'SpongeBob']})
df2 = pd.DataFrame({'IDs': ['Jake', 'John', 'Marc', 'Tony', 'Bob']})

pattern = fr"(?:{'|'.join(df2['IDs'])})"

df1['In_df2'] = df1['name'].str.contains(pattern).astype(int)

更新: 我设法弄清楚该错误是指模式中的 loc 17217 而不是 strategy_accounts df。以模式打印 loc 17217 返回 '*'。在将其插入str.contains 之前,我曾尝试将此函数应用于pattern,但我似乎无法将其删除。

import re

pattern = fr"(?:{'|'.join(strategic_accounts['Account Name'])})"
def esc_spec_char(pattern):
    for p in pattern:
        if p == '\*':
            re.sub('*', '1', p)
        else:
            continue
    return pattern
pattern = esc_spec_char(pattern)
pattern[17217]

新_更新: 我已经应用了@LiamFiddler 将字符串转换为re.Pattern 对象并在虚拟df 上运行它的方法,虽然它似乎确实逃脱了*,但它似乎没有找到N。不确定我是否犯了一些错误。代码如下:

sries = pd.Series(['x','y','$','%','^','N','*'])
ac = '|'.join(sries)
p = re.compile(re.escape(ac))
df1 = pd.DataFrame(data = {'Id' : [123, 232, 344, 455, 566, 377], 
                           'col2' : ["N", "X", "Y", '*', "W", "Z"]})
df1['col2'].str.contains(p, regex=True).astype(int)

【问题讨论】:

  • 您使用正则表达式而不是pandas.Series.isin()的任何原因?
  • @liamfiddler 感谢您的评论!我正在将潜在客户对象与帐户对象进行比较,并且在某些情况下,帐户名称在从潜在客户转换后已被修改,因此它们仍将保留与潜在客户相同的大部分原始字符串,但差异很小。换句话说,不是完全匹配,所以.isin 不起作用
  • 明白了,有道理。该函数是否适用于其他行,而不是这个特定的行?
  • 我怀疑您的模式字符串存在偷偷摸摸的问题。查看有关组合 f-string 和 r-strings 的答案:stackoverflow.com/a/61625479/12229158
  • @liamfiddler 谢谢!所以我尝试在高达 17216 的元素上运行它,它仍然抛出同样的错误。我用一个在两个示例 dfs 上工作的示例更新了原始帖子。也许这会带来更多启示?

标签: pandas


【解决方案1】:

编辑

我意识到re.escape() 也逃脱了| 分隔符,所以我认为适当的解决方案是将re.escape() 映射到系列之前加入名称:

strategic_accounts['Escaped Accounts'] = strategic_accounts['Account Name'].apply(lambda x: re.escape(x))
pattern = re.compile('|'.join(strategic_accounts['Escaped Accounts']))

然后您可以使用Series.str.contains() 进行如下操作。在您的示例数据框中,我得到了以下信息:

sries = pd.Series(['x','y','$','%','^','N','*'])
ac = sries.apply(lambda x: re.escape(x))
p = re.compile('|'.join(ac))
df1 = pd.DataFrame(data = {'Id' : [123, 232, 344, 455, 566, 377], 
                           'col2' : ["N", "X", "Y", '*', "W", "Z"]})
df1['col2'].str.contains(p, regex=True).astype(int)

Out:
0    1
1    0
2    0
3    1
4    0
5    0

原创

好的,所以基于对特殊字符的发现,我认为这是你的解决方案:

首先,我们需要对字符串中的特殊字符进行转义,以免它们弄乱正则表达式。幸运的是,Python 的 re 模块有一个 .escape() 方法专门用于转义特殊字符。

import re
accounts = '|'.join(strategic_accounts['Account Name'])
pattern = re.compile(re.escape(accounts))

现在我们可以像以前一样继续:

all_leads['in_strategic_list'] = all_leads['Company'].str.contains(pattern, regex=True).astype(int)

【讨论】:

  • @JustinBenfit 我跟不上。为什么要逃避“N”?
  • @JustinBenfit 我想我看到了错误; re.escape() 也逃脱了管道 |,所以我们需要想办法解决这个问题。我认为最好的方法可能是将re.escape() 函数映射到系列,然后使用管道加入它。
  • @JustinBenfit 查看更新的解决方案。
  • 这是一些很棒的魔法!我觉得我对 pandas 的了解增加了很多,只是看着你完成了这些工作!非常感谢您的帮助@LiamFiddler!
  • 很高兴为您提供帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-03-23
  • 2016-08-02
  • 1970-01-01
  • 2020-12-02
  • 1970-01-01
  • 2018-02-12
相关资源
最近更新 更多