【问题标题】:Updating dataframe value based on list根据列表更新数据框值
【发布时间】:2021-01-14 09:46:40
【问题描述】:

我有一个数据框,基于名为“originator”的列中的字符串,我想检查该字符串是否包含位于另一个列表中的单词。如果字符串中有一个单词位于所述列表中,则将列 originator_prediction 更新为“org”。

有没有更好的方法来做到这一点?我是按以下方式完成的,但速度很慢。

for row in df['ORIGINATOR'][1:]:
    string = str(row)
    splits = string.split()
    for word in splits:
        if word in COMMON_ORG_UNIGRAMS_LIST:
            df['ORGINATOR_PREDICTION'] = 'Org'
        else:
            continue

df  = pd.DataFrame({'ORIGINATOR':  ['JOHN DOE', 'APPLE INC', 'MIKE LOWRY'],
        'ORGINATOR_PREDICTION': ['Person', 'Person','Person']})

COMMON_ORG_UNIGRAMS_LIST = ['INC','LLC','LP']

具体来说,如果您查看我们的数据框“APPLE INC”中的第 2 行,应该有一个 originator_prediction = 'ORG' 而不是 person。

原因是,我们遍历了我们常见的 org unigrams 列表,其中 INC 一词。

【问题讨论】:

  • 我会说是的,你能发布一些示例数据和预期输出吗?
  • Scott 在问题中添加了更多信息

标签: python pandas nested-loops


【解决方案1】:

试试这个,使用.str,字符串访问器和contains方法。我们可以使用join 为字符串列表创建一个正则表达式:

df.loc[df['ORIGINATOR'].str.contains('|'.join(COMMON_ORG_UNIGRAMS_LIST)), 'ORGINATOR_PREDICTION'] = 'Org'

输出:

   ORIGINATOR ORGINATOR_PREDICTION
0    JOHN DOE               Person
1   APPLE INC                  Org
2  MIKE LOWRY               Person

完整代码:

df  = pd.DataFrame({'ORIGINATOR':  ['JOHN DOE', 'APPLE INC', 'MIKE LOWRY'],
        'ORGINATOR_PREDICTION': ['Person', 'Person','Person']})

COMMON_ORG_UNIGRAMS_LIST = ['INC','LLC','LP']

df.loc[df['ORIGINATOR'].str.contains('|'.join(COMMON_ORG_UNIGRAMS_LIST)),'ORGINATOR_PREDICTION'] = 'Org'

print(df)

【讨论】:

  • 收到以下错误:Series 的对象是可变的,因此它们不能被散列
  • 呃.. COMMON_ORN_UNIGRAMS_LIST 是一个系列吗?
  • COMMON_ORG_UNIGRAMS_LIST 是一个列表 - df['ORIGINATOR'] 是一个对象
  • 是的,我在操作完成之前内存不足。
【解决方案2】:

您的代码不会给出正确的结果,因为在每次检查之后,使用df['ORGINATOR_PREDICTION'] = 'Org',您正在为该列中的所有行分配该值。这将导致该列中的所有行都具有值Org。另外,我不明白您为什么在循环中添加了[1:]。如果这是您试图避免的,它不会选择列名。我已经对您的代码进行了一些更改,它可以正常工作

org_or_person_list = []
for row in df['ORIGINATOR']:
    splits = row.split()
    org_or_person_list.append('Org' if set(splits) & set(COMMON_ORG_UNIGRAMS_LIST) else 'Person')

df['ORGINATOR_PREDICTION'] = org_or_person_list

输出:

    ORIGINATOR  ORGINATOR_PREDICTION
0   JOHN DOE    Person
1   APPLE INC   Org
2   MIKE LOWRY  Person

【讨论】:

  • 谢谢你修改我原来的代码,有没有更高效的写法?运行需要很长时间。我有大约 800k 行的上下文。
  • 我已经编辑过了。现在效率更高了。另外,我已经删除了string = str(row),因为每一行已经是一个字符串,但是如果其他行的数据类型不同,您可以将其添加回来
  • 虽然我认为这行得通,而且效率更高,但我认为我需要回到绘图板并弄清楚如何通过 800k 行运行它。它永远不会结束......我将尝试将字符串拆分一段时间并创建一个包含所有字符串拆分的列。也许使用一些 numpy 数组来加快进程..
  • 如果您能提供数据,我可以提供帮助。我可以给出的提示是,如果 org unigrams(INC、LLP 等)始终位于末尾,那么您只需阅读 splits 的最后一个单词并丢弃其余单词。
  • @mikelowry 你好。我已经进一步编辑了我的代码。对每一行数据帧的重复分配是一个耗时的过程。我将结果附加到列表中,并一次性将其分配给列。 (我没有使用我之前评论中的splits 建议。)
【解决方案3】:

替代解决方案:

df  = pd.DataFrame({
    'ORIGINATOR':  ['JOHN DOE', 'APPLE INC', 'MIKE LOWRY'],
    'ORIGINATOR_PREDICTION': ['Person', 'Person','Person']
})

COMMON_ORG_UNIGRAMS_LIST = ['INC','LLC','LP']

df.loc[df['ORIGINATOR'].apply(lambda x: len(set(x.split(' ')) & set(COMMON_ORG_UNIGRAMS_LIST)) > 0), 'ORIGINATOR_PREDICTION'] = 'Org'
    

【讨论】:

  • 得到一个 IndexingError:Name: ORIGINATOR, Length: 7601, dtype: bool, 'ORIGINATOR_PREDICTION')
猜你喜欢
  • 2017-11-11
  • 1970-01-01
  • 1970-01-01
  • 2019-11-23
  • 2019-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-01
相关资源
最近更新 更多