Considere um arquivo csv:
string,date,number
a string,2/5/11 9:16am,1.0
a string,3/5/11 10:44pm,2.0
a string,4/22/11 12:07pm,3.0
a string,4/22/11 12:10pm,4.0
a string,4/29/11 11:59am,1.0
a string,5/2/11 1:41pm,2.0
a string,5/2/11 2:02pm,3.0
a string,5/2/11 2:56pm,4.0
a string,5/2/11 3:00pm,5.0
a string,5/2/14 3:02pm,6.0
a string,5/2/14 3:18pm,7.0
Posso ler e reformatar a coluna de data no formato datetime:
b=pd.read_csv('b.dat')
b['date']=pd.to_datetime(b['date'],format='%m/%d/%y %I:%M%p')
Tenho tentado agrupar os dados por mês. Parece que deveria haver uma maneira óbvia de acessar o mês e agrupar por ele. Mas eu não consigo fazer isso. Alguém sabe como?
O que estou tentando atualmente é reindexar pela data:
b.index=b['date']
Posso acessar o mês assim:
b.index.month
No entanto, não consigo encontrar uma função para agrupar por mês.
python
pandas
datetime
pandas-groupby
atomh33ls
fonte
fonte
my_df.my_column.dt.month
Respostas:
Conseguiu fazer isso:
b = pd.read_csv('b.dat') b.index = pd.to_datetime(b['date'],format='%m/%d/%y %I:%M%p') b.groupby(by=[b.index.month, b.index.year])
Ou
b.groupby(pd.Grouper(freq='M')) # update for v0.21+
fonte
resample
(quando ele fornece a funcionalidade de que você precisa) ou usarTimeGrouper
:df.groupby(pd.TimeGrouper(freq='M'))
df.groupby(pd.TimeGrouper(freq='M')).sum()
oudf.groupby(pd.TimeGrouper(freq='M')).mean()
pd.TimeGrouper
foi preterido em favor depd.Grouper
, que é um pouco mais flexível, mas ainda aceitafreq
elevel
argumentos.to_datetime
.b
é fornecido um índice após ser lido em CSV. Adicioneb.index = pd.to_datetime(b['date'],format='%m/%d/%y %I:%M%p')
depois da linhab = pd.read_csv('b.dat')
. [Eu também editei a resposta agora](atualização: 2018)
Observe que
pd.Timegrouper
está depreciado e será removido. Use em seu lugar:df.groupby(pd.Grouper(freq='M'))
fonte
freq=...
) aqui . Alguns exemplos sãofreq=D
para dias ,freq=B
para dias úteis ,freq=W
por semanas ou mesmofreq=Q
para bairros .Uma solução que evita o MultiIndex é criar uma nova
datetime
configuração de coluna dia = 1. Em seguida, agrupe por esta coluna.Normalizar dia do mês
df = pd.DataFrame({'Date': pd.to_datetime(['2017-10-05', '2017-10-20', '2017-10-01', '2017-09-01']), 'Values': [5, 10, 15, 20]}) # normalize day to beginning of month, 4 alternative methods below df['YearMonth'] = df['Date'] + pd.offsets.MonthEnd(-1) + pd.offsets.Day(1) df['YearMonth'] = df['Date'] - pd.to_timedelta(df['Date'].dt.day-1, unit='D') df['YearMonth'] = df['Date'].map(lambda dt: dt.replace(day=1)) df['YearMonth'] = df['Date'].dt.normalize().map(pd.tseries.offsets.MonthBegin().rollback)
Em seguida, use
groupby
normalmente:g = df.groupby('YearMonth') res = g['Values'].sum() # YearMonth # 2017-09-01 20 # 2017-10-01 30 # Name: Values, dtype: int64
Comparação com
pd.Grouper
O benefício sutil dessa solução é, ao contrário
pd.Grouper
, o índice de garoupa é normalizado para o início de cada mês, e não para o final e, portanto, você pode facilmente extrair grupos por meio deget_group
:some_group = g.get_group('2017-10-01')
Calcular o último dia de outubro é um pouco mais complicado.
pd.Grouper
, a partir da v0.23, oferece suporte a umconvention
parâmetro, mas isso é aplicável apenas para umPeriodIndex
garoupaComparação com conversão de string
Uma alternativa à ideia acima é converter para uma string, por exemplo, converter data
2017-10-XX
e hora para string'2017-10'
. No entanto, isso não é recomendado, pois você perde todos os benefícios de eficiência de umadatetime
série (armazenada internamente como dados numéricos em um bloco de memória contíguo) versus umaobject
série de strings (armazenada como uma matriz de ponteiros).fonte
pd.tseries.offsets
tem vantagem sobrepd.tseries.MonthBegin
?df['YearMonth'] = df['Date'] - pd.offsets.MonthBegin(1)
código acima altera qualquer data que já seja o primeiro dia do mês para o primeiro dia do mês anterior.Solução ligeiramente alternativa para @jpp's, mas gerando uma
YearMonth
string:df['YearMonth'] = pd.to_datetime(df['Date']).apply(lambda x: '{year}-{month}'.format(year=x.year, month=x.month)) res = df.groupby('YearMonth')['Values'].sum()
fonte