Pandas 使用开始日期重新采样
Pandas resample with start date
我想使用特定日期(或月份)作为第一个 bin 的边缘对 pandas 对象重新采样。例如,在下面的代码片段中,我希望我的第一个索引值是 2020-02-29
并且我很乐意指定 start=2
或 start="2020-02-29"
.
>>> dates = pd.date_range("2020-01-29", "2021-07-04")
>>> s = pd.Series(range(len(dates)), index=dates)
>>> s.resample('4M').count()
2020-01-31 3
2020-05-31 121
2020-09-30 122
2021-01-31 123
2021-05-31 120
2021-09-30 34
Freq: 4M, dtype: int64
到目前为止,这是我能想到的最干净的用法 pd.cut
和 groupby
:
>>> rule = "4M"
>>> start = pd.Timestamp("2020-02-29") - pd.tseries.frequencies.to_offset(rule)
>>> end = s.index.max() + pd.tseries.frequencies.to_offset(rule)
>>> bins = pd.date_range(start, end, freq=rule)
>>> gb = s.groupby(pd.cut(s.index, bins)).count()
>>> gb.index = gb.index.categories.right
>>> gb
2020-02-29 32
2020-06-30 122
2020-10-31 123
2021-02-28 120
2021-06-30 122
2021-10-31 4
dtype: int64
您只需使用 pd.cut
,如下所示:
>>> gb = pd.cut(s.index, bins).value_counts()
>>> gb.index = gb.index.categories.right
>>> gb
2020-02-29 32
2020-06-30 122
2020-10-31 123
2021-02-28 120
2021-06-30 122
2021-10-31 4
dtype: int64
不需要使用groupby
我的回答感觉有点老套,但使用 resample
并给出了所需的输出。找到指定日期前一个 bin 长度的日期(例如 4 个月,或者特别是月末),将其附加到 s
,然后 resample
:
rule = '4M'
date = '02-29-2020'
base_date = pd.to_datetime(date) - pd.tseries.frequencies.to_offset(rule)
s.loc[base_date] = np.nan
output = s.resample(rule=rule).count()
output=output[output.index >= date]
结果:
2020-02-29 32
2020-06-30 122
2020-10-31 123
2021-02-28 120
2021-06-30 122
2021-10-31 4
Freq: 4M, dtype: int64
我添加了 output=output[output.index >= date]
b/c 否则你会得到一个额外的空容器:
2019-10-31 0
2020-02-29 32
2020-06-30 122
2020-10-31 123
2021-02-28 120
2021-06-30 122
2021-10-31 4
Freq: 4M, dtype: int64
处理月间隔的另一种方法是将日期时间索引从年和月转换为整数,删除 start_date 定义的值和规则中的一些模值。在 groupby 中使用它。
rule = '4M'
start = "2020-02-29"
# change types of value
d = pd.Timestamp(start)
nb = int(rule[:-1])
gr = s.groupby(d+(1+((s.index.year*12+s.index.month) #convert datetime index to int
-(d.year*12+d.month+1))//nb) # remove start and modulo rule
*pd.tseries.frequencies.to_offset(rule) # get rule freq
).count()
print (gr)
2020-02-29 32
2020-06-30 121
2020-10-31 123
2021-02-28 120
2021-06-30 122
2021-10-31 4
dtype: int64
现在与您的方法相比,假设您定义了一个日期,您希望它不在您的规则定义的前 X 个月内,例如使用相同规则 (4M) 的 2020-07-31。使用这种方法,它给出:
2020-03-31 63 #you get this interval
2020-07-31 121
2020-11-30 122
2021-03-31 121
2021-07-31 95
dtype: int64
使用您的方法,您将获得:
2020-07-31 121 #you loose info from before the 2020-03-31
2020-11-30 122
2021-03-31 121
2021-07-31 95
dtype: int64
我知道你在问题中说你定义了第一个日期,但是使用这种方法你可以定义任何日期,只要规则是在月份
这不是原始答案,而是将@ALollz(评论)和@MhdMedf(答案)的改进组合成一个清晰的答案,因为它们代表了兼容的改进。另请参阅下面的时间说明。
rule = "4M"
start = pd.Timestamp("2020-02-29") - pd.tseries.frequencies.to_offset(rule)
end = s.index.max() + pd.tseries.frequencies.to_offset(rule)
bins = pd.date_range(start, end, freq=rule)
gb = pd.cut(s.index, bins, labels=bins[1:]).value_counts()
(上面的最后一行替换了 OP 中答案的最后两行。前四行没有变化,但为了清楚起见包含在这里。)
结果:
2020-02-29 32
2020-06-30 122
2020-10-31 123
2021-02-28 120
2021-06-30 122
2021-10-31 4
Speed/timing:考虑到只有 524 行(在我的机器上为 6 毫秒),OP 中的代码花费了相当多的时间。使用 OP 数据,这两项改进结合起来可实现大约 3 倍的加速。当然,在更大的 series/dataframe 上,计时结果可能与此处看到的结果大不相同。
我想使用特定日期(或月份)作为第一个 bin 的边缘对 pandas 对象重新采样。例如,在下面的代码片段中,我希望我的第一个索引值是 2020-02-29
并且我很乐意指定 start=2
或 start="2020-02-29"
.
>>> dates = pd.date_range("2020-01-29", "2021-07-04")
>>> s = pd.Series(range(len(dates)), index=dates)
>>> s.resample('4M').count()
2020-01-31 3
2020-05-31 121
2020-09-30 122
2021-01-31 123
2021-05-31 120
2021-09-30 34
Freq: 4M, dtype: int64
到目前为止,这是我能想到的最干净的用法 pd.cut
和 groupby
:
>>> rule = "4M"
>>> start = pd.Timestamp("2020-02-29") - pd.tseries.frequencies.to_offset(rule)
>>> end = s.index.max() + pd.tseries.frequencies.to_offset(rule)
>>> bins = pd.date_range(start, end, freq=rule)
>>> gb = s.groupby(pd.cut(s.index, bins)).count()
>>> gb.index = gb.index.categories.right
>>> gb
2020-02-29 32
2020-06-30 122
2020-10-31 123
2021-02-28 120
2021-06-30 122
2021-10-31 4
dtype: int64
您只需使用 pd.cut
,如下所示:
>>> gb = pd.cut(s.index, bins).value_counts()
>>> gb.index = gb.index.categories.right
>>> gb
2020-02-29 32
2020-06-30 122
2020-10-31 123
2021-02-28 120
2021-06-30 122
2021-10-31 4
dtype: int64
不需要使用groupby
我的回答感觉有点老套,但使用 resample
并给出了所需的输出。找到指定日期前一个 bin 长度的日期(例如 4 个月,或者特别是月末),将其附加到 s
,然后 resample
:
rule = '4M'
date = '02-29-2020'
base_date = pd.to_datetime(date) - pd.tseries.frequencies.to_offset(rule)
s.loc[base_date] = np.nan
output = s.resample(rule=rule).count()
output=output[output.index >= date]
结果:
2020-02-29 32
2020-06-30 122
2020-10-31 123
2021-02-28 120
2021-06-30 122
2021-10-31 4
Freq: 4M, dtype: int64
我添加了 output=output[output.index >= date]
b/c 否则你会得到一个额外的空容器:
2019-10-31 0
2020-02-29 32
2020-06-30 122
2020-10-31 123
2021-02-28 120
2021-06-30 122
2021-10-31 4
Freq: 4M, dtype: int64
处理月间隔的另一种方法是将日期时间索引从年和月转换为整数,删除 start_date 定义的值和规则中的一些模值。在 groupby 中使用它。
rule = '4M'
start = "2020-02-29"
# change types of value
d = pd.Timestamp(start)
nb = int(rule[:-1])
gr = s.groupby(d+(1+((s.index.year*12+s.index.month) #convert datetime index to int
-(d.year*12+d.month+1))//nb) # remove start and modulo rule
*pd.tseries.frequencies.to_offset(rule) # get rule freq
).count()
print (gr)
2020-02-29 32
2020-06-30 121
2020-10-31 123
2021-02-28 120
2021-06-30 122
2021-10-31 4
dtype: int64
现在与您的方法相比,假设您定义了一个日期,您希望它不在您的规则定义的前 X 个月内,例如使用相同规则 (4M) 的 2020-07-31。使用这种方法,它给出:
2020-03-31 63 #you get this interval
2020-07-31 121
2020-11-30 122
2021-03-31 121
2021-07-31 95
dtype: int64
使用您的方法,您将获得:
2020-07-31 121 #you loose info from before the 2020-03-31
2020-11-30 122
2021-03-31 121
2021-07-31 95
dtype: int64
我知道你在问题中说你定义了第一个日期,但是使用这种方法你可以定义任何日期,只要规则是在月份
这不是原始答案,而是将@ALollz(评论)和@MhdMedf(答案)的改进组合成一个清晰的答案,因为它们代表了兼容的改进。另请参阅下面的时间说明。
rule = "4M"
start = pd.Timestamp("2020-02-29") - pd.tseries.frequencies.to_offset(rule)
end = s.index.max() + pd.tseries.frequencies.to_offset(rule)
bins = pd.date_range(start, end, freq=rule)
gb = pd.cut(s.index, bins, labels=bins[1:]).value_counts()
(上面的最后一行替换了 OP 中答案的最后两行。前四行没有变化,但为了清楚起见包含在这里。)
结果:
2020-02-29 32
2020-06-30 122
2020-10-31 123
2021-02-28 120
2021-06-30 122
2021-10-31 4
Speed/timing:考虑到只有 524 行(在我的机器上为 6 毫秒),OP 中的代码花费了相当多的时间。使用 OP 数据,这两项改进结合起来可实现大约 3 倍的加速。当然,在更大的 series/dataframe 上,计时结果可能与此处看到的结果大不相同。