2014-10-20 91 views
1

问题:给定一个数据框有几个条目和一个形式为“%Y%m%d”的日期列(即yyyy-mm-dd;这些条目是字符串)什么是一种快速计算的方式将数据列添加到由月份的词典顺序组成的数据框中?熊猫,groupby绝对月份

为什么在StackOverflow:给定一个指定的年份和月份,上述顺序允许人们轻松地上升或下降相对于指定月份的任何月数。我有一个有效的临时解决方案,但想象之前这个问题已经被优雅地解决了。

上下文:举例来说,给定数据帧DF:

  date user 
0 2011-10-06  1 
1 2011-09-01  2 
2 2011-11-05  3 
3 2012-01-01  1 
4 2012-01-01  2 
5 2012-01-02  3 

期望的输出是:

  date user absmonth 
0 2011-10-06  1   2 
1 2011-09-01  2   1 
2 2011-11-05  3   3 
3 2012-01-01  1   4 
4 2012-01-01  2   4 
5 2012-01-02  3   4 

我已经试过

1)我做了一个adhoc def,它基于简单的算术设置'absmonth'的值;通过df.loc[row, 'absmonth'] = ...为每一行。这个“工作”,但计算上很慢

2)使用GROUPBY:

df['newdate']=pd.to_datetime(df['date'],format='%Y-%m-%d') 
df = df.set_index('newdate') 
monthsgroup = df.groupby(df.index.month, df.index.year) 

产生错误:

axis = self._AXIS_ALIASES.get(axis, axis) 
TypeError: unhashable type: 'numpy.ndarray' 

也:

months = df.gropuby(df.index.month) 
len(months) 
4 

在这一点上,我应该能够使用类似df使用months“应用”功能,但有点丢失...

PS:

pd.__version__ 
'0.14.0' 

帮助理解。

+0

不知道你lexagraphic顺序是什么意思几个月?这个月是按英文顺序排列的吗? – Joop 2014-10-20 09:06:33

+0

在所有数字对(Y,m)的集合上词典编纂。即我们写出“(Y,m)<(Y',m')”当且仅当以下成立为自然数:i)Y wheatgrassman 2014-10-20 13:06:51

回答

1

我认为“适用”是一个好方法。

我从头到尾提供了我当前的解决方案。我想我已经通过现在应用方法'min'来修复排名以获得期望的结果。

import pandas as pd 

x = [{'date':'2011-10-06', 'user':1}, {'date':'2011-09-01', 'user':2},{'date':'2011-11-05', 'user':3}, {'date':'2012-01-01', 'user':1},{'date':'2012-01-01', 'user':2}, {'date':'2012-01-02', 'user':3}] 

dx = pd.DataFrame(x) 

dx['date'] = pd.to_datetime(dx['date'], format='%Y-%m-%d') 

def get_ym(s): 
    s = str(s) 
    s = s[:7] 
    s = s.replace('-','') 
    return int(s) 


dx['absmonth'] = dx['date'].apply(get_ym) 
dx['absmonth'] = dx['absmonth'].rank(method='min') 

----- 
dx = 
     date user absmonth 
0 2011-10-06  1 2 
1 2011-09-01  2 1 
2 2011-11-05  3 3 
3 2012-01-01  1 4 
4 2012-01-01  2 4 
5 2012-01-02  3 4 

如果有人有一个更好的解决方案,G。使用groupby,我都是耳朵。

UPDATE: DSM善意使用“密”提出了以下解决方案,这是我的方法和增量为1队伍的精简版本:

dx['absmonth'] = dx['date'].str.split('-').str[:2].rank('dense') 
+0

嘿,你删除了我的建议。 :-)我们应该使用'dense'而不是'min'作为rank方法,即'df [“date”]。str.split(“ - ”)。str [:2] .rank(“dense”) '来处理你注意到的情况。随着它每次增加1。 – DSM 2014-10-21 03:32:51

+0

哦,对不起,我以为你已经删除了,我的道歉! – wheatgrassman 2014-10-21 03:41:53

+1

我需要一段时间,所以我[加入](https://github.com/pydata/pandas/pull/6514)。 :-) – DSM 2014-10-21 03:49:37

0

这是怎么回事?

df['absmonth'] = df.date 
dict = df.absmonth.unique() 
dict.sort() 
df.absmonth.replace(dict,range(1,len(dict)+1),inplace=True) 

编辑如果你喜欢在最后使用日期的工作而不是格式:

df['absmonth'] = df.date.apply(lambda x: np.datetime64(x, 'M')) 
dict = df.absmonth.unique() 
dict.sort() 
df.absmonth.replace(dict,range(1,len(dict)+1),inplace=True) 
df.absmonth=df.absmonth.astype(int) 

我想办法应该存在,以避免使用适用的,但我没有找到它。 Pandas.to_datetime(df ['date'],format ='%Y-%m-%d',unit ='M')不适用于我。 但是,我希望它能实现你想要的。

+0

您的解决方案不能正确工作,因为您按整个日期排序三元组(Y,m,d),*不执行按对(Y,m)排序所必需的解析。要做后者,我认为groupby(或加入)可能是最好的。另请注意:在熊猫14.0上,以及我提到的设置,您编辑的解决方案不起作用unfortuntaley:TypeError:不能将datetimelike [datetime64 [ns]]设置为[int32]。 – wheatgrassman 2014-10-20 22:59:25

+0

如果有帮助:在第一个提议的结果中,'absmonth'列中的最后一个条目,即'date = 2012-01-02'的行是'5',它应该是'4'。 – wheatgrassman 2014-10-20 23:19:00

+0

确定了,我没有意识到 – Daniele 2014-10-21 10:33:17