首页 > 解决方案 > 如果条件不满足,为什么带有条件的 np.where 不能仅处理数据框中的一行

问题描述

这是一个例子:

cars2 = {'Brand': ['Hon*da\nCivic', 'BM*AMT*B6*W'],'Price': [22000, 55000]}

df2 = pd.DataFrame(cars2, columns = ['Brand', 'Price'])


df2['Allowed_Amount'] = np.where(
                df2['Brand'].apply(lambda x: x.count("AMT" + "*" + "B6") > 0),
                df2['Brand'].str.split("AMT" + "*").str[1].str.split("B6").str[1].str[1:].str.split('\n').str[0], 0.00)

输出:

           Brand  Price Allowed_Amount
0  Hon*da\nCivic  22000              0
1    BM*AMT*B6*W  55000              W

这正是我需要的。

但是,如果 df 仅包含不满足条件的一行,则会出现错误:

cars = {'Brand': ['Hon*da\nCivic'],'Price': [22000]}

df = pd.DataFrame(cars, columns = ['Brand', 'Price'])

df['Allowed_Amount'] = np.where(
                    df['Brand'].apply(lambda x: x.count("AMT" + "*" + "B6") > 0),
                    df['Brand'].str.split("AMT" + "*").str[1].str.split("B6").str[1].str[1:].str.split('\n').str[0], 0.00)

输出:

AttributeError: Can only use .str accessor with string values!

我需要的:

           Brand  Price Allowed_Amount
0  Hon*da\nCivic  22000              0

为什么不满足条件不退出?如何使此代码也适用于一行?

标签: pythonpandasnumpyparsingsplit

解决方案


您的代码的问题是df['Brand'].str.split("AMT" + " ")* 在“负”情况下返回大小为1的列表(单个元素中的整个源字符串 )。

在这种情况下.str[1](按照前面的代码)返回None并且您的代码中的“以下”方法不能在它上面调用。

但是在Pandas中,只有在每个源元素都发生上述情况时才会引发实际异常,就像df的情况一样。

我还认为这么长的str.splitstr和 index 选择序列很难阅读。

尝试另一种基于使用正则表达式提取的方法:

df['Allowed_Amount'] = df['Brand'].str.extract(r'AMT\*.*?B6.(.*)').fillna(0)

正则表达式的详细信息:

  • AMT\*- 匹配AMT和星号。
  • .*?- 尽可能少地匹配任意数量的字符(“AMT*”和“B6”之间的字符,如果有的话)。也许你可以从正则表达式中删除这个片段。
  • B6- 代表自己。
  • .- 匹配任何单个字符([1:]代码中的对应字符)。
  • (.*)- 将文本匹配到换行符(不包括,因为点与换行符不匹配)或字符串的末尾,作为捕获组,所以这只是提取的内容。

如果上述正则表达式不匹配,则为该行返回NaN 。

然后这些NaN值被替换为0,因为之后调用了fillna(0)

在df2上尝试相同的操作。

因此,通过这种方式,您将使用更短且更具可读性的代码来实现您想要的结果。

当然,它需要一些正则表达式的知识,但绝对值得花一些时间来学习它们。

按照问题编辑

要使用给定的分隔符替换正则表达式中的文字星号,您可以定义以下函数,为新列生成内容:

def myExtract(df, delimiter='*'):
    pat = rf'AMT\{delimiter}B6.(.*)'
    return df['Brand'].str.extract(pat).fillna(0)

如你看到的:

  • 使用f-string功能将分隔符合并到正则表达式中(可以与r-string 共存),
  • 它必须以反斜杠开头,以按字面意思对待它 (而不是特殊的正则表达式字符)。

要生成新的列,只需调用此函数,至少传递源 DataFrame(以及可选的右分隔符):

df['Allowed_Amount'] = myExtract(df); df

df2也是如此。


推荐阅读