Try:
df['downum'] = df['date'].apply(downu)
并将 downu 更改为:
def downu(dtime):
d = dtime.day # use dtime.day rather than dtime.dt.day
x = np.ceil(d/7)
return int(x) # cast to int since d/7 is float even after np.ceil()
df.apply() 适用于整个 df,即依次(按列)所有列。每个处理列Series的索引仍然是DataFrame索引。因此,列标签“日期”不能用作正在处理的中间系列的索引。您必须在“日期”系列上使用 apply() ,除非您的 downu() 函数可以接受所有列的值并忽略不相关的列。
Edit:
使用添加替代解决方案apply(... ,axis=1)
and list(map(...))
这里有进一步的解决方案,其中一些我认为是OP最初尝试的目标编码方式。我还将讨论它们在大型数据集的系统性能(执行时间)以及程序可读性(清晰度)方面的优缺点。
替代解决方案 1:
%%timeit
df['downum'] = df.apply(lambda x: downu(x['date']), axis=1)
988 µs ± 8.26 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
替代解决方案 2:
%%timeit
df['downum'] = df.apply(lambda x: downu(x.date), axis=1)
1.01 ms ± 13.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
替代解决方案 3:
%%timeit
df['downum'] = list(map(downu, df['date']))
244 µs ± 3.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
原解决方案:
%%timeit
df['downum'] = df['date'].apply(downu)
810 µs ± 484 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
替代解决方案 1 和 2 应该是 OP 最初尝试的目标编码格式。唯一的区别是axis=1
添加以使它们可行。现在,与axis=1
添加到DataFrame.apply()
功能,downu(x['date']
and downu(x.date)
可以在 lambda 函数中使用。有效地,axis=1
改变行为DataFrame.apply()
函数允许使用列索引名称。通过认为 apply() 内部的函数是通过 Series 对象按行传递,可以更好地理解这一点。 Series 对象具有原始 DataFrame 列名称/索引,现在成为 Series 索引。因此,您可以按照与访问 Series 元素相同的方式来访问这些元素,方法是按照 series_obj['index'] 等格式进行编码。
解决方案比较:
比较原始解决方案的执行时间(使用pandas.Series.apply()
)与 2 个替代解决方案使用pandas.DataFrame.apply(... ,axis=1)
,原来的解决方案还是快了一点。在程序可读性方面,原始解决方案的工作原理是df['date']
pandas 系列被认为简单且更好。
考虑到系统性能,替代方案3使用list(map(...))
is 速度提高 3 倍 ~ 4 倍比所有其他解决方案。请注意,此性能比较结果为DataFrame.apply(..., axis=1)
vs list(map(..))
是通用的而不是特定于这个问题的。你可以参考这个answer https://stackoverflow.com/a/46923192/15070697帖子的如何将函数应用于 Pandas 数据框的两列 https://stackoverflow.com/q/13331698/15070697以便对该主题进行更深入的讨论。同一篇文章的一些其他答案对于更好地理解 apply() 函数也非常有用。
综上所述,如果数据集不大且系统性能不是主要考虑因素,请使用原始解决方案pandas.Series.apply()
有利于程序的可读性和清晰度。否则,出于系统性能考虑,使用list(map(...))
远远优于pandas.DataFrame.apply(... ,axis=1)
方法。