2016-03-18 8 views
1

Я написал беспорядочную функцию, которая вычисляет количество лет в фрейме данных на основе его длины (при условии, что dataframe имеет значения для каждого дня года).Расчет количества лет в кадре данных pandas

Он отлично работает, но это очень много кода, который можно было бы сделать гораздо умнее (но я не знаю, как ...)

Вот функция, она идет только до 10 лет, я хочу он работает для набора данных любого размера. Я мог бы расширить его дальше, копируя и вставляя и добавляя итоговые данные дальше, но должен быть более умный способ написать этот код.

def numyears(x): 
    if len(x.index) <= 366: 
     return 1 
    elif len(x.index) <= 732: 
     return 2 
    elif len(x.index) <= 1098: 
     return 3 
    elif len(x.index) <= 1464: 
     return 4 
    elif len(x.index) <= 1830: 
     return 5 
    elif len(x.index) <= 2196: 
     return 6 
    elif len(x.index) <= 2562: 
     return 7 
    elif len(x.index) <= 2928: 
     return 8 
    elif len(x.index) <= 3294: 
     return 9 
    elif len(x.index) <= 3660: 
     return 10 
    else: 
     return 'ERROR' 
+0

У вас есть временные метки или любые значения даты-времени, связанные с индексом или значений строк? – EdChum

+0

Да значения строк имеют связанный с ними объект datetime – Pad

+0

Итак, это столбец или это индекс? – EdChum

ответ

3

кажется более разумным, чтобы просто иметь доступ к атрибуту year, а затем просто получить len уникальных значений:

In [2]: 
s = pd.date_range(dt.datetime(1900,1,1), end=dt.datetime(2000,1,1), freq='6M') 
s 

Out[2]: 
DatetimeIndex(['1900-01-31', '1900-07-31', '1901-01-31', '1901-07-31', 
       '1902-01-31', '1902-07-31', '1903-01-31', '1903-07-31', 
       '1904-01-31', '1904-07-31', 
       ... 
       '1995-01-31', '1995-07-31', '1996-01-31', '1996-07-31', 
       '1997-01-31', '1997-07-31', '1998-01-31', '1998-07-31', 
       '1999-01-31', '1999-07-31'], 
       dtype='datetime64[ns]', length=200, freq='6M') 

In [8]: 
len(np.unique(s.year)) 

Out[8]: 
100 

таким образом она обрабатывает нечастые периоды, пропущенные дни, записи, которые перекрывают год границы и т.д.

Вы также можете преобразовать индекс к Series и называют nunique:

In [11]: 
s.to_series().dt.year.nunique() 

Out[11]: 
100 

Видя, как у вас уже есть DateTime как столбец, то только это будет работать:

df['date_col'].dt.year.nunique() 

При необходимости можно преобразовать в дату с помощью:

df['date_col'] = pd.to_datetime(df['date_col']) 

UPDATE

поэтому, похоже, ваше требование состоит в том, чтобы засчитывать полные годы, если вы установите индекс в компонент год и день, тогда вы можете рассчитывать на уровне года, а затем отфильтровать строки, которые не> = 365, чтобы дать вам количество полных лет:

In [34]: 
df = pd.DataFrame({'date':pd.date_range(dt.datetime(1900,6,1), end=dt.datetime(1910,6,1))}) 
count = df.set_index([df['date'].dt.year, df['date'].dt.day]).count(level=0) 
count 

Out[34]: 
     date 
date  
1900 214 
1901 365 
1902 365 
1903 365 
1904 366 
1905 365 
1906 365 
1907 365 
1908 366 
1909 365 
1910 152 

In [39]: 
len(count[count >= 365].dropna()) 

Out[39]: 
9 
+0

Это определенно правильный способ сделать это, если DataFrame имеет даты, но если он по какой-то причине является просто последовательным, не привязанным по времени, он явно не работает. – Paul

+0

@Paul, пожалуйста, объясните, как это не будет работать для временных меток – EdChum

+0

Я думаю, что он говорил, что это не сработает, если они не являются отметками времени – sedavidw

4

разделите длину индекса на 365

def numyears(x): 
    return len(x.index)/365 # use // for python 3 

Как написано это будет делать целочисленное деление и соответствует выходу, здесь. Это будет масштабировать кадр данных любого размера

EDIT Вышеупомянутое решение принимает подход к полу, после повторного чтения сообщения, ОП использовал потолочный подход. Для этого

return len(x.index)/365 + 1 
+1

Есть 365 дней в году, за исключением високосных лет – sedavidw

+0

Не могу поверить, что я этого не видел. Спасибо за помощь! – Pad

+1

Изменить '/' на '//' для Python 3. – ayhan

1

Вы можете создать набор из всех лет, а затем возвращает его длину.

import numpy as np 
import pandas as pd 

df = pd.DataFrame(np.random.randn(365*10, 3), 
        columns=list('ABC'), 
        index=pd.date_range('2000-1-1', periods=365*10)) 

# Number of unique years 
>>> len(set(ts.year for ts in df.index)) 
10 

Если индекс имеет тип DateTime или строки, сначала необходимо преобразовать его в Timestamp:

>>> len(set(ts.year for ts in pd.to_datetime(df.index))) 
10 
Смежные вопросы