【问题标题】:DataFrame.apply() error: "<Series> is not a valid function for 'Series' object"DataFrame.apply() 错误:“<Series> 不是 'Series' 对象的有效函数”
【发布时间】:2020-04-25 02:55:48
【问题描述】:

我从 pandas.DataFrame.apply() 得到一个 AttributeError。尽管如此,该功能似乎可以工作,但我想更好地理解 apply() ,所以我还是发布了这个问题......

我有两个数据框,如下所示:

a = pd.DataFrame(data = {
    'ID': ['123', '456', '789'],
    'TIME': [1.5, 2, 3]
})

b = pd.DataFrame(data = {
    'ID': ['123', '456', '789'] * 2,
    'TIME_START': [1, 3, 3, 2, 1, 5],
    'TIME_END': [5, 4, 6, 6, 3, 6],
    'CORR_KEY': ['abc', 'def', 'ghi', 'jkl', 'mno', 'pqr']
})

我像这样合并它们:

c = a.merge(b, how = 'inner', on = 'ID')

我得到以下信息:

print(c)

    ID  TIME  TIME_START  TIME_END CORR_KEY
0  123   1.5           1         5      abc
1  123   1.5           2         6      jkl
2  456   2.0           3         4      def
3  456   2.0           1         3      mno
4  789   3.0           3         6      ghi
5  789   3.0           5         6      pqr

现在我需要在 TIME_START TIME TIME_END 为 FALSE 的 c 中删除记录。这样,我最终只得到了具有相关 CORR_KEY 的记录。 (例如,ID 123 的正确 CORR_KEY 是 abc,而不是 jkl。)

我使用以下函数,并沿数据框应用它:

def drop_records(df):
    start_condition = df['TIME_START'] <= df['TIME']
    end_condition = df['TIME'] <= df['TIME_END']

    df.drop(df[~(start_condition) | ~(end_condition)].index, inplace = True)

    return df

c = c.apply(drop_records(c))

结果是:

AttributeError: 'ID' 不是 'Series' 对象的有效函数

但是,再次检查 c,我得到了预期的输出:

print(c)

    ID  TIME  TIME_START  TIME_END CORR_KEY
0  123   1.5           1         5      abc
3  456   2.0           1         3      mno
4  789   3.0           3         6      ghi

那么,导致 AttributeError 的原因是什么?

谢谢!

【问题讨论】:

    标签: python pandas dataframe apply


    【解决方案1】:

    您过度使用了解决方案。您可以使用query 直接获取您的输出:

    c = c.query('TIME_START <= TIME <= TIME_END')
    
    print(c)
        ID  TIME  TIME_START  TIME_END CORR_KEY
    0  123   1.5           1         5      abc
    3  456   2.0           1         3      mno
    4  789   3.0           3         6      ghi
    

    【讨论】:

    • 哇,我没有意识到这个方法的存在。在其他情况下,这也会为我节省很多时间!谢谢。
    【解决方案2】:

    当您执行apply 时,数据框按系列划分,每列一个,并且该功能应用于系列。由于ID 只是第一列,apply 正在尝试执行drop_records(c),但向他们发送ID 系列,这将导致AttributeError

    您不需要在这里apply 一个函数,只需:

    c = drop_records(c)
    

    或者使用布尔掩码:

    mask = (c.TIME_START <= c.TIME) & (c.TIME <= c.TIME_END)
    c = c[mask]
    

    甚至可以按照@Sandeep Kadapa 的建议进行查询。

    【讨论】:

    • 感谢其他建议,我肯定需要重构我的代码。虽然仍然对 apply() 感到有些困惑 - 如果我真正做的是一次输入一个系列,为什么 c 会按预期改变?
    • 因为drop_records(c)实际上是返回信息,所以它分配给c失败的是c试图发送ID系列作为函数的参数。实际上,您正试图将一个系列提供给一个不需要任何参数的函数。
    • 哦,好的,我明白了。 drop_records 中的 inplace 参数对 c 进行了更改,然后 c 被传递到抛出 AttributeErrorapply 方法中。那讲得通。我还想到 inplace 参数在这里是多余的。我只是出于习惯设置它。
    • 我接受了这个答案,因为这些 cmets 解决了我的实际问题。我确实在我的代码中使用了query 方法。
    猜你喜欢
    • 1970-01-01
    • 2016-03-15
    • 1970-01-01
    • 2018-02-05
    • 1970-01-01
    • 2021-11-03
    • 2023-02-04
    • 2019-11-03
    • 2015-07-25
    相关资源
    最近更新 更多