【问题标题】:Pandas count values greater than current row in the last n rowsPandas 在最后 n 行中计数大于当前行的值
【发布时间】:2018-12-04 23:54:39
【问题描述】:

如何获取最后 n 行中大于当前行的值的计数?

假设我们有一个如下的数据框:

    col_a
0    8.4
1   11.3
2    7.2
3    6.5
4    4.5
5    8.9

我正在尝试获取如下表,其中 n=3。

    col_a   col_b
0     8.4       0
1    11.3       0
2     7.2       2
3     6.5       3
4     4.5       3
5     8.9       0

提前致谢。

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:
    n = 3
    df['col_b'] = df.apply(lambda row: sum(row.col_a <= df.col_a.loc[row.name - n: row.name-1]), axis=1)
    
    Out[]: 
       col_a  col_b
    0    8.4      0
    1   11.3      0
    2    7.2      2
    3    6.5      3
    4    4.5      3
    5    8.9      0
    

    【讨论】:

    • 不幸的是,您的代码输出错误,因此无法添加计时。对不起。
    • @jezrael 你这是什么意思?
    【解决方案2】:

    使用pd.Series.items 的列表推导:

    n = 3
    df['count'] = [(j < df['col_a'].iloc[max(0, i-3):i]).sum() \
                   for i, j in df['col_a'].items()]
    

    等效地,使用enumerate:

    n = 3
    df['count'] = [(j < df['col_a'].iloc[max(0, i-n):i]).sum() \
                   for i, j in enumerate(df['col_a'])]
    

    结果:

    print(df)
    
       col_a  count
    0    8.4      0
    1   11.3      0
    2    7.2      2
    3    6.5      3
    4    4.5      3
    5    8.9      0
    

    【讨论】:

      【解决方案3】:

      在 pandas 中最好不要循环,因为速度慢,这里最好使用 rolling 和自定义函数:

      n = 3
      df['new'] = (df['col_a'].rolling(n+1, min_periods=1)
                              .apply(lambda x: (x[-1] < x[:-1]).sum())
                              .astype(int))
      print (df)
         col_a  new
      0    8.4    0
      1   11.3    0
      2    7.2    2
      3    6.5    3
      4    4.5    3
      5    8.9    0
      

      如果性能很重要,请使用strides

      n = 3
      x = np.concatenate([[np.nan] * (n), df['col_a'].values])
      
      def rolling_window(a, window):
          shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
          strides = a.strides + (a.strides[-1],)
          return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)
      arr = rolling_window(x, n + 1)
      
      df['new'] = (arr[:, :-1] > arr[:, [-1]]).sum(axis=1)
      print (df)
         col_a  new
      0    8.4    0
      1   11.3    0
      2    7.2    2
      3    6.5    3
      4    4.5    3
      5    8.9    0
      

      性能:这里用perfplot小窗口n = 3

      np.random.seed(1256)
      n = 3
      
      def rolling_window(a, window):
          shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
          strides = a.strides + (a.strides[-1],)
          return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)
      
      def roll(df):
          df['new'] = (df['col_a'].rolling(n+1, min_periods=1).apply(lambda x: (x[-1] < x[:-1]).sum(), raw=True).astype(int))
          return df
      
      def list_comp(df):
          df['count'] = [(j < df['col_a'].iloc[max(0, i-3):i]).sum() for i, j in df['col_a'].items()]
          return df
      
      def strides(df):
          x = np.concatenate([[np.nan] * (n), df['col_a'].values])
          arr = rolling_window(x, n + 1)
          df['new1'] = (arr[:, :-1] > arr[:, [-1]]).sum(axis=1)
          return df
      
      
      def make_df(n):
          df = pd.DataFrame(np.random.randint(20, size=n), columns=['col_a'])
          return df
      
      perfplot.show(
          setup=make_df,
          kernels=[list_comp, roll, strides],
          n_range=[2**k for k in range(2, 15)],
          logx=True,
          logy=True,
          xlabel='len(df)')
      

      我也很好奇大窗口的性能,n = 100

      【讨论】:

      • 我可以确认这远远胜过其他答案。我是熊猫新手,我只是不知道如何过滤掉滚动系列。
      • @koray1396 - 问题真的很有趣,回答有点慢,所以尝试添加更好的。所以推荐使用这个 - rolling 更简单,strides 复杂,但更快。
      • @koray1396 - 在 pandas 中是更简单的规则,如果存在更好更快的矢量化解决方案,请避免 loops 之类的列表推导。
      • 只是为了清楚roll 方法更快,但由于apply + lambda,它仍然没有矢量化。 strides 方法确实是矢量化的,如果你能理解逻辑,这是一个很好的解决方案。
      猜你喜欢
      • 1970-01-01
      • 2023-01-24
      • 1970-01-01
      • 2020-10-30
      • 2019-08-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多