Jasne, mógłbym napisać to sam, ale zanim wymyślę koło na nowo, czy jest jakaś funkcja, która już to robi?
pandas.Series.dt.quarter
.
Jasne, mógłbym napisać to sam, ale zanim wymyślę koło na nowo, czy jest jakaś funkcja, która już to robi?
pandas.Series.dt.quarter
.
Odpowiedzi:
Biorąc pod uwagę wystąpienie x
z datetime.date , (x.month-1)//3
daje czwartą (0 dla pierwszego kwartału, 1 dla drugiego kwartału, etc - dodać1w jeśli trzeba liczyć od 1 zamiast ;-).
Pierwotnie dwie odpowiedzi, pomnożone za głosami, a nawet pierwotnie zaakceptowane (obie obecnie usunięte), były błędne - nie robiłem tego -1
przed podziałem i dzielono przez 4 zamiast 3. Od .month
1 do 12 łatwo jest sprawdzić, jaka jest formuła dobrze:
for m in range(1, 13):
print m//4 + 1,
print
daje 1 1 1 2 2 2 2 3 3 3 3 4
- dwa kwartały czteromiesięczne i jednomiesięczny (eep).
for m in range(1, 13):
print (m-1)//3 + 1,
print
daje 1 1 1 2 2 2 3 3 3 4 4 4
- czy to nie wygląda dla ciebie zdecydowanie lepiej? -)
To dowodzi, że pytanie jest, jak sądzę, uzasadnione ;-).
Nie sądzę, że moduł datetime koniecznie powinien mieć każdą możliwą użyteczną funkcję kalendarza, ale wiem, że utrzymuję (dobrze przetestowany ;-) datetools
moduł do wykorzystania moich (i innych) projektów w pracy, który ma wiele niewielkich funkcje do wykonywania wszystkich tych obliczeń w kalendarzu - niektóre są złożone, inne proste, ale nie ma powodu, aby wykonywać tę pracę w kółko (nawet prostą pracę) ani ryzykować błędów w takich obliczeniach ;-).
(m+2)//3
zamiast(m-1)//3 + 1
Jeśli już używasz pandas
, jest to dość proste.
import datetime as dt
import pandas as pd
quarter = pd.Timestamp(dt.date(2016, 2, 29)).quarter
assert quarter == 1
Jeśli masz date
kolumnę w ramce danych, możesz łatwo utworzyć nową quarter
kolumnę:
df['quarter'] = df['date'].dt.quarter
pandas.Series.dt.quarter
jest idealnym rozwiązaniem, gdy masz wartości daty i godziny w obiekcie Dataframe lub Series .
Sugerowałbym inne, prawdopodobnie czystsze rozwiązanie. Jeśli X jest datetime.datetime.now()
instancją, to kwartał jest:
import math
Q=math.ceil(X.month/3.)
ceil musi zostać zaimportowany z modułu matematycznego, ponieważ nie można uzyskać do niego bezpośredniego dostępu.
math.ceil(float(4)/3) = 2.0
, podczas gdymath.ceil(4/3) = 1.0
.
zrobili po 3.math.ceil(4/3.) = 2.0
Dla każdego, kto próbuje uzyskać kwartał roku podatkowego , który może różnić się od kalendarza , napisałem moduł Pythona, aby to zrobić.
Instalacja jest prosta. Po prostu biegnij:
$ pip install fiscalyear
Nie ma żadnych zależności i fiscalyear
powinno działać zarówno dla Pythona 2, jak i 3.
Zasadniczo jest to otoka wokół wbudowanego modułu datetime , więc wszystkie datetime
polecenia, które już znasz, będą działać. Oto 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
jest hostowany na GitHub i PyPI . Dokumentację można znaleźć pod adresem Read the Docs . Jeśli szukasz funkcji, których obecnie nie ma, daj mi znać!
Oto przykład funkcji, która pobiera obiekt datetime.datetime i zwraca unikalny ciąg dla każdego kwartału:
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))
A wynik to:
2019-02-14 Q1_2019
2018-11-16 Q4_2018
2017-08-18 Q3_2017
Ta metoda działa dla dowolnego mapowania:
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
Właśnie wygenerowaliśmy funkcję int->int
month2quarter(9) # returns 3
Ta metoda jest również niezawodna
month2quarter(-1) # returns None
month2quarter('July') # returns None
Dla tych, którzy szukają danych za kwartał roku obrotowego, używając pand,
import datetime
import pandas as pd
today_date = datetime.date.today()
quarter = pd.PeriodIndex(today_date, freq='Q-MAR').strftime('Q%q')
odniesienie: indeks okresu pand
To stare pytanie, ale nadal warte dyskusji.
Oto moje rozwiązanie, wykorzystujące doskonały moduł 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)
Tak więc first_day
jest to pierwszy dzień kwartału i last_day
ostatni dzień kwartału (obliczony poprzez znalezienie pierwszego dnia następnego kwartału minus jeden dzień).
hmmm więc obliczenia mogą się nie udać, tutaj jest lepsza wersja (tylko ze względu na to)
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"
. Powinieneś pisać testy, tak jak wszyscy dobrzy programiści. Testy pomagają powstrzymać Cię od popełnienia błędów i wyłapać te, które robisz. Deweloper nigdy nie powinien poświęcać wydajności i czytelności, aby nie popełnić błędu. Ponadto jest to mniej czytelne, niż gdybyś po prostu utworzył statyczny dykt za pomocą literałów.
(m-1)//3 + 1
to też nie wszystko, co jest czytelne, niewiele osób wie, co to //
robi. Mój pierwotny komentarz dotyczył właśnie oświadczenia"calculations can go wrong"
które wydaje mi się dziwne.
Oto rozwlekłe, ale także czytelne rozwiązanie, które będzie działać w przypadku wystąpienia daty i godziny
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
używając słowników, możesz to zrobić przez
def get_quarter(month):
quarter_dictionary = {
"Q1" : [1,2,3],
"Q2" : [4,5,6],
"Q3" : [7,8,9],
"Q4" : [10,11,12]
}
for key,values in quarter_dictionary.items():
for value in values:
if value == month:
return key
print(get_quarter(3))