循环遍历熊猫数据框

Posted

技术标签:

【中文标题】循环遍历熊猫数据框【英文标题】:Looping through pandas dataframe 【发布时间】:2020-11-20 16:05:34 【问题描述】:

数据框:

       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 行)。但是,通过这种方式,我既不是按日期选择窗口,也不是删除最后一个数据点并添加下一个数据点。我还没有弄清楚该怎么做。如果有人有可能的解决方案/建议,将不胜感激! 谢谢!

【问题讨论】:

pd.Period()pd.PeriodIndex() 对于制作这个 3 个月的滑动窗口很有用;见pandas.pydata.org/pandas-docs/stable/reference/api/… 这听起来很有趣,谢谢我去看看! 【参考方案1】:

这是一种方法。首先构建一个数据框:

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 工具(包括 groupbyrolling)来避免遍历数据框。

更新:

我们可以控制一个窗口的长度,以及从一个窗口开始到下一个窗口开始的时间:

# 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')

【讨论】:

嗨@jsmart,我非常喜欢你的方法,非常清晰有用,谢谢! 我有最后一个问题:假设我设置 months_in_window = 15 所以它会返回 2015-01 ... 2016-03 然后将循环删除/添加 1个月。如果我想删除/添加超过 1 个月(例如,假设 3 个月),例如:df1 将是 2015-01 ... 2016-03 ,则 df2 将是 2015-04 ... 2016-06,然后 df3 将是 2015-07 ... 2016-09 等等...。有没有办法做到这一点?我想我们必须对 --> mask = (start 进行一些更改。如果您对如何操作有任何想法,请告诉我,谢谢! 这个版本有months_in_window = 2——所以每个窗口都有2个月的1月+2月;二月+三月;三月+四月; .... 只需将months_in_window 更改为 3,您将获得 Jan+Feb+March;二月+三月+四月; ...此外,您可以在 for 循环中打印 startend 以显示这一点。 感谢您的回复。我完全理解通过更改 monts_in_window 您可以根据需要确定月数。但是,无论我们选择什么窗口大小,循环都会在每个新的 df 上仅添加 1 个月。因此,我现在的问题是,如果我设置 **monts_in_window = 5 即 Jan+Feb+Mar+Apr+May,那么对于这个版本,下一个 df 将是 Feb+Mar+Apr+May-Jun。但是,如果我希望它是 Mar+Apr+May+July+Jul,因此 每次删除并添加 2 个月(而不仅仅是 1 个月),是否可以通过修改您的版本来实现?跨度> 让我们从zip(XS, YS) 开始,其中 XS 和 YS 是可迭代的(不一定是相同的长度)。在这种情况下,zip 产生一个元组序列(例如,(x[0], y[0]), (x[1], y[1]), ... 当shortest iterable 已用尽。下面是代码中的一个简短示例:ns = [1, 2, 3, 4, 5]; for x, y in zip(ns, ns[1:]): print(x, y)。关键是要了解 zip 在这种情况下是如何工作的。这有帮助吗?【参考方案2】:

如果我理解正确,您希望循环遍历数据框并每次获取 4 行的块。您可以尝试这样的方法并根据需要进行调整:

首先按日期对数据框进行排序。为此,您可以使用sort_values 函数:

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

请注意,如果您的日期列的日期时间格式不正确,那么您需要在排序之前这样做:

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

【讨论】:

感谢您的建议。如果您想按行选择数据并遍历长度,我会得到您的方法,该方法可以正常工作。但是,我想使用类似的方法,而是选择日期(月份)并遍历数据帧长度(例如,固定窗口 Jan、Feb、March,然后删除 Jan 并添加 Apr 等。直到数据帧结束)。关于如何使用日期选择自定义样品的任何建议?谢谢你! 所以您想按日期时间列对 df 进行排序,然后对其进行迭代并获得一个块? 好吧抱歉,我不是很清楚。您建议按日期对数据框进行排序(已正确排序,因此我们不需要它),然后执行 for 循环选择多行(在您的示例中为 4)。谢谢,但是,这不是我想要的 我想选择日期(而不是行)并遍历所选日期的所有值。然后,做一个滑动窗口删除 1 个日期(例如,最早的月份)并添加另一个数据(例如,下个月)

以上是关于循环遍历熊猫数据框的主要内容,如果未能解决你的问题,请参考以下文章

如何循环遍历熊猫数据框,并有条件地将值分配给变量的一行?

循环遍历熊猫中的行[重复]

如何在循环中附加多个熊猫数据框?

如何循环遍历熊猫分组的时间序列?

一个接一个地循环数据帧(熊猫)

循环遍历层后附加熊猫数据帧