我有一个看起来像这样的数据框:
index value
0 1
1 1
2 2
3 3
4 2
5 1
6 1
我想要的是每个值返回前一个较小值的索引,以及前一个“ 1”值的索引。如果值为1,则不需要它们(两个值都可以是-1
或其他值)。
所以我追求的是:
index value previous_smaller_index previous_1_index
0 1 -1 -1
1 1 -1 -1
2 2 1 1
3 3 2 1
4 2 1 1
5 1 -1 -1
6 1 -1 -1
我尝试使用滚动,累积函数等,但无法弄清楚。 任何帮助将不胜感激!
编辑: SpghttCd已经为“以前的1”问题提供了很好的解决方案。我正在为“以前的小”问题寻找一只不错的熊猫眼线。 (当然,当然,对于这两个问题,也欢迎使用更好的解决方案)
答案 0 :(得分:6)
使用与argmax
的矢量化numpy广播比较可以找到“ previous_smaller_index”。
可以使用groupby
医用口罩上的idxmax
和cumsum
来解决“ previous_1_index”。
m = df.value.eq(1)
u = np.triu(df.value.values < df.value[:,None]).argmax(1)
v = m.cumsum()
df['previous_smaller_index'] = np.where(m, -1, len(df) - u - 1)
df['previous_1_index'] = v.groupby(v).transform('idxmax').mask(m, -1)
df
index value previous_smaller_index previous_1_index
0 0 1 -1 -1
1 1 1 -1 -1
2 2 2 1 1
3 3 3 2 1
4 4 2 1 1
5 5 1 -1 -1
6 6 1 -1 -1
如果您希望将它们作为衬板使用,可以将几行压缩成一条:
m = df.value.eq(1)
df['previous_smaller_index'] = np.where(
m, -1, len(df) - np.triu(df.value.values < df.value[:,None]).argmax(1) - 1
)[::-1]
# Optimizing @SpghttCd's `previous_1_index` calculation a bit
df['previous_1_index'] = (np.where(
m, -1, df.index.where(m).to_series(index=df.index).ffill(downcast='infer'))
)
df
index value previous_1_index previous_smaller_index
0 0 1 -1 -1
1 1 1 -1 -1
2 2 2 1 1
3 3 3 1 2
4 4 2 1 1
5 5 1 -1 -1
6 6 1 -1 -1
总体效果
设置和性能基准测试是使用perfplot
完成的。可以在this gist上找到该代码。
时间是相对的(y刻度是对数的)。
previous_1_index
效果
答案 1 :(得分:2)
您可以尝试
df = pd.DataFrame({'value': [1, 1, 2, 3, 2, 1, 1, 2, 3, 4, 5]})
df['prev_smaller_idx'] = df.apply(lambda x: df.index[:x.name][(x.value>df.value)[:x.name]].max(), axis=1)
df['prev_1_idx'] = pd.Series(df.index.where(df.value==1)).shift()[df.value!=1].ffill()
# value prev_smaller_idx prev_1_idx
#0 1 NaN NaN
#1 1 NaN NaN
#2 2 1.0 1.0
#3 3 2.0 1.0
#4 2 1.0 1.0
#5 1 NaN NaN
#6 1 NaN NaN
#7 2 6.0 6.0
#8 3 7.0 6.0
#9 4 8.0 6.0
#10 5 9.0 6.0
答案 2 :(得分:1)
此功能应该起作用:
def func(values, null_val=-1):
# Initialize with arbitrary value
prev_small = values * -2
prev_1 = values * -2
# Loop through values and find previous values
for n, x in enumerate(values):
prev_vals = values.iloc[:n]
prev_small[n] = prev_vals[prev_vals < x].index[-1] if (prev_vals < x).any() else null_val
prev_1[n] = prev_vals[prev_vals == 1].index[-1] if x != 1 and (prev_vals == 1).any() else null_val
return prev_small, prev_1
df = pd.DataFrame({'value': [1, 1, 2, 3, 2, 1, 1,]})
df['previous_small'], df['previous_1'] = func(df['value'])
输出:
value previous_small previous_1
0 1 -1 -1
1 1 -1 -1
2 2 1 1
3 3 2 1
4 2 1 1
5 1 -1 -1
6 1 -1 -1
答案 3 :(得分:1)
这里是做previous_smaller_index
l=list(zip(df['index'],df.value))[::-1]
t=[]
n=len(l)
for x in l:
if x[1]==1:
t.append(-1)
else:
t.append(next(y for y in l[n-x[0]:] if y[1]<x[1])[0])
df['previous_smaller_index']=t[::-1]
df
Out[71]:
index value previous_smaller_index
0 0 1 -1
1 1 1 -1
2 2 2 1
3 3 3 2
4 4 2 1
5 5 1 -1
6 6 1 -1
获取前1个
df['index'].where(df.value==1).ffill().where(df.value!=1,-1)
Out[77]:
0 -1.0
1 -1.0
2 1.0
3 1.0
4 1.0
5 -1.0
6 -1.0
Name: index, dtype: float64
重新分配
df['previous_1_index']=df['index'].where(df.value==1).ffill().where(df.value!=1,-1)
df
Out[79]:
index value previous_smaller_index previous_1_index
0 0 1 -1 -1.0
1 1 1 -1 -1.0
2 2 2 1 1.0
3 3 3 2 1.0
4 4 2 1 1.0
5 5 1 -1 -1.0
6 6 1 -1 -1.0