2014-10-20 88 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