2014-09-10 5 views
2

Мне нужно отрезать несколько интервалов из одного кадра данных с индексом Freq: 120T. Дата начала каждого из требуемых интервалов задается вторым фреймом данных, индексированным с помощью Freq: None. Идея состоит в том, что мне нужно взять каждую из этих дат начала и включить время и количество периодов для каждого интервала. Атрибут времени и периоды одинаковы для всех интервалов.Продвинутая нарезка интервалов в Pandas Dataframe

Давайте посмотрим на этом бардаке с примером

Скажет наше время начала '18: 00: 00' и наши # периодов равен 3. dataframe быть раздробленным является df1 и dataframe, который содержит начало даты - df2.

df1

     A B  
DateTime            
2005-09-06 16:00:00 1 5 
2005-09-06 18:00:00 2 6 
2005-09-06 20:00:00 3 7 
2005-09-06 22:00:00 4 8 
2005-12-07 16:00:00 9 8 
2005-12-07 18:00:00 7 6 
2005-12-07 20:00:00 5 4 
2005-12-07 22:00:00 3 2 

<class 'pandas.tseries.index.DatetimeIndex'> 
[2005-09-06 16:00:00, ..., 2005-12-07 22:00:00] 
Length: 8, Freq: 120T, Timezone: None 

df2

   Num 
DateTime                  
2005-09-07  1 
2005-12-07  2 

<class 'pandas.tseries.index.DatetimeIndex'> 
[2005-09-07, 2005-12-07] 
Length: 2, Freq: None, Timezone: None 

Желаемая Выход:

df3 = func(source=df1['B'], start_dates=df2.index, time_start='18:00:00', periods=3) 

      1 2 
18:00:00 6 6 
20:00:00 7 4 
22:00:00 8 2 

Что я сделал и соображения:

Одна из трудностей состоит в том, что данные в df1 находится на частоте 120T, но это только рабочие дни. Принимая это во внимание, я хотел бы сделать что-то вроде этого:

start = df2.index[0] ## And somehow add to this formula the fact that we want to start at   
          '18:00' 
df3 = df1['B'][(df1.index > start) & (df1.index < start + 3)] ## Somehow iterate this over the 
                    dates in the df2 index 

Я ценю любой проницательности

Заранее спасибо

+0

Вы можете привести небольшой пример, чтобы проиллюстрировать это, пример с 39433 вводами кажется немного экстремальным (я не следую тому, что вы пытаетесь сделать)! –

+0

@ Энди Хайден Вы можете игнорировать это число. Упрощенным примером может быть, если df1 содержит 8 строк примера. Я пытаюсь извлечь фрагменты df1, учитывая отметку времени начала df2. Дайте мне знать, если это более ясно. Спасибо – hernanavella

+0

спасибо, это намного проще. Я до сих пор не вижу, как вы получаете df3 из df1 и df2, но, возможно, для меня уже слишком поздно! –

ответ

1

Совершенно иной подход:

def next_n_asof(x, t, n): 
    """The next n rows after time t in x 
    """ 
    i = np.argmax(df.index >= t) 
    return x[i:i + n] 

In [11]: next_n_asof(df.B, pd.Timestamp('2005-09-06 18:00:00'), 3) 
Out[11]: 
2005-09-06 18:00:00 6 
2005-09-06 20:00:00 7 
2005-09-06 22:00:00 8 
Name: B, dtype: int64 

Мы можем использовать это в CONCAT на каждый день в индексе:

In [12]: pd.concat(next_n_asof(df.B, t, 3) 
        for t in df2.index + pd.tseries.timedeltas.to_timedelta(18, unit='h')) 
Out[12]: 
2005-09-06 18:00:00 6 
2005-09-06 20:00:00 7 
2005-09-06 22:00:00 8 
2005-12-07 18:00:00 6 
2005-12-07 20:00:00 4 
2005-12-07 22:00:00 2 
Name: B, dtype: int64 

нам пришлось добавить время к датам в df2. индекс:

In [13]: df2.index + pd.tseries.timedeltas.to_timedelta(18, unit='h') 
Out[13]: 
<class 'pandas.tseries.index.DatetimeIndex'> 
[2005-09-06 18:00:00, 2005-12-07 18:00:00] 
Length: 2, Freq: None, Timezone: None 

Примечание: Я не мог получить эту работу cleanl y с самим asof ... что может быть более эффективным.

+0

Это работает, спасибо за ваши усилия. Это был грязный вопрос. Теперь мне просто нужно взять df и повернуть его. – hernanavella

+0

Когда я меняю частоту df, от 1 до 2 часов, функция тормозит вниз и дает мне и пустой фрейм данных.Я не могу понять, как сделать его гибким для частоты df. Любые подсказки? – hernanavella

+0

@hernanavella не совсем уверен, как вы видите, что это не использует частоту где-нибудь? –

2

Вы ищете pivot ... по крайней мере, один раз вы извлекли строки вы заинтересованы в

Те, что на ту же дату, используйте normalize и isin:.

In [11]: res = df.loc[df.index.normalize().isin(df2.index), 'B'] 

In [12]: res 
Out[12]: 
2005-09-06 16:00:00 5 
2005-09-06 18:00:00 6 
2005-09-06 20:00:00 7 
2005-09-06 22:00:00 8 
2005-12-07 16:00:00 8 
2005-12-07 18:00:00 6 
2005-12-07 20:00:00 4 
2005-12-07 22:00:00 2 
Name: B, dtype: int64 

Как только он находится в этой форме, откройте (если, вероятно, будут отсутствовать данные, возможно, вам придется использовать pivot_table, что немного более гибко)!

In [14]: pd.pivot(res.index.time, res.index.normalize(), res.values) 
Out[14]: 
      2005-09-06 2005-12-07 
16:00:00   5   8 
18:00:00   6   6 
20:00:00   7   4 
22:00:00   8   2 

«мясо» выбора строк с помощью ISIN, проверяя, если время, нормированное к полуночи, содержится в df2.index.

df.index.normalize().isin(df2.index) 

Если мы заботимся о времени, мы можем использовать indexer_between_time:

In [15]: df.ix[df.index.indexer_between_time('18:00', '00:00'), 'B'] 
Out[15]: 
2005-09-06 18:00:00 6 
2005-09-06 20:00:00 7 
2005-09-06 22:00:00 8 
2005-12-07 18:00:00 6 
2005-12-07 20:00:00 4 
2005-12-07 22:00:00 2 
Name: B, dtype: int64 

Хорошо, в этом примере, это те же (как есть только даты, которые мы хотим!), но в целом вы действительно хотите, оба эти условия (к «и» их) ...

# I had tried to make this a one-liner but utterly failed! 
in_time = np.zeros(len(df), dtype=bool) 
in_time[df.index.indexer_between_time('18:00', '00:00')] = True 
res = df.loc[df.index.normalize().isin(df2.index) & in_time, 'B'] 

In [17]: res 
Out[17]: 
2005-09-06 16:00:00 5 
2005-09-06 18:00:00 6 
2005-09-06 20:00:00 7 
2005-09-06 22:00:00 8 
2005-12-07 16:00:00 8 
2005-12-07 18:00:00 6 
Name: B, dtype: int64 

Вы можете отобразить столбцы шарнирного результата:

In [21]: pv = pd.pivot(res.index.time, res.index.normalize(), res.values) 

In [22]: pv 
Out[22]: 
      2005-09-06 2005-12-07 
18:00:00   6   6 
20:00:00   7   4 
22:00:00   8   2 

In [23]: pv.columns = pv.columns.map(df2.Num.get) 

In [24]: pv 
Out[24]: 
      1 2 
18:00:00 6 6 
20:00:00 7 4 
22:00:00 8 2 

вуаля.

+0

Это решение почти идеально. Есть одна проблема, помните, что в вопросе я упомянул, что мне нужно указать час (который вы указали) и период. Почему период ?, потому что интервалы могут быть многодневными и потому, что данные находятся в рабочие дни или имеют некоторые недостающие данные между ними. Мне кажется, что, используя «между_time», код оптимизирован для работы «внутри дня». Прости, если это боль в заднице. Я попытался выразить эту озабоченность в вопросе, а также предложил упрощенный пример. Возможно, мне это не удалось. Я ценю, если вы сможете обновить ответ. – hernanavella

+0

@hernanavella это на самом деле не внутри дня, вы можете делать между 18:00 и 02:00. Не совсем уверен, что я буду следовать за вами. Я думаю, вы хотите, чтобы вы выбрали следующее (?) Время после даты и времени dt (для нескольких дат с одинаковым временем начала), а затем выберите последующие N записей (включительно)? Вы можете сделать это с .asof, если это то, что вы имеете в виду. –

+0

Да, последующие N записей. Если вы заметили в примере, мы сказали, что начинаем с '18: 00 'и включаем еще 3 записи включительно, чтобы вы схватили с '18: 00' до '22: 00. В сценарии, который вы написали, как я могу сказать функции хватит, скажем, последующие 36 записей? – hernanavella

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