Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 每日数据,每3天重新采样,在后续5天内高效计算_Python_Pandas_Numpy - Fatal编程技术网

Python 每日数据,每3天重新采样,在后续5天内高效计算

Python 每日数据,每3天重新采样,在后续5天内高效计算,python,pandas,numpy,Python,Pandas,Numpy,考虑df tidx = pd.date_range('2012-12-31', periods=11, freq='D') df = pd.DataFrame(dict(A=np.arange(len(tidx))), tidx) df 我想计算连续5天的总和,每3天一次 我想是这样的 这是经过编辑的 我所拥有的是不正确的@伊万·波兹德耶夫和@boud注意到这是一个中心窗口,这不是我的意图。为困惑而道歉。 每个人的解决方案都抓住了我所追求的大部分 标准 我正在寻找能够扩展到大型数据集的智

考虑
df

tidx = pd.date_range('2012-12-31', periods=11, freq='D')
df = pd.DataFrame(dict(A=np.arange(len(tidx))), tidx)
df
我想计算连续5天的总和,每3天一次

我想是这样的

这是经过编辑的
我所拥有的是不正确的@伊万·波兹德耶夫和@boud注意到这是一个中心窗口,这不是我的意图。为困惑而道歉。
每个人的解决方案都抓住了我所追求的大部分


标准

  • 我正在寻找能够扩展到大型数据集的智能高效解决方案

  • 我将提供时间解决方案,并考虑优雅

  • 解决方案还应适用于各种样本和回溯频率


来自评论

  • 我想要一个通用的解决方案来处理指定频率的回溯,并获取属于该回溯的任何内容。
    • 对于上面的示例,回溯是
      5D
      ,可能有4或50个观察值属于该回溯
  • 我希望时间戳是回望期内最后观察到的时间戳

    • 您给我们的df是:

                   A
      2012-12-31   0
      2013-01-01   1
      2013-01-02   2
      2013-01-03   3
      2013-01-04   4
      2013-01-05   5
      2013-01-06   6
      2013-01-07   7
      2013-01-08   8
      2013-01-09   9
      2013-01-10  10
      
      您可以创建滚动5天总和序列,然后对其重新采样。我想不出比这更有效的方法了。总的来说,这应该是相对省时的

      df.rolling(5,min_periods=5).sum().dropna().resample('3D').first()
      Out[36]: 
                       A
      2013-01-04 10.0000
      2013-01-07 25.0000
      2013-01-10 40.0000
      

      这还不太完美,但我得去为今晚的哈洛韦派对做假血。。。你应该能从评论中看出我的意思。最大的加速之一是使用
      np.searchsorted
      查找窗口边缘。它还没有完全起作用,但我敢打赌它只是一些需要调整的索引偏移量

      将熊猫作为pd导入
      将numpy作为np导入
      tidx=pd.日期范围('2012-12-31',期间=11,频率=D')
      df=pd.DataFrame(dict(A=np.arange(len(tidx))),tidx)
      样本频率=3天
      样本宽度=5天
      采样频率*=每天86400秒
      样本宽度*=每天86400秒
      times=df.index.astype(np.int64)//10**9#时间戳数组(unix时间)
      cumsum=np.cumsum(df.A).as_matrix()#累积和数组(可以消除重叠较大的额外和)
      mat=np。数组([times,cumsum])#可以消除临时时间和cumsum变量
      def产量步骤(垫,频率):
      normtime=((mat[0]-mat[0,0])/freq.astype(int)#表示样本编号的整数
      对于范围内的i(最大(正常时间)+1):
      收益率np.searchsorted(normtime,i)#收益率窗口索引的开始
      def sumwindow(mat,i,width):#i是yieldstep返回的窗口的开始
      normtime=((mat[0,i:]-mat[0,i])/width.astype(int)#与之前相同,但我们对窗口宽度进行了规范
      j=np.searchsorted(normtime,i,side='right')-1#查找窗口的右侧
      #返回unix历元中窗口最右边的时间戳(以秒为单位)和窗口总和
      return mat[0,j],mat[1,j]-mat[1,i]#窗口的和只是结束-开始,因为我们之前做了一个求和
      加窗求和=np.数组([sumwindow(mat,i,样本宽度)用于i的yieldstep(mat,样本频率)])
      
      这里列出了两个基于NumPy的解决方案,使用基于bin的求和,基本上涵盖了三种场景

      场景#1:每个日期有多个条目,但没有遗漏日期

      方法1:

      方法2:

      方法#3:

      我们可以将卷积部分替换为直接切片求和,以改进它的版本-

      def vectorized_app3_v2(df, S=3, W=5):  
          dt = df.index.values
          shifts = np.append(False,dt[1:] > dt[:-1])
          c = np.bincount(shifts.cumsum(),df.A.values)
          f = c.size+S-W
          out = c[:f:S].copy()
          for i in range(1,W):
              out += c[i:f+i:S]
          out_index = dt[np.nonzero(shifts)[0][W-2::S]]
          return pd.DataFrame(out,index=out_index,columns=['A'])
      
      场景#2:每个日期和缺失日期有多个条目

      方法4:

      场景#3:连续日期和每个日期仅一个条目

      方法#5:


      创建测试数据的建议

      情景1:

      情景2:

      要创建多个日期和缺少日期的设置,我们只需编辑
      df_data
      创建步骤,如下所示-

      df_data = np.random.randint(0,9,(len(idx0)))
      
      情景3:

      仅适用于定期间隔的日期 这里有两种方法,第一种是pandas方法,第二种是numpy函数

      >>> n=5   # trailing periods for rolling sum
      >>> k=3   # frequency of rolling sum calc
      
      >>> df.rolling(n).sum()[-1::-k][::-1]
      
                     A
      2013-01-01   NaN
      2013-01-04  10.0
      2013-01-07  25.0
      2013-01-10  40.0
      
      这里有一个numpy函数(改编自):

      对于间隔不规则的日期(或间隔规则的日期) 只需在前面加上:

      df.resample('D').sum().fillna(0)
      
      例如,上述方法变为:

      df.resample('D').sum().fillna(0).rolling(n).sum()[-1::-k][::-1]
      

      请注意,处理不规则间隔的日期可以在熊猫身上简单而优雅地完成,因为这是熊猫的一种力量,几乎胜过其他任何东西。但是你可能会找到一种numpy(或者numba或者cython)的方法,它会在速度提高的同时牺牲一些简单性。当然,这是否是一个好的折衷方案将取决于您的数据大小和性能要求

      对于间隔不规则的日期,我测试了下面的示例数据,它似乎工作正常。这将在每个日期产生丢失、单个和多个条目的组合:

      np.random.seed(12345)
      per = 11
      tidx = np.random.choice( pd.date_range('2012-12-31', periods=per, freq='D'), per )
      df = pd.DataFrame(dict(A=np.arange(len(tidx))), tidx).sort_index()
      

      看起来像一个以滚动为中心的窗口,在该窗口中,您每n天提取一次数据:

      def rolleach(df, ndays, window):
          return df.rolling(window, center=True).sum()[ndays-1::ndays]
      
      rolleach(df, 3, 5)
      Out[95]: 
                     A
      2013-01-02  10.0
      2013-01-05  25.0
      2013-01-08  40.0
      

      如果dataframe是按日期排序的,那么我们实际拥有的是在计算某些内容时对数组进行迭代

      这是一个算法,它在数组的一次迭代中计算所有的和。要理解它,请参阅下面我的笔记扫描。这是一个基本的、未优化的版本,旨在展示该算法(针对Python和Cython follow进行了优化),对于我的系统(第4页)上的100k数组,
      list()
      需要
      ~500ms
      。由于Python的int和range相对较慢,因此将其转换到C级应该会带来巨大的好处

      from __future__ import division
      import numpy as np
      
      #The date column is unimportant for calculations.
      # I leave extracting the numbers' column from the dataframe
      # and adding a corresponding element from data column to each result
      # as an exercise for the reader
      data = np.random.randint(100,size=100000)
      
      def calc_trailing_data_with_interval(data,n,k):
          """Iterate over `data', computing sums of `n' trailing elements
          for each `k'th element.
          @type data: ndarray
          @param n: number of trailing elements to sum up
          @param k: interval with which to calculate sums
          """
          lim_index=len(data)-k+1
      
          nsums = int(np.ceil(n/k))
          sums = np.zeros(nsums,dtype=data.dtype)
          M=n%k
          Mp=k-M
      
          index=0
          currentsum=0
      
          while index<lim_index:
              for _ in range(Mp):
                  #np.take is awkward, requiring a full list of indices to take
                  for i in range(currentsum,currentsum+nsums-1):
                      sums[i%nsums]+=data[index]
                  index+=1
              for _ in range(M):
                  sums+=data[index]
                  index+=1
              yield sums[currentsum]
              currentsum=(currentsum+1)%nsums
      

      优化:Cython 在Cython中静态键入所有内容可立即将速度提高到
      150ms
      。并且(可选地)假设
      np.int
      dtype
      ,能够在C级别处理数据,将时间缩短到
      ~11ms
      。在这一点上,保存到一个
      np.empty
      确实会有所不同,保存一个难以置信的
      ~6.5ms
      ,总计
      ~5.5ms

      # Setup input for exactly one entry per date S = 4 # Could be edited W = 7 datasize = 3 # Decides datasize tidx = pd.date_range('2012-12-31', periods=datasize*S + W-S, freq='D') df = pd.DataFrame(dict(A=np.arange(len(tidx))), tidx)
      >>> n=5   # trailing periods for rolling sum
      >>> k=3   # frequency of rolling sum calc
      
      >>> df.rolling(n).sum()[-1::-k][::-1]
      
                     A
      2013-01-01   NaN
      2013-01-04  10.0
      2013-01-07  25.0
      2013-01-10  40.0
      
      def rolling_sum(a, n=5, k=3):
          ret = np.cumsum(a.values)
          ret[n:] = ret[n:] - ret[:-n]
          return pd.DataFrame( ret[n-1:][-1::-k][::-1], 
                               index=a[n-1:][-1::-k][::-1].index )
      
      rolling_sum(df,n=6,k=4)   # default n=5, k=3
      
      df.resample('D').sum().fillna(0)
      
      df.resample('D').sum().fillna(0).rolling(n).sum()[-1::-k][::-1]
      
      rolling_sum( df.resample('D').sum().fillna(0) )
      
      np.random.seed(12345)
      per = 11
      tidx = np.random.choice( pd.date_range('2012-12-31', periods=per, freq='D'), per )
      df = pd.DataFrame(dict(A=np.arange(len(tidx))), tidx).sort_index()
      
      def rolleach(df, ndays, window):
          return df.rolling(window, center=True).sum()[ndays-1::ndays]
      
      rolleach(df, 3, 5)
      Out[95]: 
                     A
      2013-01-02  10.0
      2013-01-05  25.0
      2013-01-08  40.0
      
      from __future__ import division
      import numpy as np
      
      #The date column is unimportant for calculations.
      # I leave extracting the numbers' column from the dataframe
      # and adding a corresponding element from data column to each result
      # as an exercise for the reader
      data = np.random.randint(100,size=100000)
      
      def calc_trailing_data_with_interval(data,n,k):
          """Iterate over `data', computing sums of `n' trailing elements
          for each `k'th element.
          @type data: ndarray
          @param n: number of trailing elements to sum up
          @param k: interval with which to calculate sums
          """
          lim_index=len(data)-k+1
      
          nsums = int(np.ceil(n/k))
          sums = np.zeros(nsums,dtype=data.dtype)
          M=n%k
          Mp=k-M
      
          index=0
          currentsum=0
      
          while index<lim_index:
              for _ in range(Mp):
                  #np.take is awkward, requiring a full list of indices to take
                  for i in range(currentsum,currentsum+nsums-1):
                      sums[i%nsums]+=data[index]
                  index+=1
              for _ in range(M):
                  sums+=data[index]
                  index+=1
              yield sums[currentsum]
              currentsum=(currentsum+1)%nsums
      
      def calc_trailing_data_with_interval(data,n,k):
          """Iterate over `data', computing sums of `n' trailing elements
          for each `k'th element.
          @type data: ndarray
          @param n: number of trailing elements to sum up
          @param k: interval with which to calculate sums
          """
          lim_index=len(data)-k+1
      
          nsums = int(np.ceil(n/k))
          sums = np.zeros(nsums,dtype=data.dtype)
          M=n%k
          Mp=k-M
          RM=range(M)     #cache for efficiency
          RMp=range(Mp)   #cache for efficiency
      
          index=0
          currentsum=0
          currentsum_ranges=[range(currentsum,currentsum+nsums-1)
                  for currentsum in range(nsums)]     #cache for efficiency
      
          while index<lim_index:
              for _ in RMp:
                  #np.take is unusable as it allocates another array rather than view
                  for i in currentsum_ranges[currentsum]:
                      sums[i%nsums]+=data[index]
                  index+=1
              for _ in RM:
                  sums+=data[index]
                  index+=1
              yield sums[currentsum]
              currentsum=(currentsum+1)%nsums