Certo che potrei scriverlo da solo, ma prima di reinventare la ruota c'è una funzione che lo fa già?
pandas.Series.dt.quarter
.
Certo che potrei scriverlo da solo, ma prima di reinventare la ruota c'è una funzione che lo fa già?
pandas.Series.dt.quarter
.
Risposte:
Data un'istanza x
di datetime.date , (x.month-1)//3
ti darà il trimestre (0 per il primo trimestre, 1 per il secondo trimestre, ecc. - aggiungi 1 se devi invece contare da 1 ;-).
Originariamente due risposte, moltiplicate per voti positivi e persino originariamente accettate (entrambe attualmente cancellate), erano buggy - non facendo la -1
prima della divisione e dividendo per 4 invece di 3. Dato che .month
va da 1 a 12, è facile verificare di persona quale sia la formula giusto:
for m in range(1, 13):
print m//4 + 1,
print
dà 1 1 1 2 2 2 2 3 3 3 3 4
- due trimestri di quattro mesi e uno di un mese (eep).
for m in range(1, 13):
print (m-1)//3 + 1,
print
dà 1 1 1 2 2 2 3 3 3 4 4 4
- ora non ti sembra di gran lunga preferibile? -)
Ciò dimostra che la domanda è ben giustificata, credo ;-).
Non penso che il modulo datetime debba necessariamente avere tutte le possibili utili funzioni di calendario, ma so di mantenere un datetools
modulo (ben collaudato ;-) per l'uso dei miei (e di altri) progetti al lavoro, che ha molti piccoli funzioni per eseguire tutti questi calcoli calendrici - alcuni sono complessi, altri semplici, ma non c'è motivo per fare il lavoro più e più volte (anche lavoro semplice) o rischiare bug in tali calcoli ;-).
(m+2)//3
invece di(m-1)//3 + 1
SE stai già usando pandas
, è abbastanza semplice.
import datetime as dt
import pandas as pd
quarter = pd.Timestamp(dt.date(2016, 2, 29)).quarter
assert quarter == 1
Se hai una date
colonna in un dataframe, puoi facilmente creare una nuova quarter
colonna:
df['quarter'] = df['date'].dt.quarter
pandas.Series.dt.quarter
è una soluzione ideale quando si hanno valori datetime in un oggetto Dataframe o Series .
Suggerirei un'altra soluzione discutibilmente più pulita. Se X è datetime.datetime.now()
un'istanza, il trimestre è:
import math
Q=math.ceil(X.month/3.)
ceil deve essere importato dal modulo matematico poiché non è possibile accedervi direttamente.
math.ceil(float(4)/3) = 2.0
mentremath.ceil(4/3) = 1.0
.
dopo 3 math.ceil(4/3.) = 2.0
Per chiunque cerchi di ottenere il trimestre dell'anno fiscale , che può differire dall'anno solare , ho scritto un modulo Python per fare proprio questo.
L'installazione è semplice. Corri:
$ pip install fiscalyear
Non ci sono dipendenze e fiscalyear
dovrebbe funzionare sia per Python 2 che per 3.
È fondamentalmente un wrapper attorno al modulo datetime integrato, quindi tutti i datetime
comandi con cui hai già familiarità funzioneranno. Ecco una demo:
>>> from fiscalyear import *
>>> a = FiscalDate.today()
>>> a
FiscalDate(2017, 5, 6)
>>> a.fiscal_year
2017
>>> a.quarter
3
>>> b = FiscalYear(2017)
>>> b.start
FiscalDateTime(2016, 10, 1, 0, 0)
>>> b.end
FiscalDateTime(2017, 9, 30, 23, 59, 59)
>>> b.q3
FiscalQuarter(2017, 3)
>>> b.q3.start
FiscalDateTime(2017, 4, 1, 0, 0)
>>> b.q3.end
FiscalDateTime(2017, 6, 30, 23, 59, 59)
fiscalyear
è ospitato su GitHub e PyPI . La documentazione può essere trovata in Leggi i documenti . Se stai cercando funzionalità che attualmente non ha, fammelo sapere!
Di seguito è riportato un esempio di una funzione che ottiene un oggetto datetime.datetime e restituisce una stringa univoca per ogni trimestre:
from datetime import datetime, timedelta
def get_quarter(d):
return "Q%d_%d" % (math.ceil(d.month/3), d.year)
d = datetime.now()
print(d.strftime("%Y-%m-%d"), get_q(d))
d2 = d - timedelta(90)
print(d2.strftime("%Y-%m-%d"), get_q(d2))
d3 = d - timedelta(180 + 365)
print(d3.strftime("%Y-%m-%d"), get_q(d3))
E l'output è:
2019-02-14 Q1_2019
2018-11-16 Q4_2018
2017-08-18 Q3_2017
Questo metodo funziona per qualsiasi mappatura:
month2quarter = {
1:1,2:1,3:1,
4:2,5:2,6:2,
7:3,8:3,9:3,
10:4,11:4,12:4,
}.get
Abbiamo appena generato una funzione int->int
month2quarter(9) # returns 3
Questo metodo è anche infallibile
month2quarter(-1) # returns None
month2quarter('July') # returns None
Per coloro che sono alla ricerca di dati trimestrali dell'anno finanziario, utilizzando i panda,
import datetime
import pandas as pd
today_date = datetime.date.today()
quarter = pd.PeriodIndex(today_date, freq='Q-MAR').strftime('Q%q')
riferimento: indice del periodo dei panda
Questa è una vecchia domanda ma ancora degna di discussione.
Ecco la mia soluzione, utilizzando l'eccellente modulo dateutil .
from dateutil import rrule,relativedelta
year = this_date.year
quarters = rrule.rrule(rrule.MONTHLY,
bymonth=(1,4,7,10),
bysetpos=-1,
dtstart=datetime.datetime(year,1,1),
count=8)
first_day = quarters.before(this_date)
last_day = (quarters.after(this_date)
-relativedelta.relativedelta(days=1)
Quindi first_day
è il primo giorno del trimestre ed last_day
è l'ultimo giorno del trimestre (calcolato trovando il primo giorno del trimestre successivo, meno un giorno).
hmmm quindi i calcoli possono andare storti, ecco una versione migliore (solo per il gusto di farlo)
first, second, third, fourth=1,2,3,4# you can make strings if you wish :)
quarterMap = {}
quarterMap.update(dict(zip((1,2,3),(first,)*3)))
quarterMap.update(dict(zip((4,5,6),(second,)*3)))
quarterMap.update(dict(zip((7,8,9),(third,)*3)))
quarterMap.update(dict(zip((10,11,12),(fourth,)*3)))
print quarterMap[6]
"it is difficult to see correctness except by testing it"
. Dovresti scrivere dei test, come dovrebbero fare tutti i bravi sviluppatori. I test sono ciò che ti aiuta a impedirti di commettere errori e a catturare quelli che fai. Uno sviluppatore non dovrebbe mai sacrificare prestazioni e leggibilità per evitare di commettere errori. Inoltre, questo è meno leggibile rispetto a se avessi creato un dict statico usando letterali.
(m-1)//3 + 1
non è nemmeno tutto leggibile, non molte persone sanno cosa //
fa. Il mio commento originale era solo sull'affermazione "calculations can go wrong"
che mi suona strana.
Ecco una soluzione dettagliata, ma anche leggibile che funzionerà per le istanze di data e ora
def get_quarter(date):
for months, quarter in [
([1, 2, 3], 1),
([4, 5, 6], 2),
([7, 8, 9], 3),
([10, 11, 12], 4)
]:
if date.month in months:
return quarter