And*_*son 2 python datetime dataframe pandas
所以我有以下代码读取 5 列,日期 ohlc。然后它创建一个列“dow”来保存星期几。到现在为止还挺好:
import numpy as np
import pandas as pd
df = pd.read_csv('/content/drive/MyDrive/Forex/EURUSD-2018_12_18-2020_11_01.csv',parse_dates=True,names = ['date','1','2','3','4',])
df['date'] = pd.to_datetime(df['date'])
df.index = df['date']
df['dow'] = df['date'].dt.dayofweek
#df['downum'] = df.apply(lambda x: downu(x['date']))
df
Run Code Online (Sandbox Code Playgroud)
产生以下输出:
date 1 2 3 4 dow
date
2018-12-18 00:00:00 2018-12-18 00:00:00 1.13498 1.13497 1.13508 1.13494 1
2018-12-18 00:01:00 2018-12-18 00:01:00 1.13497 1.13500 1.13500 1.13496 1
2018-12-18 00:02:00 2018-12-18 00:02:00 1.13500 1.13498 1.13502 1.13495 1
2018-12-18 00:03:00 2018-12-18 00:03:00 1.13498 1.13513 1.13513 1.13498 1
2018-12-18 00:04:00 2018-12-18 00:04:00 1.13513 1.13511 1.13515 1.13511 1
... ... ... ... ... ... ...
2020-11-01 23:55:00 2020-11-01 23:55:00 1.16402 1.16408 1.16410 1.16401 6
2020-11-01 23:56:00 2020-11-01 23:56:00 1.16409 1.16408 1.16410 1.16405 6
2020-11-01 23:57:00 2020-11-01 23:57:00 1.16409 1.16417 1.16418 1.16408 6
2020-11-01 23:58:00 2020-11-01 23:58:00 1.16417 1.16416 1.16418 1.16414 6
2020-11-01 23:59:00 2020-11-01 23:59:00 1.16418 1.16419 1.16419 1.16413 6
Run Code Online (Sandbox Code Playgroud)
现在我想添加以下自定义函数:
def downu(dtime):
d = dtime.dt.day
x = np.ceil(d/7)
return x
Run Code Online (Sandbox Code Playgroud)
并在显示数据框之前调用它,如下所示:
df['downum'] = df.apply(lambda x: downu(x['date']))
Run Code Online (Sandbox Code Playgroud)
添加一列指示第一个 '1',第二个 '2'.... 第五个 '5' xxxday
但是,这会产生以下错误:
---------------------------------------------------------------------------
ParserError Traceback (most recent call last)
pandas/_libs/tslibs/conversion.pyx in pandas._libs.tslibs.conversion._convert_str_to_tsobject()
pandas/_libs/tslibs/parsing.pyx in pandas._libs.tslibs.parsing.parse_datetime_string()
/usr/local/lib/python3.6/dist-packages/dateutil/parser/_parser.py in parse(timestr, parserinfo, **kwargs)
1373 else:
-> 1374 return DEFAULTPARSER.parse(timestr, **kwargs)
1375
11 frames
ParserError: Unknown string format: date
During handling of the above exception, another exception occurred:
ValueError Traceback (most recent call last)
pandas/_libs/tslibs/timestamps.pyx in pandas._libs.tslibs.timestamps.Timestamp.__new__()
pandas/_libs/tslibs/conversion.pyx in pandas._libs.tslibs.conversion.convert_to_tsobject()
pandas/_libs/tslibs/conversion.pyx in pandas._libs.tslibs.conversion._convert_str_to_tsobject()
ValueError: could not convert string to Timestamp
The above exception was the direct cause of the following exception:
KeyError Traceback (most recent call last)
/usr/local/lib/python3.6/dist-packages/pandas/core/indexes/datetimes.py in get_loc(self, key, method, tolerance)
603 key = self._maybe_cast_for_get_loc(key)
604 except ValueError as err:
--> 605 raise KeyError(key) from err
606
607 elif isinstance(key, timedelta):
KeyError: 'date'
Run Code Online (Sandbox Code Playgroud)
我在类似情况下看到了以下建议:
df['downum'] = df.apply(lambda x: downu(x.date))
Run Code Online (Sandbox Code Playgroud)
但这会产生以下(可以理解的)错误:
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-33-7f9aa69c7ea7> in <module>()
12 df.index = df['date']
13 df['dow'] = df['date'].dt.dayofweek
---> 14 df['downum'] = df.apply(lambda x: downu(x.date))
15 df
5 frames
/usr/local/lib/python3.6/dist-packages/pandas/core/generic.py in __getattr__(self, name)
5139 if self._info_axis._can_hold_identifiers_and_holds_name(name):
5140 return self[name]
-> 5141 return object.__getattribute__(self, name)
5142
5143 def __setattr__(self, name: str, value) -> None:
AttributeError: 'Series' object has no attribute 'date'
Run Code Online (Sandbox Code Playgroud)
任何解决方案?
尝试:
df['downum'] = df['date'].apply(downu)
Run Code Online (Sandbox Code Playgroud)
并将 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()
Run Code Online (Sandbox Code Playgroud)
df.apply() 适用于整个 df,即所有列依次(逐列)。每个处理列Series的索引仍然是DataFrame索引。因此,列标签“日期”不能用作正在处理的中间系列的索引。您必须在“日期”系列上使用 apply() ,除非您的 downu() 函数可以接受所有列的值并忽略不相关的列。
apply(... ,axis=1)和添加替代解决方案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)
Run Code Online (Sandbox Code Playgroud)
替代解决方案 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)
Run Code Online (Sandbox Code Playgroud)
替代解决方案 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)
Run Code Online (Sandbox Code Playgroud)
原解决方案:
%%timeit
df['downum'] = df['date'].apply(downu)
810 µs ± 484 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Run Code Online (Sandbox Code Playgroud)
替代解决方案 1 和 2 应该是 OP 最初尝试的编码目标格式。唯一的区别是axis=1为了使它们可用而添加的。 现在,withaxis=1添加到DataFrame.apply()函数中,downu(x['date']并且downu(x.date)可以在 lambda 函数中使用。有效地axis=1修改DataFrame.apply()函数的行为以允许使用列索引名称。通过将 apply() 中的函数与 Series 对象一起按行传递,可以更好地理解这一点。Series 对象的原始 DataFrame 列名/索引现在变成了 Series 索引。因此,您可以通过以类似 series_obj['index'] 的格式进行编码,以与访问 Series 元素相同的方式访问这些元素。
将原始解决方案(使用pandas.Series.apply())的执行时间与使用2 个替代解决方案的执行时间进行比较pandas.DataFrame.apply(... ,axis=1),原始解决方案仍然要快一点。在程序可读性方面,在df['date']pandas 系列上工作的原始解决方案被认为是简单和更好的。
考虑到系统的性能,另一种解决方案使用3list(map(...))是 快3个〜4倍倍比所有其他的解决方案。请注意,DataFrame.apply(..., axis=1)vs 的这个性能比较结果list(map(..))是通用的,而不是针对这个问题的。您可以参考这篇文章如何将函数应用于两列 Pandas 数据框的答案,以更深入地讨论该主题。同一篇文章的其他一些答案对于更好地理解 apply() 函数也非常有用。
综上所述,如果数据集不大且系统性能不是主要考虑因素,请使用原始解决方案,pandas.Series.apply()以有利于程序的可读性和清晰度。否则,出于系统性能的考虑,使用list(map(...))远远优于该pandas.DataFrame.apply(... ,axis=1)方法。