【问题标题】:Function with IF and ELIF using pandas使用 pandas 的 IF 和 ELIF 函数
【发布时间】:2019-01-16 00:43:37
【问题描述】:

有什么更好的方法(如果有的话)来定义一个检查 pandas 列是否在给定整数范围内的函数?

我在 Pandas 数据框中有一列,我想检查值是否在设定范围内。我选择通过创建一个函数来执行此操作,该函数接受数据框作为参数并使用 IF 和 ELIF 测试列是否在范围内。 这在范围较小的情况下可能没问题,但是如果范围很大,则生成的 IF、ELIF 函数可能难以维护。有没有更好的方法来实现这一目标?

我的代码有效-

def fn(dframe):
    if dframe['A'] < 125:
        return 935 + 0.2 * dframe['A']

    elif (dframe['A'] >= 955) and (dframe['A'] <= 974):
        return 921.2 + 0.2 * (dframe['A'] - 955)

    elif (dframe['A'] >= 975) and (dframe['A'] <= 1023):
        return 925.2 + 0.2 * (dframe['BCCH'] - 975)

    elif (dframe['A'] >= 511) and (dframe['A'] <= 885):
        return 1805.2 + 0.2 * (dframe['A'] - 512)

此代码按预期工作,但如果范围很大,则生成的函数难以管理。

编辑:

感谢@ycx、@Jorge 和所有人——我喜欢你的代码的可读性。但是想知道@ycx的方法如果我在csv文件中有'condlist'的最小值和最大值 - 例如

condlist_from_CSV_file

然后我可以将其读入数据框。现在,我想检查来自另一个数据帧的“A”列的每一行是否在这些限制之间,如果为真,则返回相应的“选择”,否则返回“无”这有意义吗? 期望的输出 -

output dataframe with check

等等..

【问题讨论】:

  • 第二个 ELIF 中的 dframe['BCCH'] 是错字吗?
  • 不属于任何范围的值会发生什么? (例如,130。)
  • 您的代码应该会失败,因为 if some_series &lt; 125 未定义.. 自己尝试一下.. if pd.Series([1, 2, 3]) &lt; 125: print('hello') 给出(正确)ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all(). 请提供 minimal reproducible example
  • Jorge - 抱歉,是的意思是 dframe['A'] 而不是 dframe['BCCH']
  • NPE - 如果条件都不成立,则返回“无”

标签: python pandas function


【解决方案1】:

看来你需要 np.where

import numpy as np
np.where(dframe['A'] < 125, 935 + 0.2 * dframe['A'],
       np.where(dframe['A'] >= 511) & (dframe['A'] <= 885), 1805.2 + 0.2 * (dframe['A'] - 512,
       np.where(dframe['A'] <= 974, 921.2 + 0.2 * (dframe['A'] - 955),
       np.where(dframe['A'] <= 1023, 925.2 + 0.2 * (dframe['A'] - 975),
    'Value for any other value'))))

【讨论】:

  • 谢谢豪尔赫。如果我必须测试每个值的不仅仅是 4 个范围怎么办?
  • @Ananth i如果您需要更多范围,请添加更多 np.where 条件。只要确保它们井然有序,并且列中的所有值都已涵盖。
  • 谢谢@Jorge。如果我在 csv 文件中有更大的范围,那么我可以读取该文件并使用 np.where 检查我的值是否在该范围内?
  • @Ananth,是的,您只需要使用 pd.read_csv 读取 csv 文件,这将是一个可以应用 np.where 的数据框。
  • 你可以试试: bins = [0, 1, 5, 10, 25, 50, 100] 然后 df.loc[:,'A'] = pd.cut(df['percentage '], bins),但它不会为每个 bin 考虑你的条件,你最终会重新运行类似 np.where 的东西
【解决方案2】:

您可以使用np.select 来管理您的条件和选项。这使您可以轻松维护您的条件和选项,并利用 numpy 库函数,这可能有助于加速您的代码

def fn(dframe):
    import numpy as np
    condlist = [
            dframe['A'] < 125, 
            (dframe['A'] >= 955) and (dframe['A'] <= 974),
            (dframe['A'] >= 975) and (dframe['A'] <= 1023),
            (dframe['A'] >= 511) and (dframe['A'] <= 885),
            ]
    choicelist = [
            935 + 0.2 * dframe['A'],
            921.2 + 0.2 * (dframe['A'] - 955),
            925.2 + 0.2 * (dframe['BCCH'] - 975),
            1805.2 + 0.2 * (dframe['A'] - 512),
            ]
    output = np.select(condlist,choicelist)
    return output

【讨论】:

  • 谢谢@ycx - 1) 我怎样才能将它扩展到超过 4 个范围? 2) np.select 可以从列表中读取值并相应地应用条件吗?
  • @Ananth 不确定你的意思。在这个例子中,np.select 已经接受了一个条件列表和一个选择列表。我认为这回答了您的问题 1 和 2,因为您只需添加到 2 个列表中?您能否进一步详细说明?
  • 谢谢@ycx-我喜欢你的代码的可读性。但是想知道,如果我在 csv 文件中有“condlist”的最小值和最大值 - 例如 Cond_Min Cond_Max Choice 783.5 798.5 -4.02 798.5 813.5 -3.16,那么显然我可以将其读入数据框。现在,我想检查来自另一个数据帧的“A”列的每一行是否在这些限制之间,如果为真,则返回相应的“选择”,否则返回“无”这有意义吗?期望的输出 - 'A' 'Check' 789 -4.02 780 -3.16,等等...
  • @Ananth np.select 有一个 default 参数,您可以在其中传入 None。这意味着如果 condlist 中的条件都不满足,它将输出None,因为它是默认值。所以就像output = np.select(condlist, choicelist, None) np.select 将返回一个numpy.array 对象,它类似于list,您可以直接分配给另一个数据框的列
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-03
  • 2019-07-10
相关资源
最近更新 更多