根据datafram中的另一个单元格值更改单元格值

2024-06-13 00:33:13 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图确定某一列在一行中有多少天高于或低于某个阈值。在

>>> df.head()
            Open   High    Low  Close  Volume
Date
2004-08-19  49.96  51.98  47.93  50.12     NaN
2004-08-20  50.69  54.49  50.20  54.10     NaN
2004-08-23  55.32  56.68  54.47  54.65     NaN
2004-08-24  55.56  55.74  51.73  52.38     NaN
2004-08-25  52.43  53.95  51.89  52.95     NaN
>>>

对于上面的例子,我希望另一列df['RDA']在每连续一天打开的列超过50时递增。对于低于50的连续一天,我希望第二列df['RDB']递增,df['RDA']重置为0。我尝试过if/then逻辑,但它不喜欢这样,给了我一个值错误:

^{pr2}$

我希望数据帧的输出如下所示:

>>> df.head()
            Open   High    Low  Close  Volume    RDA   RDB
Date
2004-08-19  51.96  51.98  47.93  50.12     NaN    1      0
2004-08-20  50.69  54.49  50.20  54.10     NaN    2      0
2004-08-23  55.32  56.68  54.47  54.65     NaN    3      0
2004-08-24  45.56  55.74  51.73  52.38     NaN    0      1
2004-08-25  42.43  53.95  51.89  52.95     NaN    0      2
2004-08-26  41.96  51.98  47.93  50.12     NaN    0      3
2004-08-27  40.69  54.49  50.20  54.10     NaN    0      4
2004-08-28  55.32  56.68  54.47  54.65     NaN    1      0
2004-08-29  55.56  55.74  51.73  52.38     NaN    2      0
2004-08-30  52.43  53.95  51.89  52.95     NaN    3      0
>>>

这对熊猫来说是可能的吗?我知道您可以获得列中值的计数,但到目前为止,我还找不到具有连续值的方法。一个包含2个变量的if/then语句可以工作,但是就像我上面提到的,当我尝试那样做时,我得到了一个值错误。任何帮助都将不胜感激。在


Tags: dfclosedateif错误阈值opennan
3条回答

首先,向dataframe添加一个flag列,以指示Open是否高于目标价格50(True或False)。在

然后,可以使用compare-cumsum-groupby pattern来标识此标志的累积分组,并将cumsum应用于每个这样的组。在

我们现在需要反转标志,使一为零,零为一,然后使用相同的策略来计算rdb。在

最后,我们删除flag列(我使用.iloc[:, :-1]来删除它,因为我将它添加为最后一列),并附加新的RDA和{}列。在

target_price = 50
df = df.assign(flag=df.Open.gt(target_price))  # True if `Open` greater than `target_price`, otherwise False.

rda = df.groupby((df['flag'] != df['flag'].shift()).cumsum()).flag.cumsum()
df['flag'] = ~df['flag']  # Invert flag for RDB.
rdb = df.groupby((df['flag'] != df['flag'].shift()).cumsum()).flag.cumsum()

df = df.iloc[:, :-1].assign(RDA=rda, RDB=rdb)
>>> df
      Date   Open   High    Low  Close  Volume  RDA  RDB
0  8/19/04  51.96  51.98  47.93  50.12     NaN    1    0
1  8/20/04  50.69  54.49  50.20  54.10     NaN    2    0
2  8/23/04  55.32  56.68  54.47  54.65     NaN    3    0
3  8/24/04  45.56  55.74  51.73  52.38     NaN    0    1
4  8/25/04  42.43  53.95  51.89  52.95     NaN    0    2
5  8/26/04  41.96  51.98  47.93  50.12     NaN    0    3
6  8/27/04  40.69  54.49  50.20  54.10     NaN    0    4
7  8/28/04  55.32  56.68  54.47  54.65     NaN    1    0
8  8/29/04  55.56  55.74  51.73  52.38     NaN    2    0
9  8/30/04  52.43  53.95  51.89  52.95     NaN    3    0
  • 我将使用np.sign来区分Open和{}。小于50时为-1,正好50时为0,大于50时为{}。在
  • 接下来,我将使用np.diff来标识它何时从一个值切换到另一个值
  • 然后我将使用cumsum来定义连续符号组
  • 接下来我将使用cumcount来获取组内的计数
  • 最后,我将使用np.where来分割{}

o = df.Open.values - 50
signs = np.sign(o)
changes = np.append(False, signs[:-1] != signs[1:])
g = changes.cumsum()
cumcounts = df.groupby(g).cumcount() + 1

a = np.where(signs == 1,  cumcounts, 0)
b = np.where(signs == -1, cumcounts, 0)

df.assign(RDA=a, RDB=b)

             Open   High    Low  Close  Volume  RDA  RDB
Date                                                    
2004-08-19  51.96  51.98  47.93  50.12     NaN    1    0
2004-08-20  50.69  54.49  50.20  54.10     NaN    2    0
2004-08-23  55.32  56.68  54.47  54.65     NaN    3    0
2004-08-24  45.56  55.74  51.73  52.38     NaN    0    1
2004-08-25  42.43  53.95  51.89  52.95     NaN    0    2
2004-08-26  41.96  51.98  47.93  50.12     NaN    0    3
2004-08-27  40.69  54.49  50.20  54.10     NaN    0    4
2004-08-28  55.32  56.68  54.47  54.65     NaN    1    0
2004-08-29  55.56  55.74  51.73  52.38     NaN    2    0
2004-08-30  52.43  53.95  51.89  52.95     NaN    3    0

这也可以使用Python提供的functools.reduce方法来完成。首先创建目标数据的iterable,因此在您的例子中:

target = df.Open > 50

这将是您稍后传递到functools.reduce中以“减少”的内容。Reduce本质上是map,但在列表元素中保留一个值。这可以用来做你所要求的。在

我将尝试分解您可以使用的函数(在文章的末尾有完整的显示)。在

functools.reduce允许您访问两个参数。您的累计值,以及您所在的当前列表项。它还允许您传入自己的初始值设定项(在查看任何内容之前的第一项)。有了这个,我们可以浏览我们的列表,如果它是True,正如我们上面的目标系列所确定的那样,我们可以向列表中的最后一个元素添加1,否则向累加器添加一个0。在

这需要一点精细处理,方法是将初始值设定项设置为一个列表,其中的值为0,就像[0],这样在第一次传递时,它可以使用“last”元素并对其执行操作而不会出错。在

完成后,列表前面会有一个离散符0,您可以使用一个切片[1:]来删除它,从而只获取第二个元素和以后的元素。在

您的RDB列是完全相同的,只是您希望确保它不是目标列表中的True,这只需要在条件语句中添加一个not。在

完整代码如下所示:

^{pr2}$

相关问题 更多 >