我有一个这种格式的SQL表,我想阅读并转换成pandas时间序列。
y (year) w (week) d (some data)
2009 1 10
2009 2 15
...
这样做的好方法是什么?
我知道read_sql()的parse_dates参数,或者使用DatetimeIndex手动设置索引。我无法理解如何使用周数据来做到这一点。我尝试了以下内容。感谢。
# gives NaT for year & week:
df = pd.read_sql("SELECT y, w, d FROM t",
db, parse_dates={"y":"%Y", "w":"%U"})
# gives wrong dates for yw - e.g. all 2009-01-01:
df = pd.read_sql("SELECT CONCAT(y,'/',w) as yw, d FROM t",
db, parse_dates={"yw": "%Y/%U"})
# throws DateParseError exception:
df = pd.read_sql("SELECT CONCAT(y,'W',w) as yw, d FROM t",
db)
df.index = pd.DatetimeIndex(df.yw)
答案 0 :(得分:0)
真的,我认为最优雅的方法是在SQL中执行转换:
sql = "SELECT DATE_ADD(MAKEDATE(y, 1), INTERVAL w WEEK) as date, d FROM test.t"
df = pd.read_sql(sql, engine)
print(df)
产量
date d
0 2009-01-08 10
1 2009-01-15 15
要在Python中执行等效操作需要更多样板,因为AFAIK Pandas不提供任何开箱即用的设施,可将年份和周数转换为日期。您当然可以使用循环和datetime模块将数字逐个转换为datetime.datetime对象。
更快的方法是使用NumPy的datetime64和timedelta64 dtypes作为NumPy数组进行日期算术:
sql = "SELECT y, w, d FROM t"
df = pd.read_sql(sql, engine)
date = (df['y'].astype('<i8')-1970).view('<M8[Y]')
delta = (df['w'].astype('<i8')*7).view('<m8[D]')
df['date'] = date+delta
df = df[['date', 'd']]
print(df)
产量
date d
0 2009-01-08 10
1 2009-01-15 15
编辑:在评论的基础上建立Hadi的答案,也可以使用MySQL STR_TO_DATE function计算SQL中的日期:
sql = "SELECT STR_TO_DATE(CONCAT(y,':',w,':1'), '%x:%v:%w') as date, d FROM test.t"
df = pd.read_sql(sql, engine)
产生
date d
0 2008-12-29 10
1 2009-01-05 15
请注意,根据MySQL docs,%v
,表示
Week (01..53), where Monday is the first day of the week; WEEK() mode 3; used with %x
以及之后on the same page,模式3表示
Mode First day of week Range Week 1 is the first week …
3 Monday 1-53 with 4 or more days this year
对于具有“今年4天或更多天”含义的模式值 周数根据ISO 8601:1988编号。
因此,如果您希望周数与ISO 8601:1988一致,那么使用STR_TO_DATE
,您应该使用%v
(或%u
),而不是%V
(或%U
)。
请注意,我上面的第一个答案并未将本周解释为ISO 8601周数;它只计算每周1月1日起的7天。