pandas 传入lambda以应用panda DataFrame时出错

qxsslcnc  于 2023-03-11  发布在  其他
关注(0)|答案(2)|浏览(277)

我尝试将一个函数应用于PandasDataFrame的所有行(实际上只是该DataFrame中的一列)
我肯定这是语法错误,但我知道我做错了什么

df['col'].apply(lambda x, y:(x - y).total_seconds(), args=[d1], axis=1)

col列包含了一堆datetime.datetime对象,d1是其中最早的一个,我试图得到每一行的总秒数。
我不断收到以下错误

TypeError: <lambda>() got an unexpected keyword argument 'axis'

我不明白为什么axis会被传递给lambda函数
我也试过

def diff_dates(d1, d2):
    return (d1-d2).total_seconds()

df['col'].apply(diff_dates, args=[d1], axis=1)

我得到了同样的错误。

8zzbczxx

8zzbczxx1#

注意**Series.apply调用**没有axis参数,这与DataFrame.apply调用不同。
序列.apply(函数,转换数据类型=真,参数=(),**kwds)

func : function
convert_dtype : boolean, default True
Try to find better dtype for elementwise function results. If False, leave as dtype=object
args : tuple
Positional arguments to pass to function in addition to the value

有一个用于df的函数,但是不清楚当你在一个序列上调用它,但是你期望它在一行上工作时,你期望它如何工作?

t1rydlwq

t1rydlwq2#

一个单列(通常)是一个Pandas系列,正如EdChum提到的,DataFrame.applyaxis参数,但Series.apply没有,所以axis=1上的apply对列不起作用。
以下作品:

df['col'].apply(lambda x, y: (x - y).total_seconds(), args=(d1,))

为了对行中的每个元素应用函数,也可以使用map

df['col'].map(lambda x: (x - d1).total_seconds())

由于apply只是Python循环的语法糖,列表解析可能比这两种方法都更有效,因为它没有Pandas开销:

[(x - d1).total_seconds() for x in df['col'].tolist()]

对于单列 Dataframe ,可以传递axis=1

df[['col']].apply(lambda x, y: (x - y).dt.total_seconds(), args=[d1], axis=1)
PSA:尽可能避免apply

apply在 * 大多数情况下 * 甚至不需要。对于OP中的情况(以及大多数其他情况),存在矢量化操作(只需从列中减去d1-值被广播以匹配列),并且无论如何都比apply快得多:

(df['col'] - d1).dt.total_seconds()
计时

对于10 k行的帧,向量化减法在一列上比apply快大约150倍,在单列DataFrame上比apply快7000倍以上。由于apply是一个循环,因此随着行数的增加,这个差距会变大。

df = pd.DataFrame({'col': pd.date_range('2000', '2023', 10_000)})
d1 = df['col'].min()

%timeit df['col'].apply(lambda x, y: (x - y).total_seconds(), args=[d1])
# 124 ms ± 7.57 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit df['col'].map(lambda x: (x - d1).total_seconds())
# 127 ms ± 16.8 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit [(x - d1).total_seconds() for x in df['col'].tolist()]
# 107 ms ± 4.14 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit (df['col'] - d1).dt.total_seconds()
# 851 µs ± 189 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

%timeit df[['col']].apply(lambda x, y: (x - y).dt.total_seconds(), args=[d1], axis=1)
# 6.07 s ± 419 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

相关问题