首页 > 解决方案 > 如何在pandas python中获得最近的除以100的数字

问题描述

我想根据输入列在熊猫数据框中添加一个新列。必须像这样填充新添加的列。

  1. 第一行必须用最接近的除以 100 的数字填充。
  2. 从下一行开始,将重复输出,直到其与输入值的差异大于或等于 100。

    input       output
    11700.15    11700
    11695.20    11700
    11661.00    11700
    11630.40    11700
    11666.10    11700
    11600.30    11700
    11600.00    11600
    11555.40    11600
    11655.20    11600
    11699.00    11600
    11701.55    11700
    11799.44    11700
    11604.65    11700
    11600.33    11700
    11599.65    11600
    

在熊猫中最优雅的方法是什么?

标签: pythonpandas

解决方案


据我所知,这里没有不涉及显式迭代的直观方法,这对于numpyand并不理想pandas。然而,这个问题的时间复杂度是 O(n),这使它成为numba图书馆的一个很好的目标。这使我们能够提出一个非常有效的解决方案。

关于我的解决方案的一个注释,我使用 using (a + threshold // 2) // threshold * threshold,与 using 相比看起来很冗长np.round(a, decimals=-2)。这是由于使用numba's nopython=True, flag 的性质,它与函数不兼容np.round


from numba import jit

@jit(nopython=True)
def cumsum_with_threshold(arr, threshold):
       """
       Rounds values in an array, propogating the last value seen until
       a cumulative sum reaches a threshold
       :param arr: the array to round and sum
       :param threshold: the point at which to stop propogation
       :return: rounded output array
       """

       s = a.shape[0]
       o = np.empty(s)
       d = a[0]
       r = (a + threshold // 2) // threshold * threshold
       c = 0
       o[0] = r[0]

       for i in range(1, s):
           if np.abs(a[i] - d) > threshold:
               o[i] = r[i]
               d = a[i]
           else:
               o[i] = o[i - 1]

       return o

让我们测试一下:

a = df['input'].values
pd.Series(cumsum_with_threshold(a, 100))

0     11700.0
1     11700.0
2     11700.0
3     11700.0
4     11700.0
5     11700.0
6     11600.0
7     11600.0
8     11600.0
9     11600.0
10    11700.0
11    11700.0
12    11700.0
13    11600.0
14    11600.0
dtype: float64

如果您想将舍入值与输入进行比较,而不是实际值,只需在循环中对上面的函数进行以下更改,这将给出您问题的输出。

for i in range(1, s):
   if np.abs(a[i] - d) > t:
       o[i] = r[i]
       # OLD d = a[i]
       d = r[i]
   else:
       o[i] = o[i - 1]

为了测试效率,让我们在一个更大的数据集上运行它:

l = np.random.choice(df['input'].values, 10_000_000)

%timeit cumsum_with_threshold(l, 100)
1.54 µs ± 7.93 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

推荐阅读