python - grouper - Agrupe objetos de fecha arbitraria que estén dentro de un intervalo de tiempo uno del otro
pandas grouper (3)
Quiero dividir el calendario en intervalos de dos semanas a partir de 2008-May-5
, o cualquier punto de partida arbitrario.
Entonces comienzo con varios objetos de fecha:
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()
Analizando manualmente las fechas, puedo descifrar qué fechas caen dentro del mismo intervalo quincenal. Quiero obtener una agrupación similar a esta:
# 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'')
El uso de un DataFrame
con resample
también funciona. Dados los datos de OP, pero cambie "algunos datos aquí" a "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'')]
Ahora intenta usar pandas. Primero crea un DataFrame
, nombra las columnas y establece los índices a las fechas.
>>> 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
Ahora use los alias de compensación de serie cada 2 semanas comenzando los domingos y concatenar los resultados.
>>> fortnight = df.resample(''2W-SUN'').sum()
data
date
2010-06-27 b
2010-07-11 cd
2010-07-25 0
2010-08-08 a
Ahora profundice en los datos según sea necesario antes de la semana de inicio
>>> fortnight.loc[''2010-06-27''][''data'']
b
o índice
>>> fortnight.iloc[0][''data'']
b
o índices
>>> 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
Use itertools groupby con la función lambda para dividir por el período de tiempo la distancia desde el punto de inicio.
>>> 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]
Entonces con las fechas:
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)
También puede usar los números de semana de strftime y lenperiod en número de semanas:
for fnight,info in it.groupby(transactions,lambda data: int (data[0].strftime(''%W'')) // lenperiod):
print list(info)
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))
rendimientos
# (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'')])
Tenga en cuenta que 2010-6-25 se encuentra en la quincuagésima quinta semana entre 2008-5-5, mientras que 2010-7-1 se encuentra en la 56ª. Si quiere que se agrupen, simplemente cambie start_date
(a algo así como 2008-5-16).
PD. La herramienta clave utilizada anteriormente es itertools.groupby
, que se explica en detalle aquí .
Editar: Las lambda
s son simplemente una forma de realizar funciones "anónimas" . (Son anónimos en el sentido de que no reciben nombres como funciones definidas por def
). Donde sea que veas una lambda, también es posible usar una def
para crear una función equivalente. Por ejemplo, podrías hacer esto:
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))