如何在熊猫python中获得最接近的100除数

时间:2018-12-08 20:09:25

标签: python pandas

我想基于输入列在pandas数据框中添加一个新列。新添加的列必须这样填充。

  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
    

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

3 个答案:

答案 0 :(得分:4)

据我所知,这里没有一种不涉及显式迭代的直观方法,这对于numpypandas而言并不理想。但是,此问题的时间复杂度为O(n),这使其成为numba库的良好目标。这使我们能够提出一个非常有效的解决方案。

关于解决方案的一个便笺是,我使用(a + threshold // 2) // threshold * threshold四舍五入,与使用np.round(a, decimals=-2)相比,它显得冗长。这是由于使用numba的{​​{1}}标志的性质所致,它与nopython=True函数不兼容。


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))

如果您想将 rounded 值与输入值进行比较,而不是 actual 值,只需在循环中对上述函数进行以下更改,即可得到您问题的输出。

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]

答案 1 :(得分:2)

无论如何都不优雅,但是我想这不可能绕一个循环(可能是错误的!):

window.location.href = 'www.yourpage.com/activity/test';

输出:

vals = df1['input'].values
anchor = vals[0]
ch = np.zeros(len(vals))
ch.fill(np.nan)
for i in range(len(vals)):
    if abs(vals[i] - anchor) >= 100:
        anchor = vals[i]
        ch[i] = 1
    else:
        continue
ch[0] = 1

df['out_check'] = pd.Series(100* np.round((df['input'] * ch)/100)).ffill()

我相信 input output out_check 0 11700.15 11700 11700.0 1 11695.20 11700 11700.0 2 11661.00 11700 11700.0 3 11630.40 11700 11700.0 4 11666.10 11700 11700.0 5 11600.30 11700 11700.0 6 11600.00 11600 11600.0 7 11555.40 11600 11600.0 8 11655.20 11600 11600.0 9 11699.00 11600 11600.0 10 11701.55 11700 11700.0 11 11799.44 11700 11700.0 12 11604.65 11700 11700.0 13 11600.33 11700 11600.0 14 11599.65 11600 11600.0 中的最后两个值必须为1600。

答案 2 :(得分:0)

我想出的解决方案:

last = df.loc[0, 'input'].round(-2)
for ix in range(len(df)):
    inp = df.loc[ix, 'input']
    last = inp.round(-2) if abs(inp - last) >= 100 else last
    df.loc[ix, 'output'] = last

精确地产生OP给定的输出。