循环遍历熊猫数据框
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 工具(包括 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')
【讨论】:
嗨@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 循环中打印 start
和 end
以显示这一点。
感谢您的回复。我完全理解通过更改 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 个日期(例如,最早的月份)并添加另一个数据(例如,下个月)以上是关于循环遍历熊猫数据框的主要内容,如果未能解决你的问题,请参考以下文章