我想基于输入列在pandas数据框中添加一个新列。新添加的列必须这样填充。
将从下一行开始重复输出,直到与输入值的差大于或等于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
在大熊猫中最优雅的方法是什么?
答案 0 :(得分:4)
据我所知,这里没有一种不涉及显式迭代的直观方法,这对于numpy
和pandas
而言并不理想。但是,此问题的时间复杂度为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给定的输出。