Pandas计算滚动时间范围内的百分比变化

时间:2017-09-07 14:28:40

标签: python pandas percentage

我在pandas中有一个数据框,其组织如下:

btc_price['btc_price'] = pd.to_numeric(btc_price['btc_price'].str.replace(',', ''))
btc_price.head(n=120)
Out[4]: 
                      btc_price
time                           
2017-08-27 22:50:00  4,389.6113
2017-08-27 22:51:00  4,389.0850
2017-08-27 22:52:00  4,388.8625
2017-08-27 22:53:00  4,389.7888
2017-08-27 22:56:00  4,389.9138
2017-08-27 22:57:00  4,390.1663
2017-08-27 22:58:00  4,390.2600
2017-08-27 22:59:00  4,392.4013
2017-08-27 23:00:00  4,391.6588
2017-08-27 23:01:00  4,391.9213
2017-08-27 23:02:00  4,394.0113
2017-08-27 23:03:00  4,396.9713
2017-08-27 23:04:00  4,397.3350
2017-08-27 23:05:00  4,397.0700
2017-08-27 23:06:00  4,398.6188
2017-08-27 23:07:00  4,398.5725
2017-08-27 23:08:00  4,397.4713
2017-08-27 23:09:00  4,398.0938
2017-08-27 23:10:00  4,398.7775
2017-08-27 23:11:00  4,398.0200
2017-08-27 23:12:00  4,397.9513
2017-08-27 23:13:00  4,398.0613
2017-08-27 23:14:00  4,398.0900
2017-08-27 23:15:00  4,398.0063
2017-08-27 23:16:00  4,397.6088
2017-08-27 23:17:00  4,394.3763
2017-08-27 23:46:00  4,389.1100
2017-08-27 23:48:00  4,390.6763
2017-08-27 23:49:00  4,392.5388
2017-08-27 23:49:00  4,392.5388
                        ...
2017-08-28 00:51:00  4,367.5738
2017-08-28 00:51:00  4,367.5738
2017-08-28 00:52:00  4,367.7888
2017-08-28 00:53:00  4,368.4188
2017-08-28 00:54:00  4,368.8225
2017-08-28 00:55:00  4,368.7438
2017-08-28 00:57:00  4,368.4700
2017-08-28 00:58:00  4,367.9963
2017-08-28 00:59:00  4,366.4750
2017-08-28 01:00:00  4,359.1988
2017-08-28 01:01:00  4,355.2825
2017-08-28 01:02:00  4,352.3675
2017-08-28 01:03:00  4,354.2188
2017-08-28 01:04:00  4,353.5263
2017-08-28 01:05:00  4,354.2488
2017-08-28 01:06:00  4,358.8063
2017-08-28 01:07:00  4,359.5738
2017-08-28 01:08:00  4,361.7313
2017-08-28 01:09:00  4,360.8638
2017-08-28 01:10:00  4,363.0750
2017-08-28 01:11:00  4,362.3375
2017-08-28 01:12:00  4,362.3338
2017-08-28 01:13:00  4,358.8000
2017-08-28 01:14:00  4,354.0463
2017-08-28 01:15:00  4,356.1950
2017-08-28 01:16:00  4,359.5975
2017-08-28 01:17:00  4,360.1588
2017-08-28 01:18:00  4,362.2338
2017-08-28 01:19:00  4,363.7900
2017-08-28 01:20:00  4,362.6150

我想创建一个值为-1,0,1的新列change。这些应该相当于过去一小时(-1)价格下降5%,"没有变化" (0),过去一小时(1)价格上涨5%。此外,一小时的价值应该是可变的,所以我可以将它改为一天或30分钟,例如,我觉得合适。

我发现了类似的问题herehere,但我是python的新手,并不确定如何将这些解决方案专门应用于我的问题。

另一个选择是计算每小时的平均价格,然后按小时计算百分比变化,但我希望能够使用滚动时间范围。

我也尝试在R中做这个没有运气。请帮忙。

我开始尝试:

btc_price['change'] = btc_price.pct_change(periods=60, fill_method='pad', limit=None, freq=None) 

这有效,但并不能完全满足我的要求,我想将每个值与过去"时间框架的最小值和最大值进行比较"并根据此值计算%变化,而不是简单地比较两行。

我最终想要的是这样的(不完整的):

# Calculate the % change in btc_price
def calc_change(df):
    array = df.values
    a = array[:,1]

# Apply % change comparison to timeframe 
def rolling(df, period, func, min_periods = None):
        if min_periods is None:
            min_periods = period
        result = pd.Series(np.nan, index = df.index)

        for i in range(1, len(df) + 1):
            sub_df = df.iloc[max(i)]

我相信我可以使用类似df.rolling() here之类的内容,但我不太确定这是否正是我想要的,因为我不太明白它是如何工作的。解释会很棒。

1 个答案:

答案 0 :(得分:6)

  1. 您可以使用更友好的格式粘贴DF,以便人们可以使用pd.read_clipboard
  2. 导入它
  3. 你应该删除','来自btc_price并使用pd.to_numeric投射它。
  4. 拥有有效数据后,您可以执行以下操作:

    In [59]: df.head()
    Out[59]: 
                         btc_price
    time                          
    2017-09-07 22:50:00  4389.6113
    2017-09-07 22:51:00  4389.0850
    2017-09-07 22:52:00  4388.8625
    2017-09-07 22:53:00  4389.7888
    2017-09-07 22:56:00  4389.9138
    
    In [60]: df = df.resample('1MIN').ffill(); df.head(10)
    Out[60]: 
                         btc_price
    time                          
    2017-09-07 22:50:00  4389.6113
    2017-09-07 22:51:00  4389.0850
    2017-09-07 22:52:00  4388.8625
    2017-09-07 22:53:00  4389.7888
    2017-09-07 22:54:00  4389.7888
    2017-09-07 22:55:00  4389.7888
    2017-09-07 22:56:00  4389.9138
    2017-09-07 22:57:00  4390.1663
    2017-09-07 22:58:00  4390.2600
    2017-09-07 22:59:00  4392.4013
    
    In [61]: WINDOW = 5  # 5 minutes, you can change to any window you want. Has to match resolution from resample
    
    In [63]: df['change'] = df['btc_price'].pct_change(periods=WINDOW); df.head(10)
    Out[63]: 
                         btc_price    change
    time                                    
    2017-09-07 22:50:00  4389.6113       NaN
    2017-09-07 22:51:00  4389.0850       NaN
    2017-09-07 22:52:00  4388.8625       NaN
    2017-09-07 22:53:00  4389.7888       NaN
    2017-09-07 22:54:00  4389.7888       NaN
    2017-09-07 22:55:00  4389.7888  0.000040
    2017-09-07 22:56:00  4389.9138  0.000189
    2017-09-07 22:57:00  4390.1663  0.000297
    2017-09-07 22:58:00  4390.2600  0.000107
    2017-09-07 22:59:00  4392.4013  0.000595
    
    In [64]: import numpy as np
    
    ]n [67]: df['change_label'] = pd.cut(df['change'], [np.NINF, -0.05, 0.05, np.PINF], labels=['below 5%', 'around 0%', 'above 5%']) 
    
    In [69]: df.head(10)
    Out[69]: 
                         btc_price        change change_label
    time                                                     
    2017-09-07 22:50:00  4389.6113           NaN          NaN
    2017-09-07 22:51:00  4389.0850           NaN          NaN
    2017-09-07 22:52:00  4388.8625           NaN          NaN
    2017-09-07 22:53:00  4389.7888           NaN          NaN
    2017-09-07 22:54:00  4389.7888           NaN          NaN
    2017-09-07 22:55:00  4389.7888  4.043638e-05    around 0%
    2017-09-07 22:56:00  4389.9138  1.888321e-04    around 0%
    2017-09-07 22:57:00  4390.1663  2.970701e-04    around 0%
    2017-09-07 22:58:00  4390.2600  1.073400e-04    around 0%
    2017-09-07 22:59:00  4392.4013  5.951311e-04    around 0%
    

    感觉你需要:

    1. Resample以获得可预测的解决方案
    2. FFill为了没有洞。或者在你的情况下以其他方式处理它。
    3. 使用pct_change
    4. 要将更改变为标签,您可以使用pd.cut。此外,简单的df['change'].map(lamba v: # here logic)也可以。