今天,我对以下事实感到非常惊讶:从数据文件中读取数据(例如)pandas能够识别值的类型:
df = pandas.read_csv('test.dat', delimiter=r"\s+", names=['col1','col2','col3'])
例如,可以用这种方式检查:
for i, r in df.iterrows():
print type(r['col1']), type(r['col2']), type(r['col3'])
特别是整数,浮点数和字符串被正确识别。但是,我有一个列具有以下格式的日期:2013-6-4
。这些日期被识别为字符串(而不是python日期对象)。有没有办法将熊猫“学习”到公认的日期?
答案 0 :(得分:232)
您应该在阅读时添加parse_dates=True
或parse_dates=['column name']
,这通常足以神奇地解析它。但总有奇怪的格式需要手动定义。在这种情况下,您还可以添加日期解析器功能,这是最灵活的方式。
假设您的字符串中有一个“datetime”列,那么:
dateparse = lambda x: pd.datetime.strptime(x, '%Y-%m-%d %H:%M:%S')
df = pd.read_csv(infile, parse_dates=['datetime'], date_parser=dateparse)
这样,您甚至可以将多个列合并到一个日期时间列中,这会将“日期”和“时间”列合并为一个“日期时间”列:
dateparse = lambda x: pd.datetime.strptime(x, '%Y-%m-%d %H:%M:%S')
df = pd.read_csv(infile, parse_dates={'datetime': ['date', 'time']}, date_parser=dateparse)
您可以找到strptime
和strftime
in this page的指令(即用于不同格式的字母)。
答案 1 :(得分:15)
自@Rutger回答以来,pandas界面可能已经改变,但在版本I中使用(0.15.2),date_parser
函数接收日期列表而不是单个值。在这种情况下,他的代码应该像这样更新:
dateparse = lambda dates: [pd.datetime.strptime(d, '%Y-%m-%d %H:%M:%S') for d in dates]
df = pd.read_csv(infile, parse_dates=['datetime'], date_parser=dateparse)
答案 2 :(得分:11)
pandas read_csv方法非常适合解析日期。完整文档http://pandas.pydata.org/pandas-docs/stable/generated/pandas.io.parsers.read_csv.html
您甚至可以在不同的列中使用不同的日期部分并传递参数:
parse_dates : boolean, list of ints or names, list of lists, or dict
If True -> try parsing the index. If [1, 2, 3] -> try parsing columns 1, 2, 3 each as a
separate date column. If [[1, 3]] -> combine columns 1 and 3 and parse as a single date
column. {‘foo’ : [1, 3]} -> parse columns 1, 3 as date and call result ‘foo’
日期的默认感知效果很好,但似乎偏向北美日期格式。如果你住在别处,你可能偶尔会被结果抓住。据我所知,2000年1月6日意味着1月6日在美国,而不是我住的6月1日。如果使用23/6/2000这样的日期,它就足够聪明地摆动它们。尽管如此,保持YYYYMMDD日期变化可能更安全。向熊猫开发者致歉,但我最近没有用本地日期测试它。
您可以使用date_parser参数传递函数来转换格式。
date_parser : function
Function to use for converting a sequence of string columns to an array of datetime
instances. The default uses dateutil.parser.parser to do the conversion.
答案 3 :(得分:8)
将两列合并到一个datetime列时,接受的答案会生成错误(pandas版本0.20.3),因为这些列会分别发送到date_parser函数。
以下作品:
def dateparse(d,t):
dt = d + " " + t
return pd.datetime.strptime(dt, '%d/%m/%Y %H:%M:%S')
df = pd.read_csv(infile, parse_dates={'datetime': ['date', 'time']}, date_parser=dateparse)
答案 4 :(得分:7)
Yes - according to the pandas.read_csv
documentation:
Note: A fast-path exists for iso8601-formatted dates.
So if your csv has a column named datetime
and the dates looks like 2013-01-01T01:01
for example, running this will make pandas (I'm on v0.19.2) pick up the date and time automatically:
df = pd.read_csv('test.csv', parse_dates=['datetime'])
Note that you need to explicitly pass parse_dates
, it doesn't work without.
Verify with:
df.dtypes
You should see the datatype of the column is datetime64[ns]
答案 5 :(得分:6)
您可以按照pandas.to_datetime()
的文档中的建议使用pandas.read_csv()
:
如果列或索引包含不可解析的日期,则整个列 或索引将作为对象数据类型不加改变地返回。对于 非标准日期时间解析,在
pd.to_datetime
之后使用pd.read_csv
。
演示:
>>> D = {'date': '2013-6-4'}
>>> df = pd.DataFrame(D, index=[0])
>>> df
date
0 2013-6-4
>>> df.dtypes
date object
dtype: object
>>> df['date'] = pd.to_datetime(df.date, format='%Y-%m-%d')
>>> df
date
0 2013-06-04
>>> df.dtypes
date datetime64[ns]
dtype: object
答案 6 :(得分:1)
如果性能对您很重要,请确保您有时间:
import sys
import timeit
import pandas as pd
print('Python %s on %s' % (sys.version, sys.platform))
print('Pandas version %s' % pd.__version__)
repeat = 3
numbers = 100
def time(statement, _setup=None):
print (min(
timeit.Timer(statement, setup=_setup or setup).repeat(
repeat, numbers)))
print("Format %m/%d/%y")
setup = """import pandas as pd
import io
data = io.StringIO('''\
ProductCode,Date
''' + '''\
x1,07/29/15
x2,07/29/15
x3,07/29/15
x4,07/30/15
x5,07/29/15
x6,07/29/15
x7,07/29/15
y7,08/05/15
x8,08/05/15
z3,08/05/15
''' * 100)"""
time('pd.read_csv(data); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"]); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"],'
'infer_datetime_format=True); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"],'
'date_parser=lambda x: pd.datetime.strptime(x, "%m/%d/%y")); data.seek(0)')
print("Format %Y-%m-%d %H:%M:%S")
setup = """import pandas as pd
import io
data = io.StringIO('''\
ProductCode,Date
''' + '''\
x1,2016-10-15 00:00:43
x2,2016-10-15 00:00:56
x3,2016-10-15 00:00:56
x4,2016-10-15 00:00:12
x5,2016-10-15 00:00:34
x6,2016-10-15 00:00:55
x7,2016-10-15 00:00:06
y7,2016-10-15 00:00:01
x8,2016-10-15 00:00:00
z3,2016-10-15 00:00:02
''' * 1000)"""
time('pd.read_csv(data); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"]); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"],'
'infer_datetime_format=True); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"],'
'date_parser=lambda x: pd.datetime.strptime(x, "%Y-%m-%d %H:%M:%S")); data.seek(0)')
打印:
Python 3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 03:13:28)
[Clang 6.0 (clang-600.0.57)] on darwin
Pandas version 0.23.4
Format %m/%d/%y
0.19123052499999993
8.20691274
8.143124389
1.2384357139999977
Format %Y-%m-%d %H:%M:%S
0.5238807110000039
0.9202787830000005
0.9832778819999959
12.002349824999996
因此,对于iso8601格式的日期(%Y-%m-%d %H:%M:%S
显然是iso8601格式的日期,我猜T can be dropped并用空格代替),您应该不指定{ {1}}(显然,这与更常见的解析器没有什么区别),并且通过自己的解析器只会降低性能。另一方面,infer_datetime_format
确实与标准日期格式有所不同。像往常一样,请务必先确定时间再优化。
答案 7 :(得分:1)
虽然加载的csv文件包含date列。我们有两种方法来制作熊猫 识别日期列,即
熊猫通过arg date_parser=mydateparser
熊猫通过infer_datetime_format=True
一些日期列数据
01/01/18
18/02/01
在这里我们不知道前两件事,可能是一个月或一天。所以在这种情况下,我们必须使用 方法1: 显式传递格式
mydateparser = lambda x: pd.datetime.strptime(x, "%m/%d/%y")
df = pd.read_csv(file_name, parse_dates=['date_col_name'],
date_parser=mydateparser)
方法2:-隐式或自动识别格式
df = pd.read_csv(file_name, parse_dates=[date_col_name],infer_datetime_format=True)
答案 8 :(得分:0)
除了其他答复所说的那样,如果您必须解析具有成千上万个时间戳的超大文件,date_parser
可能会成为巨大的性能瓶颈,因为它是一个Python函数,每行调用一次。通过在解析CSV文件时将日期保留为文本,然后一次将整个列转换为日期,可以得到可观的性能改进:
# For a data column
df = pd.read_csv(infile, parse_dates={'mydatetime': ['date', 'time']})
df['mydatetime'] = pd.to_datetime(df['mydatetime'], exact=True, cache=True, format='%Y-%m-%d %H:%M:%S')
# For a DateTimeIndex
df = pd.read_csv(infile, parse_dates={'mydatetime': ['date', 'time']}, index_col='mydatetime')
df.index = pd.to_datetime(df.index, exact=True, cache=True, format='%Y-%m-%d %H:%M:%S')
# For a MultiIndex
df = pd.read_csv(infile, parse_dates={'mydatetime': ['date', 'time']}, index_col=['mydatetime', 'num'])
idx_mydatetime = df.index.get_level_values(0)
idx_num = df.index.get_level_values(1)
idx_mydatetime = pd.to_datetime(idx_mydatetime, exact=True, cache=True, format='%Y-%m-%d %H:%M:%S')
df.index = pd.MultiIndex.from_arrays([idx_mydatetime, idx_num])
对于我的有200k行(每行一个时间戳)的文件的用例,它将处理时间从大约一分钟减少到不到一秒。
答案 9 :(得分:0)
您可以将参数 date_parser
与函数一起使用,用于将字符串列的序列转换为日期时间实例的数组:
parser = lambda x: pd.to_datetime(x, format='%Y-%m-%d %H:%M:%S')
pd.read_csv('path', date_parser=parser, parse_dates=['date_col1', 'date_col2'])
答案 10 :(得分:0)
不,pandas 无法自动识别日期列。
Pandas 在类型推断方面做得很差。它基本上将大多数列作为通用 object
类型,除非您手动解决它,例如。使用上述 parse_dates
参数。
如果您想自动检测列类型,则必须使用单独的数据分析工具,例如。 visions,然后将推断的类型强制转换或提供回您的 DataFrame
构造函数(例如,对于日期和 from_csv
,使用 parse_dates
参数)。