【问题标题】:Searching through strings in a dataframe and increasing the numbers found by 1在数据框中搜索字符串并将找到的数字增加 1
【发布时间】:2021-12-05 20:17:40
【问题描述】:

我有一个手动创建的数据框。我正在编写一个复制数据帧并将新数据帧连接到第一个数据帧末尾的代码。现在,我需要代码来查看包含字符串的“名称”数据框的列的每个值,如果字符串中有数字,则将该数字加 1。我需要将数字转换为 int这样我就可以创建一个函数来查看数据帧并自动将数据帧中的最大数字加 1。一个例子:

import pandas as pd
data = {'ID': [1,2,3,4],
        'Name': ['BN #1', 'HHC', 'A comp', 'B Comp']}
df = pd.DataFrame(data)

df['SysNum'] = [int(re.search('(?<=#)\d', x)[0]) for x in df['Name'].values]

之后新的df看起来像

data2 = {'ID': [1,2,3,4,5,6,7,8],
        'Name': ['BN #1', 'HHC', 'A comp', 'B Comp','BN #2', 'HHC', 'A comp', 'B Comp']} 

当我运行它时,我收到一个“NoneType”对象不可下标错误。这是有道理的,因为只有 BN # 行有一个数字,并且 re.search 在不满足字符串参数时返回 None,但我不知道如何告诉 python 忽略其他行。

编辑 每个数据帧只有第一行会增加 1,所以如果有一种更简单的方法我不使用 re.search,那很好。我知道有几种方法可以做到这一点,但我希望能够始终查看 BN 的字符串值,并在每次运行代码时将其增加 1。

正则表达式编辑

    df2['BaseName'] = [re.sub('\d', '', x) for x in df2['Name'].values]
    df['BaseName'] = [re.sub('\d', '', x) for x in df['Name'].values]
    df2['SysNum'] = [int(re.search('(?<=#)\d', x)[0]) for x in df2['Name'].values]
    # df2['SysNum'] = df2['Name'].get(r'(?<=#)\d').astype(int)
    # df['SysNum'] = [int(re.search('(?<=#)\d', x)[0]) for x in df['Name'].values]
    df['SysNum'] = df['Name'].str.contains('(?<=#)\d').astype(int)
    
    m =  re.search(r'(?<=#)\d', df2['Name'].iloc[0])
    if m:
        df2['SysNum'] = int(m.group(0)) + 1
    
    n = re.search(r'(?<=#)\d', df['Name'].iloc[0])
    if n:
        df['SysNum'] = int(n.group(1)) + 1
    
    
    new_names = df2['BaseName'].unique()
    maxes2 = np.zeros((len(new_names), ))
    
    for j in range(len(new_names)):
        un2 = new_names[j]
        maxes2[j] = df['SysNum'].loc[df['BaseName'] == un2].max()
        df2['SysNum'].loc[df2['BaseName'] == un2] = np.linspace(1, len(df2['SysNum'].loc[df2['BaseName'] == un2]), len(df2['SysNum'].loc[df2['BaseName'] == un2]))
        df2['SysNum'].loc[df2['BaseName'] == un2] += maxes2[j]
        newnames2 = [s + '%d' % num for s,num in zip(df2['BaseName'].loc[df2['BaseName'] == un2].values, df2['SysNum'].loc[df2['BaseName'] == un2].values)]
        df2['Name'].loc[df2['BaseName'] == un2] = newnames2

我的这段代码适用于两个数据帧,编号符合我的要求。前两个对数据框中的所有行都有一个“Name-###”命名约定。这允许顶部注释掉的 re.search 行运行得很好。我正在处理的接下来的两个数据框就像我之前用 BN #1 提出的示例,其余名称没有数字。当我运行注释掉的 re.search 行时,代码尝试将 NoneTypes 转换为 int 并且它不能这样做。当我现在按原样运行代码时,紧跟名称的每一行都会放置一个新数字,但我需要它在带有 # 的行中添加一个新数字。所以我需要并且我正在努力的是一段代码,它查看数据帧,寻找#号,将#号后的数字变成一个int,一个寻找最大int然后加1的循环该数字,将该新数字添加到新数据框,将新数据框添加到旧数据框以获得更大的主列表。

【问题讨论】:

  • 修复 NoneType 试试df['SysNum'] = df['Name'].str.contains('(?&lt;=#)\d').astype(int)
  • 我认为这很接近。如果为真则返回 1,否则返回 0。因此,当我到达 BN 2 和 3 等时,新的“SysNum”列中只显示了 1 个。
  • 那么,对于BN #1,SysNum 应该是2,对于BN #5,SysNum 应该是6?
  • df['SysNum'] = df['Name'].str.extract(r'#(\d+)') 怎么样?您想如何处理 NA 结果?
  • 我想我没有充分解释那部分。我真的不需要其他名字发生任何事情,它们都会保持不变。我从 BN 之后的数字创建整数的唯一原因是寻找最大值。所以这些其他值对于“SysNum”列来说并不重要。

标签: python regex re


【解决方案1】:

您可以使用df['Name'].iloc[0] 访问Name 列第一行的值。

因此,您可以在 # 使用该值登录后搜索数字序列

m =  re.search(r'#(\d+)', df['Name'].iloc[0])
if m:
    df['SysNum'] = int(m.group(1)) + 1

输出:

>>> df
   ID    Name  SysNum
0   1   BN #1       2
1   2     HHC       2
2   3  A comp       2
3   4  B Comp       2

【讨论】:

  • 谢谢!这真的很接近我需要的最终结果。所以我有一行从 BN#1 中删除了 1,现在我需要做的只是将 2 从“SysNum”添加到下一个 df 的 BN# 中。我创建了一个循环,但它要么没有添加正确的数字,要么将数字添加到所有名称。对这个问题有什么建议吗?
  • @JakeP 听起来已经是一个单独的问题了。否则,如果您认为仍然是同一个问题,请将当前代码添加到问题中并说明您现在需要什么。
  • @JakeP 如果您需要更多帮助,您应该将当前代码示例添加到问题中。我看不到你那边发生了什么。
  • 感谢您迄今为止的帮助!我添加了一些我一直在使用的实际代码,看看是否有人知道如何改进它。谢谢!
  • @JakeP 抱歉,现在还不清楚/太宽泛了。
猜你喜欢
  • 2023-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多