我正在阅读一个巨大的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))
不过,此功能非常慢。
有什么改进建议吗?
注意:正如@ritchie46的答案所述,此解决方案可能是多余的,因为根据默认为True
的新参数cache_dates
pandas 版本 0.25
尝试使用此函数解析日期:
def lookup(date_pd_series, format=None):
"""
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, format=format) for date in date_pd_series.unique()}
return date_pd_series.map(dates)
像这样使用它:
df['date-column'] = lookup(df['date-column'], format='%Y%m%d')
基准:
$ 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
> @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.
除非你坚持使用一个非常旧的熊猫版本,0.25之前,否则这个答案不适合你。
此处描述的功能已在 0.25 版中合并到 pandas 中
通过缓存简化日期解析
读取所有数据然后转换数据总是比在读取 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的答案具有相同的优势,只需解析每个字符串一次,额外的好处是不必读取所有数据然后解析它。节省您的内存和处理时间。
从 pandas 版本 0.25 开始,函数pandas.read_csv
接受 cache_dates=boolean
(默认为 True
) 关键字参数。因此,无需像在接受的答案中那样编写自己的缓存函数。
无需指定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
尝试标准库:
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只需要被带入一次性能更好的格式,你要么不应该关心转换过程的速度(因为它只发生一次),要么你应该带上任何产生CSV的东西给你更好的数据 - 有很多格式不依赖于字符串解析。
如果您的日期时间具有 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"])
我有一个 ~150k 行的 csv。在尝试了这篇文章中的几乎所有建议后,我发现以下方法提高了 25%:
- 使用 Python3.7 本机
csv.reader
逐行读取文件 - 使用
float()
和 转换所有 4 个数字列 - 使用
datetime.datetime.fromisoformat()
解析日期列
看哪:
- 最后将列表转换为数据帧 (!**
让我感到困惑,这怎么能比本地大熊猫更快pd.read_csv(......有人可以解释一下吗?