创建一个新变量,它是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 中另一个变量的线性回归的斜率来估算单个变量的缺失数据

有没有办法改变 Unix 中另一个进程的环境变量?

如何将 DEFINE 变量设置为等于 PL/SQL 中另一个已定义表的选择

用ggplot2直方图中另一个连续变量的平均值填充条形颜色

如何强制 Python 在循环内创建新变量/新范围? [复制]

Python-函数的全局变量和局部变量