2014-09-11 12 views
5

Mam zestaw danych z codziennymi danymi. Muszę pobierać tylko dane pierwszego dnia każdego miesiąca z zestawu danych (dane pochodzą z 1972 roku). Tak na przykład potrzebowałbym wyodrębnić indeks 20, Data 2013-12-02 o wartości 0.1555. Mam problem polegający na tym, że pierwszy dzień każdego miesiąca jest inny, więc nie mogę użyć kroku takiego jak relativedelta (miesiące = 1), w jaki sposób chciałbym wydobyć te wartości z mojego zestawu danych?Filtruj dane, aby otrzymać tylko pierwszy dzień wierszy miesiąca

Czy istnieje podobne polecenie, które znalazłem w innym poście dla R? R - XTS: Get the first dates and values for each month from a daily time series with missing rows

17 2013-12-05 0.1621 18 2013-12-04 0.1698 19 2013-12-03 0.1516 20 2013-12-02 0.1555 21 2013-11-29 0.1480 22 2013-11-27 0.1487 23 2013-11-26 0.1648

Odpowiedz

8

Chciałbym pogrupować miesiąc, a następnie uzyskać zerowy (nth) wiersz każdej grupy.

najpierw ustawić jako wskaźnika (chyba że jest to konieczne):

In [11]: df1 = df.set_index('date') 

In [12]: df1 
Out[12]: 
      n  val 
date 
2013-12-05 17 0.1621 
2013-12-04 18 0.1698 
2013-12-03 19 0.1516 
2013-12-02 20 0.1555 
2013-11-29 21 0.1480 
2013-11-27 22 0.1487 
2013-11-26 23 0.1648 

Następny sortowania, tak że pierwszy element jest pierwszy dzień danego miesiąca (Uwaga: to nie pojawiają być konieczne do nth, ale myślę, że to rzeczywiście bug):

In [13]: df1.sort_index(inplace=True) 

In [14]: df1.groupby(pd.TimeGrouper('M')).nth(0) 
Out[14]: 
      n  val 
date 
2013-11-26 23 0.1648 
2013-12-02 20 0.1555 

innym rozwiązaniem jest ponowne próbkowanie i wziąć pierwszy wpis:

In [15]: df1.resample('M', 'first') 
Out[15]: 
      n  val 
date 
2013-11-30 23 0.1648 
2013-12-31 20 0.1555 

Myśląc o tym, można to znacznie prostsze zrobić poprzez ekstrakcję miesiąc, a następnie grupowanie przez że:

In [21]: pd.DatetimeIndex(df.date).to_period('M') 
Out[21]: 
<class 'pandas.tseries.period.PeriodIndex'> 
[2013-12, ..., 2013-11] 
Length: 7, Freq: M 

In [22]: df.groupby(pd.DatetimeIndex(df.date).to_period('M')).nth(0) 
Out[22]: 
    n  date  val 
0 17 2013-12-05 0.1621 
4 21 2013-11-29 0.1480 

Tym razem posortowania z df.datejest (prawidłowo) istotne, jeśli wiesz, to data w porządku malejącym można użyć nth(-1):

In [23]: df.groupby(pd.DatetimeIndex(df.date).to_period('M')).nth(-1) 
Out[23]: 
    n  date  val 
3 20 2013-12-02 0.1555 
6 23 2013-11-26 0.1648 

Jeśli to nie jest gwarantowana następnie rodzaj b y pierwsza kolumna daty: df.sort('date').

+0

Chciałem dodać, będziesz mógł napisać 'pd.DatetimeIndex (df.date) .to_period ('M')' jako 'df.date.dt.to_period ('M')' z 0.15. –

+0

Dzięki! To było dokładnie to, czego szukałem. – tadalendas

1

Jednym ze sposobów jest dodanie kolumny na rok, miesiąc i dzień:

df['year'] = df.SomeDatetimeColumn.map(lambda x: x.year) 
df['month'] = df.SomeDatetimeColumn.map(lambda x: x.month) 
df['day'] = df.SomeDatetimeColumn.map(lambda x: x.day) 

Następnie grupa przez cały rok i miesiąc, porządek w dzień, i podjąć tylko pierwszy wpis (który będzie wpisem minimalnego dnia).

df.groupby(
    ['year', 'month'] 
).apply(lambda x: x.sort('day', ascending=True)).head(1) 

Zastosowanie lambda wyrażeń sprawia, że ​​to mniej niż idealne dla dużych zbiorów danych. Możesz nie chcieć powiększać rozmiaru danych, zachowując oddzielnie przechowywane wartości roku, miesiąca i dnia. Jednak w przypadku tego rodzaju problemów z dostosowaniem daty ad hoc bardzo pomocne jest wcześniejsze lub późniejsze oddzielenie tych wartości.

Innym podejściem jest grupą bezpośrednio przez funkcję kolumny datetime:

dfrm.groupby(
    by=dfrm.dt.map(lambda x: (x.year, x.month)) 
).apply(lambda x: x.sort('dt', ascending=True).head(1)) 

Zwykle te problemy pojawiają się ze względu na patologicznej bazy danych lub przechowywania danych schematu że istnieje jeden poziom przed warstwy python/PANDAS.

Na przykład w tej sytuacji powinieneś polegać na istnieniu tabeli z danymi kalendarza lub zestawu danych kalendarza zawierającego (lub ułatwiającą zapytanie) najwcześniejszą aktywną datę w miesiącu w stosunku do dany zbiór danych (taki jak pierwszy dzień handlowy, pierwszy dzień tygodnia, pierwszy dzień roboczy, pierwsze święto lub cokolwiek innego).

Jeśli istnieje tabela towarzysząca dla tych danych, powinno być łatwo połączyć ją z zestawem danych, który już załadowałeś (powiedzmy, łącząc się z kolumną daty, którą już masz), a następnie jest to tylko kwestia zastosowania filtr logiczny w kolumnach danych kalendarza.

Staje się to szczególnie ważne, gdy trzeba korzystać z opóźnień czasowych: na przykład zestawienie wartości rynkowej spółki 1-miesięcznej z obecnym zyskiem ze sprzedaży w bieżącym miesiącu w celu obliczenia całkowitego zwrotu zrealizowanego w ciągu tego 1 miesiąca Kropka.

Ten może być wykonane przez tyle kolumn w pand z shift lub staramy się robić skomplikowane samosprzężenie że prawdopodobnie bardzo bug podatna i stwarza problem utrwalenia konkretnej daty konwencję do każdego miejsca downstream, który wykorzystuje dane z tego kodu.

Znacznie lepiej jest po prostu żądać (lub robić to samemu), że dane muszą poprawnie znormalizować funkcje daty w ich nieprzetworzonym formacie (baza danych, pliki płaskie, cokolwiek) i aby zatrzymać to, co robisz, najpierw napraw to problem z datą, i dopiero wtedy wróć do przeprowadzenia analizy z danymi daty.

+1

Uwaga: w wersji 0.15.0+ możesz utworzyć te kolumny za pomocą 'df.SomeDatetimeColumn.dt.hour'. –

+0

Tak, to ważna uwaga. Dziękuję Ci! – ely

0
import pandas as pd 
dates = pd.date_range('2014-02-05', '2014-03-15', freq='D') 
df = pd.DataFrame({'vals': range(len(dates))}, index=dates) 
g = df.groupby(lambda x: x.strftime('%Y-%m'), axis=0) 
g.apply(lambda x: x.index.min()) 
#Or depending on whether you want the index or the vals 
g.apply(lambda x: x.ix[x.index.min()]) 
0

Powyższe nie działa dla mnie, bo potrzeba więcej niż jeden wiersz miesięcznie, gdy liczba wierszy w każdym miesiącu może się zmienić. Oto co zrobiłem:

dates_month = pd.bdate_range(df['date'].min(), df['date'].max(), freq='1M') 
df_mth = df[df['date'].isin(dates_month)] 
Powiązane problemy