Цикл через фрейм данных pandas

Фрейм данных:

       date      A    B    C    D
index
0      2015-01   ..   ..   ..   ..
1      2015-01   ..   ..   ..   ..
2      2015-02   ..   ..   ..   ..
3      2015-02   ..   ..   ..   ..
4      2015-03   ..   ..   ..   ..
5      2015-03   ..   ..   ..   ..
6      2015-04   ..   ..   ..   ..
7      2015-04   ..   ..   ..   ..
8      2015-05   ..   ..   ..   ..
9      2015-05   ..   ..   ..   ..
...
1000   ...       ..   ..   ..   ..

Я хочу выполнить итерацию, используя дату (pd.to_datetime), начиная с фиксированного окна (например, первые три месяца [2015-01, 2015-01, 2015-02, 2015-02, 2015-03, 2015-03]) и возврат фрейма данных:

       date      A    B    C    D
index
0      2015-01   ..   ..   ..   ..
1      2015-01   ..   ..   ..   ..
2      2015-02   ..   ..   ..   ..
3      2015-02   ..   ..   ..   ..
4      2015-03   ..   ..   ..   ..
5      2015-03   ..   ..   ..   ..

Затем добавляем следующий месяц [2015-04, 2015-04] и удаляем самый старый [2015-01, 2015-01], возвращая следующий фрейм данных:

       date      A    B    C    D
index
2      2015-02   ..   ..   ..   ..
3      2015-02   ..   ..   ..   ..
4      2015-03   ..   ..   ..   ..
5      2015-03   ..   ..   ..   ..
6      2015-04   ..   ..   ..   ..
7      2015-04   ..   ..   ..   ..

Продолжая это до конца данных.

Я выяснил следующий код:

periods = len(dataframe)
fxw = 3

for i in range(0, periods):
    start = i                       
    if i + fxw > periods:              
       break
    else: end_df = i + fxw
 
# output:
 
# df1
       date      A    B    C    D
index
0      2015-01   ..   ..   ..   ..
1      2015-01   ..   ..   ..   ..
2      2015-02   ..   ..   ..   ..

# df2
       date      A    B    C    D
index
3      2015-02   ..   ..   ..   ..
4      2015-03   ..   ..   ..   ..
5      2015-03   ..   ..   ..   ..
 
...
# dfend 

Где я могу установить фиксированное окно (fxw = 3) для итерации по длине фрейма данных 3 строки за раз до конца данных. (например, если фрейм данных имеет 12 строк, он вернет 4 фрейма данных по 3 строки в каждом). Однако таким образом я не выбираю окно по дате и не удаляю последнюю точку данных и не добавляю следующую. Я пока не придумал, как это сделать. Если у кого-то есть возможное решение / предложение, мы будем очень признательны! Спасибо!


person LouiseLop    schedule 30.07.2020    source источник
comment
И pd.Period(), и pd.PeriodIndex() были бы полезны для создания этого трехмесячного скользящего окна; см. pandas.pydata.org/pandas-docs/stable / reference / api /   -  person jsmart    schedule 31.07.2020
comment
Звучит интересно, спасибо, посмотрю!   -  person LouiseLop    schedule 31.07.2020


Ответы (2)


Вот один способ. Начнем с создания фрейма данных:

import numpy as np
import pandas as pd

date = [ f'2015-{i:02d}' for i in range(1, 7) ]
date = np.repeat(date, 2)
date = [pd.Period(d) for d in date]

n = len(date)
amt = [10 * i for i in range(n)]

df = pd.DataFrame({'date': date, 'amt': amt})

print(df.head())

Затем создайте диапазон периодов, используя минимальную и максимальную даты из фрейма данных:

period_range = pd.period_range(start=df['date'].min(), 
                               end=df['date'].max(), 
                               freq='M')

Теперь перебираем фрейм данных:

months_in_window = 2

for start, end in zip(period_range, period_range[months_in_window - 1: ]):
    mask = (start <= df['date']) & (df['date'] <= end)
    print(df[mask], end='\n\n')

      date  amt
0  2015-01    0
1  2015-01   10
2  2015-02   20
3  2015-02   30

      date  amt
2  2015-02   20
3  2015-02   30
4  2015-03   40
5  2015-03   50

<rest of output omitted to save space>

Часто можно использовать инструменты pandas (включая groupby и rolling), чтобы избежать итерации по фрейму данных.

ОБНОВИТЬ:

Мы можем контролировать как длину окна, так и время от начала одного окна до начала следующего:

# create list of periods
periods = pd.period_range(start='2020-01-01', periods=24, freq='M')

# create parameters
months_in_window = 3   # start of window i to end of window i
step = 5               # start of window i to start of window i+1

# create start and end points for each window
windows = [
    (start, end)
    for start, end 
        in zip(periods[::step], periods[window_size-1::step])
]

for w in windows: print(w)

(Period('2020-01', 'M'), Period('2020-03', 'M'))
(Period('2020-06', 'M'), Period('2020-08', 'M'))
(Period('2020-11', 'M'), Period('2021-01', 'M'))
(Period('2021-04', 'M'), Period('2021-06', 'M'))
(Period('2021-09', 'M'), Period('2021-11', 'M'))

Наконец, при повторении одного кадра данных выглядит так (без изменений в маске):

for start, end in windows:
    mask = (start <= df['date']) & (df['date'] <= end)
    print(df[mask], end='\n\n')
person jsmart    schedule 30.07.2020
comment
Привет, @jsmart, мне очень нравится ваш метод, очень понятный и полезный, спасибо! - person LouiseLop; 31.07.2020
comment
У меня есть последний вопрос: допустим, я установил months_in_window = 15, чтобы он возвращал 2015-01 ... 2016-03, а затем drop / add < / b> 1 месяц в цикле. Если я хочу удалить / добавить более 1 месяца (например, скажем, 3 месяца), например: df1 будет 2015-01 ... 2016-03 , тогда df2 будет 2015-04 ... 2016-06, тогда df3 будет 2015-07 ... 2016-09 и т. д. Есть способ сделать это? Думаю, нам придется внести некоторые изменения в - ›mask = (start‹ = df ['date']) & (df ['date'] ‹= end). Если у вас есть идея, как это сделать, дайте мне знать и поблагодарить вас! - person LouiseLop; 31.07.2020
comment
В этой версии есть months_in_window = 2 - так что в каждом окне 2 месяца Янв + Фев; Фев + март; Март + апрель; .... Просто измените months_in_window на 3, и вы получите январь + февраль + март; Фев + март + апрель; ... Кроме того, вы можете вывести start и end в цикле for, чтобы показать это. - person jsmart; 31.07.2020
comment
Спасибо за ваш ответ. Я прекрасно понимаю, что, изменив monts_in_window, вы можете зафиксировать количество месяцев как хотите. Однако какой бы размер окна мы ни выбрали, цикл будет пропадать и добавлять только 1 месяц для каждого нового df. Следовательно, теперь мой вопрос: если я установлю ** monts_in_window = 5, то есть январь + февраль + март + апр + май, то с этой версией следующим df будет февраль + март + апр + май-июнь. Но если я хочу, чтобы это было март + апр + май + июль + июль, поэтому убирая и добавляя 2 месяца за раз (а не только 1), возможно ли это, изменив вашу версию? - person LouiseLop; 31.07.2020
comment
Вот почему я упомянул, что мы можем внести некоторые изменения в - ›mask = (start‹ = df ['date']) & (df ['date'] ‹= end) для достижения мой желаемый результат. Спасибо за вашу помощь, и я надеюсь, что я был достаточно ясен :) - person LouiseLop; 31.07.2020
comment
zip() в обновлении выше управляет как размером окна, так и интервалом между началом последовательных окон. - person jsmart; 31.07.2020
comment
это более чем идеально! супер понятный и легко настраиваемый, очень хорошо с вами сделан и очень признателен за ваши усилия! - person LouiseLop; 31.07.2020
comment
Привет! Я пытаюсь понять логику zip (периоды [:: шаг], периоды [window_size-1 :: step]). Что касается периодов [:: step], правильно ли сказать, что для начала мы перескакиваем на «шаг», а затем заканчиваем на последней точке данных фрейма данных? А для периодов [window_size-1 :: step] как вы это интерпретируете? Спасибо! - person LouiseLop; 01.08.2020
comment
Начнем с zip(XS, YS), где XS и YS повторяются (не обязательно одинаковой длины). В этом случае zip создает последовательность кортежей (например, (x [0], y [0]), (x [1], y [1]), ...] и последовательность заканчивается (zip завершается), когда Самая короткая итерация исчерпана. Вот короткий пример кода: ns = [1, 2, 3, 4, 5]; for x, y in zip(ns, ns[1:]): print(x, y). Главное - понять, как zip работает в этом случае. Это поможет? - person jsmart; 01.08.2020
comment
Хорошо, теперь у меня есть это: programiz.com/python- программирование / методы / встроенный / zip было очень полезно для понимания! - person LouiseLop; 03.08.2020
comment
У меня есть более сложный вопрос, если я могу спросить: взяв в качестве примера приведенный выше пример с month_in_window = 3 и step = 5, скажем, для каждого нового окна, которое входит в цикл, я буду выполнять для него определенную функцию. Если я хочу измерить соответствующую продолжительность в процентах между 3 месяцами в окне и 5-ю ступенями (которые составляют 5 месяцев) по полному размеру окна (что, очевидно, будет 8 месяцев), и передать этот процент переменной (которая затем будет передана функции, которую я выполняю для каждого окна), есть ли способ автоматизировать это для каждого окна в zip ()? - person LouiseLop; 03.08.2020
comment
Я также сделал этот вопрос новым, доступным здесь: stackoverflow.com/questions/63230518/ Спасибо! - person LouiseLop; 03.08.2020

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

сначала отсортируйте фрейм данных по дате. Для этого вы можете использовать функцию sort_values:

df = your_df.sort_values(by='date') 

обратите внимание, если ваш столбец даты не в правильном формате datetime, вам нужно сделать это перед сортировкой:

your_df['date'] =pd.to_datetime(your_df.date)

тогда вы можете использовать цикл for

for i in range(0, len(df), 4): # the 4 here means return a chunk of 4 rows
    chunk = df.iloc[i:i+4, :]
    print(chunk)
    # do your magic
person basilisk    schedule 30.07.2020
comment
Спасибо за ваше предложение. Я получаю ваш метод, который отлично работает, если вы хотите выбирать данные по строкам и перебирать их по длине. Тем не менее, я хотел бы использовать аналогичный подход, но лучше выбрать дату (месяцы) и перебрать длину кадра данных (например, фиксированные окна января, февраля, марта, а затем отбросить январь и добавить апр и т. Д. До конца кадра данных ). Есть предложения о том, как настроить образец с выбором даты? Спасибо вам! - person LouiseLop; 31.07.2020
comment
Итак, вы хотите отсортировать df по столбцу datetime, а затем перебрать его и получить кусок? - person basilisk; 31.07.2020
comment
Ладно, извините, но я был не очень ясен. Вы предложили отсортировать фрейм данных по дате (который уже отсортирован правильно, поэтому он нам не нужен), а затем выполнить цикл for, выбрав количество строк (4 в вашем примере). Спасибо, но, тем не менее, это не то, что я ищу - person LouiseLop; 31.07.2020
comment
Я хочу выбрать дату (а не строки) и перебрать все значения выбранной даты. А затем, выполнив скользящее окно, отбрасывая 1 дату (например, самый старый месяц) и добавляя другие данные (например, следующий месяц) - person LouiseLop; 31.07.2020