【问题标题】:Deleting values conditional on large values of another column删除以另一列的大值为条件的值
【发布时间】:2020-01-27 23:34:05
【问题描述】:

我有一个时间序列 df,其中包含 A 列中的每日 Rates 和 B 列中从一天到下一天的相对变化。

DF 如下所示:

                   IR      Shift
May/24/2019        5.9%    - 
May/25/2019        6%      1.67%      
May/26/2019        5.9%    -1.67
May/27/2019        20.2%   292%
May/28/2019        20.5%   1.4% 
May/29/2019        20%    -1.6% 
May/30/2019        5.1%   -292%
May/31/2019        5.1%     0%

我想删除 A 列中出现在较大相对偏移之间的所有值,> +/- 50%。

所以上面的DF应该如下所示:

                      IR      Shift
May/24/2019        5.9%    - 
May/25/2019        6%       1.67%      
May/26/2019        5.9%    -1.67
May/27/2019        np.nan   292%
May/28/2019        np.nan   1.4% 
May/29/2019        np.nan  -1.6% 
May/30/2019        5.1%    -292%
May/31/2019        5.1%      0%

这是我到目前为止所要做的......希望能得到一些帮助

 for i, j in df1.iterrows():
      if df1['Shift'][i] > .50 :
          x = df1['IR'][i]
      if df1['Shift'][j] < -.50 :
          y = df1['IR'][j]
      df1['IR'] = np.where(df1['Shift'].between(x,y), df1['Shift'], 
      np.nan)                                                                                                                                  

Error ValueError:Series 的真值不明确。使用 a.empty、a.bool()、a.item()、a.any() 或 a.all()。

【问题讨论】:

  • 好的,谢谢你的提示,我是编程新手。我将如何尝试...?
  • @yatu,我不清楚你所说的''保持一个临时变量是什么意思,并且每当相对于最后一个有效样本的变化大于 50% 时设置为 NaN。将当前样本与最后一个有效值进行比较”。您能举个例子吗?
  • 什么是相对位移?
  • @rprakash,IR ( colmun A ) 从当天到下一天的变化。
  • @ALollz,确实如此。你是对的。事实上,在我的数据时间序列中,峰值 (>50) 出现在整个数据中,因此需要删除这些大变化之间的所有值。一旦我回到家,我一定会尝试你的代码.. 但似乎你明白这个问题

标签: python pandas loops time-series


【解决方案1】:

这是一个尝试。可能有更多“正确”的方法可以做到这一点,但我不熟悉所有 pandas 内置函数。

df = pd.DataFrame({'Date':[datetime(2019,5,24), datetime(2019,5,25), datetime(2019,5,26), datetime(2019,5,27), datetime(2019,5,28),datetime(2019,5,29),datetime(2019,5,30)], 'IR':[0.059,0.06,0.059,0.202, 0.205, 0.2, 0.051], 'Shift':[pd.np.nan, 0.0167, -0.0167, 2.92, 0.014, -0.016, -2.92]})

>>>df
        Date     IR   Shift
0 2019-05-24  0.059     NaN
1 2019-05-25  0.060  0.0167
2 2019-05-26  0.059 -0.0167
3 2019-05-27  0.202  2.9200
4 2019-05-28  0.205  0.0140
5 2019-05-29  0.200 -0.0160
6 2019-05-30  0.051 -2.9200

df['IR'] = [pd.np.nan if abs(y-z) > 0.5 else x for x, y, z in zip(df['IR'], df['Shift'], df['Shift'].shift(1))]
>>>df
        Date     IR   Shift
0 2019-05-24  0.059     NaN
1 2019-05-25  0.060  0.0167
2 2019-05-26  0.059 -0.0167
3 2019-05-27    NaN  2.9200
4 2019-05-28    NaN  0.0140
5 2019-05-29  0.200 -0.0160
6 2019-05-30    NaN -2.9200

【讨论】:

  • 谢谢。让我消化一下上面的内容。第一次运行似乎没有效果。
  • 也许是编码新手,可能会发现常规循环比这种难以理解的列表理解更容易?
【解决方案2】:

您也可以从 numpy 中np.where 函数如下:

import pandas as pd
import numpy as np

df = pd.DataFrame({'Date':[datetime(2019,5,24), datetime(2019,5,25), datetime(2019,5,26), datetime(2019,5,27), datetime(2019,5,28),datetime(2019,5,29),datetime(2019,5,30)], 'IR':[0.059,0.06,0.059,0.202, 0.205, 0.2, 0.051], Shift':[pd.np.nan, 0.0167, -0.0167, 2.92, 0.014, -0.016, -2.92]})                                                                                                                                                                                                       

df['IR'] = np.where(df['Shift'].between(df['Shift']*0.5, df['Shift']*1.5), df['Shift'], np.nan)                                                                                                                                  

In [8]: df                                                                                                                                                                                                                               
Out[8]: 
        Date      IR   Shift
0 2019-05-24     NaN     NaN
1 2019-05-25  0.0167  0.0167
2 2019-05-26     NaN -0.0167
3 2019-05-27  2.9200  2.9200
4 2019-05-28  0.0140  0.0140
5 2019-05-29     NaN -0.0160
6 2019-05-30     NaN -2.9200

【讨论】:

  • 谢谢奥莱尔。没有骰子。上面的代码删除了 rel 变化低于 0.50 的数据点。此外,这样做的主要目标是删除时间序列中的一组数据,这些数据的速率在一段时间内飙升然后突然下降,与最初的飙升几乎相同。
【解决方案3】:

使用df.at 访问行/列标签对的单个值。

import numpy as np
import pandas as pd
from datetime import datetime

df = pd.DataFrame({'Date':[datetime(2019,5,24), datetime(2019,5,25), datetime(2019,5,26), datetime(2019,5,27), datetime(2019,5,28),datetime(2019,5,29),datetime(2019,5,30),datetime(2019,5,31)], 'IR':[5.9,6,5.9,20.2, 20.5, 20, 5.1, 5.1], 'Shift':[pd.np.nan, 1.67, -1.67, 292, 1.4, -1.6, -292, 0]})

print("DataFrame Before :")
print(df)

count = 1
while (count < len(df.index)):
    if (abs(df.at[count-1, 'Shift'] - df.at[count, 'Shift']) >= 50):
        df.at[count, 'IR'] = np.nan
    count = count + 1

print("DataFrame After :")
print(df)

程序输出:

DataFrame Before :
        Date    IR   Shift
0 2019-05-24   5.9     NaN
1 2019-05-25   6.0    1.67
2 2019-05-26   5.9   -1.67
3 2019-05-27  20.2  292.00
4 2019-05-28  20.5    1.40
5 2019-05-29  20.0   -1.60
6 2019-05-30   5.1 -292.00
7 2019-05-31   5.1    0.00

DataFrame After :
        Date    IR   Shift
0 2019-05-24   5.9     NaN
1 2019-05-25   6.0    1.67
2 2019-05-26   5.9   -1.67
3 2019-05-27   NaN  292.00
4 2019-05-28   NaN    1.40
5 2019-05-29  20.0   -1.60
6 2019-05-30   NaN -292.00
7 2019-05-31   NaN    0.00

【讨论】:

  • “Dataframe After”中的第 5 行 IR 也应该是 NaN。而第 6 行和第 7 行不应该是 NaN。想象一只股票在公告后飙升,然后在几个月后跌至正常水平。这里的目标是消除在那个高涨时期发生的价格......所以第 6 和第 7 行代表正常时期......第 3/4/5 行是高涨时期...... IR 的价格上涨和恢复“正常”的幅度相似,为 292%,尽管方向相反。
  • 因此,我们如何设置代码以在超过 50% 时触发,并在发生类似但相反的 -50% 运动时停止 - 将介于两者之间的所有值转换为 NaN
  • 另外,不知道你为什么要使用差异来确定是否超过 50%,Shift 列告诉我们一天到下一天的变化是多少......并遵循“峰值” ' 除了 IR 回落时,Shift 每天都将是微不足道的......
【解决方案4】:

根据您对在任何大转变(正面或负面)上触发此操作的描述,您可以这样做:

import pandas as pd
import numpy as np
from datetime import datetime

df = pd.DataFrame({'Date':[datetime(2019,5,24), datetime(2019,5,25), datetime(2019,5,26), datetime(2019,5,27), datetime(2019,5,28),datetime(2019,5,29),datetime(2019,5,30)], 'IR':[0.059,0.06,0.059,0.202, 0.205, 0.2, 0.051], 'Shift':[np.nan, 0.0167, -0.0167, 2.92, 0.014, -0.016, -2.92]})

df.loc[(abs(df.Shift) > .5).cumsum() % 2 == 1, 'IR'] = np.nan

        Date     IR   Shift
0 2019-05-24  0.059     NaN
1 2019-05-25  0.060  0.0167
2 2019-05-26  0.059 -0.0167
3 2019-05-27    NaN  2.9200
4 2019-05-28    NaN  0.0140
5 2019-05-29    NaN -0.0160
6 2019-05-30  0.051 -2.9200

步骤:

  • abs(df.Shift) > .5:找到 +/- 50% 以上的偏移

  • .cumsum():为每个周期赋予唯一值,其中奇数周期是我们要省略的周期。

  • % 2 == 1:为 cumsum() 检查哪些行有奇数。

注意:如果您想要限制这一点,以便每个正尖峰之后都需要一个负尖峰,则这不起作用,反之亦然。

【讨论】:

    【解决方案5】:

    不确定您的班次,因此重新计算。这对你有用吗?

    import pandas as pd
    import numpy as np
    
    df.drop(columns=['Shift'], inplace=True)  ## calculated via method below
    df['nextval'] = df['IR'].shift(periods=1)
    
    def shift(current, previous):
        return (current-previous)/previous * 100
    
    indexlist=[]  ## to save index that will be set to null
    prior=0  ## temporary flag to store value prior to a peak 
    flag=False
    
    for index, row in df.iterrows():    
        if index==0: ## to skip first row of data
            continue
    
        if flag==False and (shift(row[1], row[2])) > 50:   ## to check for start of peak
            prior=row[2]
            indexlist.append(index)
            flag=True
            continue
    
        if flag==True:  ## checking until when the peak lasts
            if (shift(row[1], prior)) > 50:
                indexlist.append(index)
    
    df.loc[df.index.isin(indexlist),'IR'] = np.nan ## replacing with nan
    

    打印输出(df)

              date   IR  nextval
    0  May/24/2019  5.9      NaN
    1  May/25/2019  6.0      5.9
    2  May/26/2019  5.9      6.0
    3  May/27/2019  NaN      5.9
    4  May/28/2019  NaN     20.2
    5  May/29/2019  NaN     20.5
    6  May/30/2019  5.1     20.0
    7  May/31/2019  5.1      5.1
    

    【讨论】:

      【解决方案6】:

      我们可以定位 pairs ([1st-2nd), [3rd-4th), ...) 异常值之间的行,然后一次屏蔽整个 DataFrame。

      设置

      import pandas as pd
      import numpy as np
      
      df = pd.read_clipboard()
      df = df.apply(lambda x: pd.to_numeric(x.str.replace('%', ''), errors='coerce'))
      
                     IR   Shift
      May/24/2019   5.9     NaN
      May/25/2019   6.0    1.67
      May/26/2019   5.9   -1.67
      May/27/2019  20.2  292.00
      May/28/2019  20.5    1.40
      May/29/2019  20.0   -1.60
      May/30/2019   5.1 -292.00
      May/31/2019   5.1    0.00
      

      代码

      # Locate the extremal values
      s = df.Shift.lt(-50) | df.Shift.gt(50)
      
      # Get the indices between consecutive pairs. 
      # This doesn't mask 2nd outlier, which matches your output
      m = s.cumsum()%2==1
      
      df.loc[m, 'IR'] = np.NaN
      #              IR   Shift
      #May/24/2019  5.9     NaN
      #May/25/2019  6.0    1.67
      #May/26/2019  5.9   -1.67
      #May/27/2019  NaN  292.00
      #May/28/2019  NaN    1.40
      #May/29/2019  NaN   -1.60
      #May/30/2019  5.1 -292.00
      #May/31/2019  5.1    0.00
      

      在这里,我添加了几行以显示在多个尖峰的情况下这将如何表现。 IR_modifiedIR 将如何被上述逻辑屏蔽。

                     IR   Shift  IR_modified
      May/24/2019   5.9     NaN          5.9
      May/25/2019   6.0    1.67          6.0
      May/26/2019   5.9   -1.67          5.9
      May/27/2019  20.2  292.00          NaN
      May/28/2019  20.5    1.40          NaN
      May/29/2019  20.0   -1.60          NaN
      May/30/2019   5.1 -292.00          5.1
      May/31/2019   5.1    0.00          5.1
      June/1/2019   7.0  415.00          NaN
      June/2/2019  17.0   15.00          NaN
      June/3/2019  27.0   12.00          NaN
      June/4/2019  17.0  315.00         17.0
      June/5/2019   7.0  -12.00          7.0
      

      【讨论】:

        【解决方案7】:

        df.loc[df['Shift']>0.5,'IR'] = np.nan

        【讨论】:

        • 请对您的回答提供一些解释。
        猜你喜欢
        • 1970-01-01
        • 2018-05-19
        • 2021-09-14
        • 2020-03-10
        • 1970-01-01
        • 2012-01-05
        • 1970-01-01
        • 2021-09-12
        • 2021-09-14
        相关资源
        最近更新 更多