2015-07-09 2 views
1

Это общий вопрос о том, как эффективно применять функцию в пандах. Я часто сталкиваюсь с ситуациями, когда мне нужно применить функцию к pd.Series, и было бы быстрее применить эту функцию только к уникальным значениям.Применение функции к уникальным значениям эффективности в pandas

Например, предположим, что у меня очень большой набор данных. Один столбец - date, и я хочу добавить столбец, который дает последнюю дату квартала для date. Я бы сделал это:

mf['qtr'] = pd.Index(mf['date']) + pd.offsets.QuarterEnd(0) 

Но для больших наборов данных это может занять некоторое время. Таким образом, чтобы ускорить его, я извлечь уникальные значения из date, применить функцию к тем, а затем объединить его обратно в исходные данные:

dts = mf['date'].drop_duplicates() 
eom = Series(pd.Index(dts) + pd.offsets.QuarterEnd(0), index=dts) 
eom.name = 'qtr' 
mf = pd.merge(mf, eom.reset_index()) 

Это может быть намного быстрее, чем однострочника выше.

Итак, вот мой вопрос: это действительно правильный способ делать такие вещи, или есть лучший подход?

И было бы целесообразно добавить функцию к пандам, которая автоматически применила бы этот уникальный подход/применение/слияние? (Это не сработало бы для определенных функций, таких как те, которые полагаются на скользящие данные, поэтому, вероятно, пользователь должен будет явно запросить такое поведение.)

+0

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

+1

FWIW, вот некоторые примеры данных, для которых способ слияния примерно в два раза быстрее меня: 'mf = pd.DataFrame ({'date': np.random.choice (pd.date_range ('1/1/2011', периоды = 365, частота = 'D'), 900)}) ' – JohnE

+0

Почему вы не группируете дату и не вызываете свою функцию в группах? – EdChum

ответ

1

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

mf.groupby('date',as_index=False)['date'].apply(lambda x: x + pd.offsets.QuarterEnd(0)) 

Я думаю, что должен работать

EDIT

OK выше не работает, но в следующем же, но я думаю, что это немного скрученные:

mf.groupby('date', as_index=False)['date'].apply(lambda x: (pd.Index(x)+ QuarterEnd(0))[0]) 

мы создаем datetimeindex для каждой даты, добавить смещение, а затем получить доступ к одного элемента, чтобы вернуть значение, но лично я думаю, что это не здорово.

+0

Спасибо, но это дает 'TypeError: не может использовать не абсолютный DateOffset в операциях datetime/timedelta [<0 * QuarterEnds: StartingMonth = 3>]'. Это потому, что 'date' не является индексом? – itzy

+0

Не уверен, что вы могли бы попробовать 'mf.groupby ('date', as_index = False) ['date']. Apply (lambda x: pd.Index (x) + pd.offsets.QuarterEnd (0))' this isn ' t ideal, хотя – EdChum

+0

На самом деле вы можете попробовать 'из pandas.tseries.offsets import * mf.groupby ('date', as_index = False) ['date'].apply (lambda x: x + QuarterEnd (0)) ' – EdChum

Смежные вопросы