【问题标题】:How to create new column based on substrings in other column in a pandas dataframe?如何根据熊猫数据框中其他列中的子字符串创建新列?
【发布时间】:2021-11-23 19:10:01
【问题描述】:

我有一个如下结构的数据框:

df = pd.DataFrame({
    'Substance': ['(NPK) 20/10/6', '(NPK) Guayacan 10/20/30', '46%N / O%P2O5 (Urea)', '46%N / O%P2O5 (Urea)', '(NPK) DAP Diammonphosphat; 18/46/0'],
    'value': [0.2, 0.4, 0.6, 0.8, .9]
})

    substance               value
0   (NPK) 20/10/6           0.2
1   (NPK) Guayacan 10/20/30 0.4
2   46%N / O%P2O5 (Urea)    0.6
3   46%N / O%P2O5 (Urea)    0.8
4   (NPK) DAP Diammonphosphat; 18/46/0          0.9

现在我想用物质的简称创建一个新列:

test['Short Name'] = test['Substance'].apply(lambda x: 'Urea' if 
                                         any(i in x for i in 'Urea') else '(NPK)')

最后一行代码有两个问题。首先,输出是这样的:

    Substance               value   Short Name
0   (NPK) 20/10/6           0.2     (NPK)
1   (NPK) Guayacan 10/20/30 0.4     Urea
2   46%N / O%P2O5 (Urea)    0.6     Urea
3   46%N / O%P2O5 (Urea)    0.8     Urea
4   (NPK) DAP Diammonphosphat; 18/46/0          0.9     (NPK)

所以第二个条目也标有尿素,虽然它应该是 NPK。

此外,我的实际数据也会产生以下错误,尽管使用了原始物质名称,但有趣/令人讨厌的是,我无法用虚拟数据重现该错误。

/var/folders/tf/hzv31v4x42q4_mnw4n8ldhsm0000gn/T/ipykernel_10743/136042259.py:5: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

注意:由于我还有更多内容,我将不得不在 if/else 循环中添加更多语句。

编辑: 物质名称需要映射到以下短名称列表:

  • 尿素如果物质包括尿素
  • 硝酸铵钙 (CAN) 如果 物质 包括 CAN
  • 磷酸二铵 (DAP),如果 物质 包括 DAP
  • 其他复合 NK、NPK 肥料适用于所有其他情况

样本数据的预期输出为

    Substance               value   Short Name
0   (NPK) 20/10/6           0.2     (NPK)
1   (NPK) Guayacan 10/20/30 0.4     (NPK)
2   46%N / O%P2O5 (Urea)    0.6     Urea
3   46%N / O%P2O5 (Urea)    0.8     Urea
4   (NPK) DAP Diammonphosphat; 18/46/0          0.9     (NPK)

编辑2: 然后我想添加一条语句,以便我收到以下输出:

    Substance               value   Short Name
0   (NPK) 20/10/6           0.2     (NPK)
1   (NPK) Guayacan 10/20/30 0.4     (NPK)
2   46%N / O%P2O5 (Urea)    0.6     Urea
3   46%N / O%P2O5 (Urea)    0.8     Urea
4   (NPK) DAP Diammonphosphat; 18/46/0          0.9     DAP

【问题讨论】:

  • 请根据您的示例数据框编辑问题以包含预期的输出。也请清楚说明Short Name的逻辑。

标签: python pandas dataframe


【解决方案1】:

试试这个:

df['Short Name'] = df['Substance'].str.extract(r'\((.+?)\)')

输出:

>>> df
                 Substance  value Short Name
0            (NPK) 20/10/6    0.2        NPK
1  (NPK) Guayacan 10/20/30    0.4        NPK
2     46%N / O%P2O5 (Urea)    0.6       Urea
3     46%N / O%P2O5 (Urea)    0.8       Urea
4            (NPK) 20/10/6    0.9        NPK

【讨论】:

  • 这确实是一个超级简洁的解决方案,但不幸的是我的物质名称有点混乱,而且短名称并不总是包含在 ( ) 中
  • 那么请显示更多您的数据。 :)
【解决方案2】:

 为我工作:

df['Short Name'] = df['Substance'].apply(lambda x: 'Urea' if 'Urea' in x else '(NPK)')
>>> df
                 Substance  value   Short Name
0            (NPK) 20/10/6    0.2        (NPK)
1  (NPK) Guayacan 10/20/30    0.4        (NPK)
2     46%N / O%P2O5 (Urea)    0.6         Urea
3     46%N / O%P2O5 (Urea)    0.8         Urea
4            (NPK) 20/10/6    0.9        (NPK)

正则表达式:

import re
short = re.compile(r"\W*(urea)\W*", re.I)
df['Short Name'] = df['Substance'].apply(lambda x: 'Urea' if len(short.findall(x.lower())) else '(NPK)')

【讨论】:

  • 出于好奇:您能否也包含这样的正则表达式?
  • 您可以尝试定义这种模式:short = re.compile(r"\W*(urea)\W*", re.I) 并将上面的语句替换为:df['Short Name'] = df['Substance'].apply(lambda x: 'Urea' if len(short.findall(x.lower())) else '(NPK)')
  • 适用于这两种情况。有什么建议可以将其与我实际需要的 4 个案例联系起来吗?
  • 我建议,如果您有不止一种物质,您可以将它们存储在这样的列表中:short_substances = [Urea, NPK, Subs1, Subs2],然后调用搜索正则表达式 apply(lambda x: substance [pattern.findall(x.lower()) for substance in short_substances] 遍历此列表,但为此您会必须将列表short_substances 的每次迭代的变量传递给模式,通过这种方式:rx = r'\b(?<=\w){0}\b(?!\w)'.format(short_substance)
  • 困难在于我真的需要默认情况下的else case。只有三个物质名称可以轻松匹配,其他一切都需要进行'NPK'。我能想到的最好的是test['Short Name'] = test['Substance'].apply(lambda x: 'Urea' if 'Urea' in x else 'DAP' if 'DAP' in x else '(NPK)')
【解决方案3】:

不是最简洁的解决方案,但至少是一个解决方案:

test['Short Name'] = test['Substance'].apply(lambda x: 'Urea' if 'Urea' in x else 'DAP' if 'DAP' in x else '(NPK)')

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-24
    • 1970-01-01
    • 2023-01-07
    • 2021-08-01
    • 1970-01-01
    • 2019-07-25
    相关资源
    最近更新 更多