2017-10-21 70 views
2

可能我的例子是很多大,我的代碼是在這裏:如何獲取自定義時間間隔中的最後日期? - 熊貓

import pandas as pd 
import numpy as np 
import io 
t = """ 
name  date 
a  2005-08-31 
a  2005-09-20 
a  2005-11-12 
a  2005-12-31 
a  2006-03-31 
a  2006-06-25 
a  2006-07-23 
a  2006-09-28 
a  2006-12-21 
a  2006-12-27 
a  2007-07-23 
a  2007-09-21 
a  2007-03-15 
a  2008-04-12 
a  2008-06-21 
a  2008-06-11 
b  2005-08-31 
b  2005-09-23 
b  2005-11-12 
b  2005-12-31 
b  2006-03-31 
b  2006-06-25 
b  2006-07-23 
b  2006-09-28 
b  2006-12-21 
b  2006-12-27 
b  2007-07-23 
b  2007-09-21 
b  2007-03-15 
b  2008-04-12 
b  2008-06-21 
b  2008-06-11 
""" 
data=pd.read_csv(io.StringIO(t),delimiter='  ')#5 space here 
data 

我想要做的是找到哪一年開始2005-7-1一年的天和最後一天),並最終2006-06-30,開始2006-7-1並結束2007-6-30 ...等等。 我的預期輸出是在這裏:

name  date 
a  2006-06-25 #the last day of the 2005/7/01 -2006/06/31 
a  2007-03-15 #the last day of the 2006/7/01 -2007/06/31 
a  2008-06-21 #the last day of the 2007/7/01 -2008/06/31 
b  2006-06-25 #the last day of the 2005/7/01 -2006/06/31 
b  2007-03-15 #the last day of the 2006/7/01 -2007/06/31 
b  2008-06-21 #the last day of the 2007/7/01 -2008/06/31 

怎樣才能解決這個問題?我想我應該使用custom

+0

是是長期看? – ileadall42

+2

注意:9月只有30天,所以有一些不好的數據。 –

+0

@AndyHayden我的天啊,多虧了點! – ileadall42

回答

5

您可以使用一個GROUPBY做到這一點沒有回滾:

In [11]: data.date = pd.to_datetime(data.date, format="%Y-%m-%d") 

In [12]: df.groupby(["name", pd.Grouper(key="date", freq="AS-JUL")])["date"].max() 
Out[12]: 
name date 
a  2005-07-01 2006-06-25 
     2006-07-01 2007-03-15 
     2007-07-01 2008-06-21 
b  2005-07-01 2006-06-25 
     2006-07-01 2007-03-15 
     2007-07-01 2008-06-21 
Name: date, dtype: datetime64[ns] 
+0

我一直在使用freq和石斑魚,但不知道它也可能會造成偏移。超級+1。我會記住這一個 – Dark

+0

添加另一個答案,因爲它非常不同(更短)! –

+1

@Bharathshetty這是石斑魚的主要觀點! :) –

4

嗯,這看起來像一個神奇的方式!
頻率爲「AS-JUL」(年份開始頻率,從7月開始)。

我們首先採取每個月的開始(因爲你在那裏有一些不好的日期,我們就忽略它們),但關鍵的是,我們需要的是日期時間,而不是字符串:

In [11]: pd.to_datetime(data.date.str[:7], format="%Y-%m") # to beginning of month 
Out[11]: 
0 2005-08-01 
1 2005-09-01 
2 2005-11-01 
3 2005-12-01 
... 

In [12]: df.date = pd.to_datetime(data.date.str[:7], format="%Y-%m") 

現在,這裏是magic

In [13]: from pandas.tseries.frequencies import to_offset 

In [14]: df.date.map(to_offset("AS-JUL").rollback) 
Out[14]: 
0 2005-07-01 
1 2005-07-01 
2 2005-07-01 
3 2005-07-01 
4 2005-07-01 
5 2005-07-01 
6 2006-07-01 
7 2006-07-01 
8 2006-07-01 
9 2006-07-01 
10 2007-07-01 
11 2007-07-01 
12 2006-07-01 
13 2007-07-01 
14 2007-07-01 
15 2007-07-01 
16 2005-07-01 
17 2005-07-01 
18 2005-07-01 
19 2005-07-01 
20 2005-07-01 
21 2005-07-01 
22 2006-07-01 
23 2006-07-01 
24 2006-07-01 
25 2006-07-01 
26 2007-07-01 
27 2007-07-01 
28 2006-07-01 
29 2007-07-01 
30 2007-07-01 
31 2007-07-01 
Name: date, dtype: datetime64[ns] 

我們創建了一個偏移"AS-JUL"和滾回去(指樓)。
注:無論出於何種原因,我們不能用dt.floor ...


好吧,你要爲每個組在各個時期的最新記錄日期,誤讀這一部分與該修正的日期時,最後的部分是一個GROUPBY:

In [21]: data.date = pd.to_datetime(data.date, format="%Y-%m-%d") 

In [22]: data["period_start"] = data.date.map(to_offset("AS-JUL").rollback).dt.normalize() 

In [23]: data.groupby(["name", "period_start"])["date"].max() 
Out[23]: 
name period_start 
a  2005-07-01  2006-06-25 
     2006-07-01  2007-03-15 
     2007-07-01  2008-06-21 
b  2005-07-01  2006-06-25 
     2006-07-01  2007-03-15 
     2007-07-01  2008-06-21 
Name: date, dtype: datetime64[ns] 
+0

那麼這些都是真正的新我 – Dark

+0

@Bharathshetty新的我也很巧妙的方法(「魔」是從[鏈接答案](https://stackoverflow.com/a/45963946/1240268))。有關其他偏移量,請參閱:https://stackoverflow.com/a/35339226/1240268。 –

+0

我很喜歡這個解決方案,但OP找的答案我認爲是不同的。他想在我想的時間間隔中找到最後一個工作日。我們需要groupby然後通過創建一個區間索引來檢查最大日期我認爲 – Dark

3

從美麗的功能to_offset @Andy建議我們可以做

from pandas.tseries.frequencies import to_offset 
new = data.groupby('name').apply(lambda x : x.groupby(x['date'].map(to_offset("AS-JUL"))).max()) 
 
      name  date 
name date      
a 2006-07-01 a 2006-06-25 
    2007-07-01 a 2007-03-15 
    2008-07-01 a 2008-06-21 
b 2006-07-01 b 2006-06-25 
    2007-07-01 b 2007-03-15 
    2008-07-01 b 2008-06-21 
+1

你們都很棒,但我只能接受一個,所以我會接受更快的Andy,但也非常感謝你! – ileadall42

+0

即使我不接受他的解決方案,我也會感覺不好。 – Dark

3

通過使用IntervalIndexDF是你DataFrame

idx=pd.IntervalIndex.from_arrays(pd.date_range(start='2005-07-01',freq='12MS',periods=12),pd.date_range(start='2006-06-30',freq='12M',periods=12),closed='both') 
df=pd.DataFrame({'G':list(range(len(idx)))},index=idx) 
DF.date=pd.to_datetime(DF.date) 
DF['G']=df.loc[DF.date].values 
DF.sort_values(['name','date']).drop_duplicates(['name','G'],keep='last') 

Out[19]: 
    name  date G 
5  a 2006-06-25 0 
12 a 2007-03-15 1 
14 a 2008-06-21 2 
21 b 2006-06-25 0 
28 b 2007-03-15 1 
30 b 2008-06-21 2 
+0

我不得不說這很容易理解!謝謝你。 – ileadall42

+0

我你知道這是我用'BEG = np.array([[ '{}/7/01'.format(i)中,' 我的第一種方法{}/6/30'.format第(i + 1) ]對於i在範圍(2005,2010)])''指數= pd.IntervalIndex.from_arrays(pd.to_datetime(BEG [:,0]),pd.to_datetime(BEG [:,1]))'。你的更好 – Dark

+0

@Tangfeifan Yw〜:-) – Wen