2010-08-07 68 views
4

我要拆分的日历成两个周的时间间隔起始于2008-May-5,或任意的起点的时间范围内一起。组任意日期对象是彼此

于是我开始与几个日期对象:

import datetime as DT 

raw = ("2010-08-01", 
     "2010-06-25", 
     "2010-07-01", 
     "2010-07-08") 

transactions = [(DT.datetime.strptime(datestring, "%Y-%m-%d").date(), 
       "Some data here") for datestring in raw] 
transactions.sort() 

通过人工分析的日期,我挺能找出哪些相同的两周时间内下跌日期。我想分组这是类似这样的:

# Fortnight interval 1 
(datetime.date(2010, 6, 25), 'Some data here') 
(datetime.date(2010, 7, 1), 'Some data here') 
(datetime.date(2010, 7, 8), 'Some data here') 

# Fortnight interval 2 
(datetime.date(2010, 8, 1), 'Some data here') 

回答

11
import datetime as DT 
import itertools 

start_date=DT.date(2008,5,5) 

def mkdate(datestring): 
    return DT.datetime.strptime(datestring, "%Y-%m-%d").date() 

def fortnight(date): 
    return (date-start_date).days //14 

raw = ("2010-08-01", 
     "2010-06-25", 
     "2010-07-01", 
     "2010-07-08") 
transactions=[(date,"Some data") for date in map(mkdate,raw)] 
transactions.sort(key=lambda (date,data):date) 

for key,grp in itertools.groupby(transactions,key=lambda (date,data):fortnight(date)): 
    print(key,list(grp)) 

产量

# (55, [(datetime.date(2010, 6, 25), 'Some data')]) 
# (56, [(datetime.date(2010, 7, 1), 'Some data'), (datetime.date(2010, 7, 8), 'Some data')]) 
# (58, [(datetime.date(2010, 8, 1), 'Some data')]) 

注意2010-6-25是从2008-5-5 55两星期,而2010 -7-1是在56。如果你想让他们分组在一起,只需更改start_date(类似于2008-5-16)。

PS。上面使用的关键工具是itertools.groupby,详细解释如下:here

编辑:lambda s只是一种制作"anonymous" functions的方法。 (它们是匿名的,因为它们没有被赋予由def定义的功能的名称)。无论您看到lambda表达式,还可以使用def创建等效函数。例如,您可以这样做:

import operator 
transactions.sort(key=operator.itemgetter(0)) 

def transaction_fortnight(transaction): 
    date,data=transaction 
    return fortnight(date) 

for key,grp in itertools.groupby(transactions,key=transaction_fortnight): 
    print(key,list(grp)) 
+2

'// 14'是相同的'/14'在Python2中,但在Python3中需要得到整数除法(因为'/ 14'在Python3中给出了浮点除法)。通过使用'// 14',您可以在将来验证您的代码。参见http://docs.python.org/library/stdtypes.html#numeric-types-int-float-long-complex – unutbu 2010-08-07 12:57:56

+1

//被用作整数除法,但实际上它除以数字,结果自动舍入到最近整数。当与浮游物一起使用时,结果保持浮动状态。 – 2010-08-07 13:00:16

+0

我不确定我是否理解'lambda'如何在这里工作。就我所了解的'lambdas'而言,它们对于使它们在'iterable's上工作特别有用。 sort()和groupby()是否对它们的''key'执行一些迭代操作? – Kit 2010-08-07 13:01:05

4

使用带有lambda函数的itertools groupby除以距离起点的距离的长度。

>>> for i, group in groupby(range(30), lambda x: x // 7): 
    print list(group) 


[0, 1, 2, 3, 4, 5, 6] 
[7, 8, 9, 10, 11, 12, 13] 
[14, 15, 16, 17, 18, 19, 20] 
[21, 22, 23, 24, 25, 26, 27] 
[28, 29] 
与日期

所以:

import itertools as it 
start = DT.date(2008,5,5) 
lenperiod = 14 

for fnight,info in it.groupby(transactions,lambda data: (data[0]-start).days // lenperiod): 
    print list(info) 

您还可以使用来自的strftime weeknumbers,并在周数lenperiod:

for fnight,info in it.groupby(transactions,lambda data: int (data[0].strftime('%W')) // lenperiod): 
    print list(info) 
1

使用pandas DataFrameresample工作过。给定OP的数据,但将“一些数据在这里”改为“abcd”。

>>> import datetime as DT 
>>> raw = ("2010-08-01", 
...  "2010-06-25", 
...  "2010-07-01", 
...  "2010-07-08") 
>>> transactions = [(DT.datetime.strptime(datestring, "%Y-%m-%d"), data) for 
...     datestring, data in zip(raw,'abcd')] 
[(datetime.datetime(2010, 8, 1, 0, 0), 'a'), 
(datetime.datetime(2010, 6, 25, 0, 0), 'b'), 
(datetime.datetime(2010, 7, 1, 0, 0), 'c'), 
(datetime.datetime(2010, 7, 8, 0, 0), 'd')] 

现在尝试使用熊猫。首先创建一个DataFrame,命名列和设置索引的日期。

>>> import pandas as pd 
>>> df = pd.DataFrame(transactions, 
...     columns=['date','data']).set_index('date') 
      data 
date 
2010-08-01 a 
2010-06-25 b 
2010-07-01 c 
2010-07-08 d 

现在开始使用在周日Series Offset Aliases每2周连接结果。

>>> fortnight = df.resample('2W-SUN').sum() 
      data 
date 
2010-06-27 b 
2010-07-11 cd 
2010-07-25 0 
2010-08-08 a 

现在根据需要通过weekstart

>>> fortnight.loc['2010-06-27']['data'] 
b 

或索引钻入数据

>>> fortnight.iloc[0]['data'] 
b 

或指数

>>> data = fortnight.iloc[:2]['data'] 
b 
date 
2010-06-27  b 
2010-07-11 cd 
Freq: 2W-SUN, Name: data, dtype: object 
>>> data[0] 
b 
>>> data[1] 
cd