我正在阅读一个巨大的CSV
,其中的日期字段格式为YYYYMMDD
,我在阅读时使用以下lambda进行转换:
import pandas as pd
df = pd.read_csv(filen,
index_col=None,
header=None,
parse_dates=[0],
date_parser=lambda t:pd.to_datetime(str(t),
format='%Y%m%d', coerce=True))
这个功能很慢。
有任何改善建议吗?
答案 0 :(得分:58)
尝试使用此函数解析日期:
def lookup(s):
"""
This is an extremely fast approach to datetime parsing.
For large data, the same dates are often repeated. Rather than
re-parse these, we store all unique dates, parse them, and
use a lookup to convert all dates.
"""
dates = {date:pd.to_datetime(date) for date in s.unique()}
return s.map(dates)
使用它像:
df['date-column'] = lookup(df['date-column'])
基准:
$ python date-parse.py
to_datetime: 5799 ms
dateutil: 5162 ms
strptime: 1651 ms
manual: 242 ms
lookup: 32 ms
来源:https://github.com/sanand0/benchmarks/tree/master/date-parse
答案 1 :(得分:6)
很棒的建议@EdChum!正如@EdChum建议的那样,使用infer_datetime_format=True
可以显着更快。以下是我的例子。
我有一个来自传感器日志的温度数据文件,如下所示:
RecNum,Date,LocationID,Unused 1,11/7/2013 20:53:01,13.60,"117","1", 2,11/7/2013 21:08:01,13.60,"117","1", 3,11/7/2013 21:23:01,13.60,"117","1", 4,11/7/2013 21:38:01,13.60,"117","1", ...
我的代码读取csv并解析日期(parse_dates=['Date']
)。
使用infer_datetime_format=False
,需要 8分8秒:
Tue Jan 24 12:18:27 2017 - Loading the Temperature data file. Tue Jan 24 12:18:27 2017 - Temperature file is 88.172 MB. Tue Jan 24 12:18:27 2017 - Loading into memory. Please be patient. Tue Jan 24 12:26:35 2017 - Success: loaded 2,169,903 records.
使用infer_datetime_format=True
,需要 13秒:
Tue Jan 24 13:19:58 2017 - Loading the Temperature data file. Tue Jan 24 13:19:58 2017 - Temperature file is 88.172 MB. Tue Jan 24 13:19:58 2017 - Loading into memory. Please be patient. Tue Jan 24 13:20:11 2017 - Success: loaded 2,169,903 records.
答案 2 :(得分:5)
读取所有数据然后转换它总是比读取CSV时转换慢。如果您立即执行此操作,则不需要对所有数据进行两次迭代。您也不必将其作为字符串存储在内存中。
我们可以定义我们自己的日期解析器,它使用缓存来查看已经看过的日期。
import pandas as pd
cache = {}
def cached_date_parser(s):
if s in cache:
return cache[s]
dt = pd.to_datetime(s, format='%Y%m%d', coerce=True)
cache[s] = dt
return dt
df = pd.read_csv(filen,
index_col=None,
header=None,
parse_dates=[0],
date_parser=cached_date_parser)
具有与@fixxxer相同的优点,只需解析每个字符串一次,额外增加的好处就是不必读取所有数据,然后解析它。节省您的记忆和处理时间。
答案 3 :(得分:2)
试用标准库:
import datetime
parser = lambda t: datetime.datetime.strptime(str(t), "%Y%m%d")
然而,我真的不知道这是否比熊猫快得多。
由于你的格式很简单,那么
呢def parse(t):
string_ = str(t)
return datetime.date(int(string_[:4]), int(string[4:6]), int(string[6:]))
编辑您说您需要处理无效数据。
def parse(t):
string_ = str(t)
try:
return datetime.date(int(string_[:4]), int(string[4:6]), int(string[6:]))
except:
return default_datetime #you should define that somewhere else
总而言之,我对您的问题的有效性有点矛盾:
那种矛盾;我个人的做法是假设你的"巨大的" CSV只需要进行一次性能更好的格式,你或者不应该关心转换过程的速度(因为它只发生一次),或者你应该带来任何产生CSV的东西来为你提供更好的数据 - 这么多格式不依赖于字符串解析。
答案 4 :(得分:2)
自pandas version 0.25起,函数pandas.read_csv
接受一个cache_dates=boolean
(默认为True
)关键字参数。因此,无需像接受的答案那样编写自己的缓存功能。
答案 5 :(得分:1)
无需指定date_parser
,pandas能够毫无困难地解析它,而且速度会快得多:
In [21]:
import io
import pandas as pd
t="""date,val
20120608,12321
20130608,12321
20140308,12321"""
df = pd.read_csv(io.StringIO(t), parse_dates=[0])
df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 3 entries, 0 to 2
Data columns (total 2 columns):
date 3 non-null datetime64[ns]
val 3 non-null int64
dtypes: datetime64[ns](1), int64(1)
memory usage: 72.0 bytes
In [22]:
df
Out[22]:
date val
0 2012-06-08 12321
1 2013-06-08 12321
2 2014-03-08 12321
答案 6 :(得分:1)
如果你的日期时间有UTC时间戳,你只需要它的一部分。将其转换为字符串,切片所需,然后应用以下内容以便更快地访问。
created_at
2018-01-31 15:15:08 UTC
2018-01-31 15:16:02 UTC
2018-01-31 15:27:10 UTC
2018-02-01 07:05:55 UTC
2018-02-01 08:50:14 UTC
df["date"]= df["created_at"].apply(lambda x: str(x)[:10])
df["date"] = pd.to_datetime(df["date"])
答案 7 :(得分:0)
我有一个约有15万行的csv。尝试了这篇文章中的几乎所有建议之后,我发现可以快25%:
csv.reader
逐行读取文件float()
和datetime.datetime.fromisoformat()
注意:
这让我感到困惑,怎么会比本地大熊猫pd.read_csv(...)...更快呢?