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 xdi datetime.date , (x.month-1)//3ti 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 -1prima della divisione e dividendo per 4 invece di 3. Dato che .monthva 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 datetoolsmodulo (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)//3invece 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 datecolonna in un dataframe, puoi facilmente creare una nuova quartercolonna:
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.0mentremath.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 fiscalyeardovrebbe funzionare sia per Python 2 che per 3.
È fondamentalmente un wrapper attorno al modulo datetime integrato, quindi tutti i datetimecomandi 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 + 1non è 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