创建一个新变量,它是python中另一个变量的每周最小值/最大值
Posted
技术标签:
【中文标题】创建一个新变量,它是python中另一个变量的每周最小值/最大值【英文标题】:Create a new variable which is weekly min/max values of another variable in python 【发布时间】:2019-05-13 14:08:48 【问题描述】:当列 A 的值在一周内最高时,如何将值 1 分配给变量 S?另外,当B的值是一周内的最小值时,如何将值2分配给变量S。我正在处理按日期时间索引的每小时数据。 这是我的数据框的样子:
A B S
datetime
6/14/2004 1:00 384.5 383.6 0
6/14/2004 2:00 384.3 382.3 0
6/14/2004 3:00 383.3 382.3 0
6/14/2004 4:00 383.3 382.6 0
6/14/2004 5:00 383.3 382.8 0
6/14/2004 6:00 383.3 382.5 0
6/14/2004 7:00 383.3 382.3 0
6/14/2004 8:00 383.8 382.3 0
6/14/2004 9:00 382.8 382.1 0
6/14/2004 10:00 382.6 382.1 0
我尝试过每周使用重采样并获得最大值,但我不知道如何编写代码,因为它比我最初想象的要复杂。 这是我希望我的最终数据看起来的样子。
A B S
datetime
6/14/2004 1:00 384.5 383.6 0
6/14/2004 2:00 384.3 382.3 0
6/14/2004 3:00 383.3 382.3 0
6/14/2004 4:00 383.3 382.6 0
6/14/2004 5:00 383.3 382.8 0
6/14/2004 6:00 383.3 382.5 0
6/14/2004 7:00 383.3 382.3 0
6/14/2004 8:00 383.8 382.3 0
6/14/2004 9:00 382.8 382.1 0
6/14/2004 10:00 382.6 382.1 0
6/14/2004 11:00 382.5 381.8 0
6/14/2004 12:00 382.8 382.3 0
6/14/2004 13:00 383.1 382.3 0
6/14/2004 14:00 385.8 382.5 0
6/14/2004 15:00 385.1 383.6 0
6/14/2004 16:00 384.8 383.5 0
6/14/2004 17:00 384.8 382.5 0
6/14/2004 18:00 383.6 382.8 0
6/14/2004 19:00 383.8 382.8 0
6/14/2004 20:00 383.3 382.8 0
6/14/2004 21:00 383.1 382.6 0
6/14/2004 22:00 383.1 382.6 0
6/14/2004 23:00 383.1 382.6 0
6/15/2004 0:00 382.8 382.6 0
6/15/2004 1:00 383.3 382.6 0
6/15/2004 2:00 383.6 382.3 0
6/15/2004 3:00 383.8 382.5 0
6/15/2004 4:00 382.8 382.1 0
6/15/2004 5:00 383.0 382.1 0
6/15/2004 6:00 382.8 382.0 0
... ... ... ...
6/24/2004 20:00 402.8 401.8 0
6/24/2004 21:00 402.3 401.8 0
6/24/2004 22:00 402.3 401.8 0
6/24/2004 23:00 402.1 401.1 0
6/25/2004 0:00 402.1 401.8 0
6/25/2004 1:00 402.1 401.3 0
6/25/2004 2:00 402.1 400.1 0
6/25/2004 3:00 401.6 400.8 0
6/25/2004 4:00 401.5 400.8 0
6/25/2004 5:00 401.3 400.8 0
6/25/2004 6:00 401.1 400.6 0
6/25/2004 7:00 402.1 400.8 0
6/25/2004 8:00 402.1 400.6 0
6/25/2004 9:00 401.6 400.5 0
6/25/2004 10:00 401.8 400.8 0
6/25/2004 11:00 401.5 400.6 0
6/25/2004 12:00 401.3 400.1 0
6/25/2004 13:00 402.8 401.3 0
6/25/2004 14:00 402.8 401.0 **1**
6/25/2004 15:00 401.5 400.1 0
6/25/2004 16:00 401.6 400.6 0
6/25/2004 17:00 401.8 401.0 0
6/25/2004 18:00 402.1 400.8 0
6/25/2004 19:00 402.3 400.8 0
6/25/2004 20:00 402.6 401.6 0
6/25/2004 21:00 401.8 401.3 0
6/25/2004 22:00 401.8 400.6 0
6/28/2004 0:00 401.8 401.6 0
6/28/2004 1:00 402.3 401.6 0
6/28/2004 2:00 402.3 401.5 0
对于第一周,S 列在 2004 年 6 月 18 日 18:00 的值为 1,在 2004 年 6 月 15 日 11:00 的值为 2 对于第二周,S 列在 6/25/2004 14:00 的值为 1,在 6/21/2004 18:00
的值为 2我想出了四个规则:
1. 当 A = max(A) 在当前周内,将值 1 放入 S。如果 A 最大值在一周内不是唯一的,则将 1 放入 S 中的最后一次出现A中的最大值。
2. 当 B = min(B) 在当前周内,将值 2 放入 S。如果 B 最小值在一周内不唯一,则将 2 放入 S 中最后一次出现的位置B中的最小值。
3. 在整个星期内重复此操作。整个数据集每小时可能有 80k+ 数据行。
4.每周内:如果 max(A) 和 min(B) 出现在同一日期时间索引处,则将值 0 留在 S 中(不变)。
下面是读取数据的代码:
import pandas as pd
url = 'https://www.dropbox.com/s/x7wl75rkzsqgkoj/dataset.csv?dl=1'
p = pd.read_csv(url)
p.set_index('datetime', drop=True, inplace=True)
p
这是一张图片,解释了我希望输出的样子:
【问题讨论】:
请在发帖前阅读此内容; How to Ask,minimal reproducible example。不要发布图片,请复制/粘贴代码并以任何人都可以用来复制您的流程的格式输入数据。 我想这是我的第一个问题...... 嗯,图像比长复制粘贴更有帮助。你的问题得到了很好的解决。你可以缩短你的样本。 【参考方案1】:所以我减小了数据框的大小以便我们可以看到一些东西,并且我添加了一个列周(“w”)以便我们更好地检查。
首先,您需要将索引的类型设置为 datetime 对象,以便您可以访问日期属性,例如 week to groupby on。
p.index = pd.to_datetime(p.index)
p["w"] = p.index.week
p
A B S w
datetime
2004-06-14 01:00:00 384.5 383.6 0 25
2004-06-14 09:00:00 382.8 382.1 0 25
2004-06-14 17:00:00 384.8 382.5 0 25
2004-06-15 01:00:00 383.3 382.6 0 25
2004-06-15 09:00:00 382.3 381.6 0 25
2004-06-15 17:00:00 388.6 384.6 0 25
2004-06-16 01:00:00 387.3 387.1 0 25
2004-06-16 09:00:00 388.8 387.6 0 25
2004-06-16 17:00:00 384.5 382.6 0 25
2004-06-17 01:00:00 384.6 383.6 0 25
2004-06-17 09:00:00 385.6 384.0 0 25
2004-06-17 17:00:00 386.8 386.0 0 25
2004-06-18 01:00:00 388.6 387.3 0 25
2004-06-18 09:00:00 387.5 385.8 0 25
2004-06-18 17:00:00 395.8 394.1 0 25
2004-06-21 02:00:00 394.3 392.8 0 26
2004-06-21 10:00:00 393.3 392.3 0 26
2004-06-21 18:00:00 394.8 392.1 0 26
2004-06-22 02:00:00 394.6 393.0 0 26
2004-06-22 10:00:00 394.0 392.6 0 26
2004-06-22 18:00:00 395.3 393.8 0 26
2004-06-23 02:00:00 394.3 393.6 0 26
2004-06-23 10:00:00 395.8 395.0 0 26
2004-06-23 18:00:00 394.6 393.6 0 26
2004-06-24 02:00:00 394.6 393.1 0 26
2004-06-24 10:00:00 397.8 394.8 0 26
2004-06-24 18:00:00 401.3 400.6 0 26
2004-06-25 02:00:00 402.1 400.1 0 26
2004-06-25 10:00:00 401.8 400.8 0 26
2004-06-25 18:00:00 402.1 400.8 0 26
2004-06-28 03:00:00 402.3 401.5 0 27
2004-06-28 11:00:00 402.1 400.8 0 27
2004-06-28 19:00:00 400.3 399.1 0 27
2004-06-29 03:00:00 399.6 399.1 0 27
2004-06-29 11:00:00 397.1 395.3 0 27
2004-06-29 19:00:00 392.3 391.0 0 27
2004-06-30 03:00:00 392.3 391.8 0 27
2004-06-30 11:00:00 393.6 393.1 0 27
2004-06-30 19:00:00 393.5 391.3 0 27
然后,您需要定义每周应用的函数:
def minmax(grp):
Amax = grp.A[::-1].idxmax() # reverse your Series since you want the last occurence, and idxmax return the first in case of tie
grp.loc[Amax, "S"] = 1
Bmin = grp.B[::-1].idxmin()
if Bmin != Amax:
grp.loc[Bmin, "S"] = 2
else:
grp.loc[Bmin, "S"] = 0 # no change
return grp
然后在每年的每周进行分组并应用该功能:
p.groupby([p.index.week, p.index.year]).apply(minmax)
A B S w
datetime
2004-06-14 01:00:00 384.5 383.6 0 25
2004-06-14 09:00:00 382.8 382.1 0 25
2004-06-14 17:00:00 384.8 382.5 0 25
2004-06-15 01:00:00 383.3 382.6 0 25
2004-06-15 09:00:00 382.3 381.6 2 25
2004-06-15 17:00:00 388.6 384.6 0 25
2004-06-16 01:00:00 387.3 387.1 0 25
2004-06-16 09:00:00 388.8 387.6 0 25
2004-06-16 17:00:00 384.5 382.6 0 25
2004-06-17 01:00:00 384.6 383.6 0 25
2004-06-17 09:00:00 385.6 384.0 0 25
2004-06-17 17:00:00 386.8 386.0 0 25
2004-06-18 01:00:00 388.6 387.3 0 25
2004-06-18 09:00:00 387.5 385.8 0 25
2004-06-18 17:00:00 395.8 394.1 1 25
2004-06-21 02:00:00 394.3 392.8 0 26
2004-06-21 10:00:00 393.3 392.3 0 26
2004-06-21 18:00:00 394.8 392.1 2 26
2004-06-22 02:00:00 394.6 393.0 0 26
2004-06-22 10:00:00 394.0 392.6 0 26
2004-06-22 18:00:00 395.3 393.8 0 26
2004-06-23 02:00:00 394.3 393.6 0 26
2004-06-23 10:00:00 395.8 395.0 0 26
2004-06-23 18:00:00 394.6 393.6 0 26
2004-06-24 02:00:00 394.6 393.1 0 26
2004-06-24 10:00:00 397.8 394.8 0 26
2004-06-24 18:00:00 401.3 400.6 0 26
2004-06-25 02:00:00 402.1 400.1 0 26
2004-06-25 10:00:00 401.8 400.8 0 26
2004-06-25 18:00:00 402.1 400.8 1 26
2004-06-28 03:00:00 402.3 401.5 1 27
2004-06-28 11:00:00 402.1 400.8 0 27
2004-06-28 19:00:00 400.3 399.1 0 27
2004-06-29 03:00:00 399.6 399.1 0 27
2004-06-29 11:00:00 397.1 395.3 0 27
2004-06-29 19:00:00 392.3 391.0 2 27
2004-06-30 03:00:00 392.3 391.8 0 27
2004-06-30 11:00:00 393.6 393.1 0 27
2004-06-30 19:00:00 393.5 391.3 0 27
HTH
【讨论】:
非常感谢,@jrjc!这有帮助,但我想它有问题。它错过了一些实例,主要是最小值。 @Silviu,你能更准确一点吗?编辑您的问题并添加一个您认为我的解决方案失败的简短示例。 我不知道会发生什么。在我共享的子集上,它工作正常。但是当我在整个数据集上运行它时,它不起作用。自己试试: import pandas as pd import numpy as np url = 'dropbox.com/s/4pr08n0i8enuqen/datasetf.csv?dl=1' 在S中生成106个值,但应该生成1513个。 尝试找出缺失的一周。 在数据集 'dropbox.com/s/4pr08n0i8enuqen/datasetf.csv?dl=1' 中,有 756 周。原则上,每周应该有 1 个高值和 1 个低值,这意味着我应该期望 S 中有 1512 个值。当我运行你的脚本时,它只给出 106。其次,脚本在运行时不会给出相同的结果更大的数据集。您可以比较我共享的两个数据集的输出【参考方案2】:很像@jrjc 方法,但我认为这可以在没有一些分配的情况下完成,让我们试试这个:
def f(x):
x.loc[x['A'][::-1].idxmax(), 'S'] = 1
lindx = x['B'][::-1].idxmin()
x.loc[lindx, 'S'] = np.where(x.loc[lindx, 'S'] == 1, 0, 2)
return x
p_out = p.groupby(pd.Grouper(freq='W')).apply(f)
通过仅查看 p_out 的非零值 S 来检查输出:
p_out[p_out.S.ne(0)]
输出:
A B S
datetime
2004-06-15 11:00:00 382.0 381.1 2
2004-06-18 18:00:00 395.8 394.1 1
2004-06-21 18:00:00 394.8 392.1 2
2004-06-25 14:00:00 402.8 401.0 1
2004-06-28 14:00:00 404.6 402.3 1
2004-06-29 17:00:00 394.5 390.3 2
【讨论】:
这太棒了!真的很有帮助!万分感谢!我花了一些时间来检查,因为我想确保在使用超过 1 年的数据时,对周数的索引不会产生任何问题。 您如何检查与此解决方案的关联(规则 #4)? 啊....jrjc 提出了一个很好的观点。我不是在检查关系。我稍后会添加这个逻辑。 谢谢,期待。如果得到解决,我很乐意接受它作为解决方案。 更新的解决方案。快乐编码!感谢@jrjc 指出逻辑错误。以上是关于创建一个新变量,它是python中另一个变量的每周最小值/最大值的主要内容,如果未能解决你的问题,请参考以下文章
使用 R 中另一个变量的线性回归的斜率来估算单个变量的缺失数据
如何将 DEFINE 变量设置为等于 PL/SQL 中另一个已定义表的选择