如何向量化 pandas 数据帧正向列值搜索
How to vectorize pandas dataframe forward column value search
我只想在正向搜索 pandas 数据框列中的目标值,如果找到更大的值,那么我想将索引差异记录为结果列。我已经设法用两个内部 for 循环来做到这一点,但速度非常慢。
这就是我想在一个简化的例子中实现的。
import pandas as pd
d = {
'Value' : [8,9,10,12,16,13,11,7,12,18],
'Target' : [12,12,11,15,19,11,16,11,17,18]
}
df = pd.DataFrame(data=d)
>>> df
Target Value
0 12 8
1 12 9
2 11 10
3 15 12
4 19 16
5 11 13
6 16 11
7 11 7
8 17 12
9 18 18
我们的第一个值为 8,我们的目标值为 12。我们期待在 Value 列中找到超过此目标值的值。我们在第 4 行找到它,值为 16。我要记录的是索引差异,即 4-0=4.
下一个值为 9,目标值为 12。我们在值中向前看并再次找到第 4 行,值为 16.Now 索引差异为 4-1=3
让我们跳到第 4 行。我们开始寻找从索引 5 开始的目标值。如果未找到值,则结果为 0。
这是我想要达到的结果列。
Target Value Result
0 12 8 4
1 12 9 3
2 11 10 1
3 15 12 1
4 19 16 0
5 11 13 3
6 16 11 3
7 11 7 1
8 17 12 1
9 18 18 0
这可以不用 for 循环来完成吗?
使用numpy广播进行比较,将numpy上三角矩阵设置为False
,通过numpy.argmax
获取第一个True
个索引,通过arange
减去并设置为0
所有否定:
t = df['Target'].values[:, None]
v = df['Value'].values
m = v > t
m[np.tril_indices(m.shape[1])] = False
print (m)
[[False False False False True True False False False True]
[False False False False True True False False False True]
[False False False True True True False False True True]
[False False False False True False False False False True]
[False False False False False False False False False False]
[False False False False False False False False True True]
[False False False False False False False False False True]
[False False False False False False False False True True]
[False False False False False False False False False True]
[False False False False False False False False False False]]
a = np.argmax(m, axis=1) - np.arange(len(df))
print (a)
[ 4 3 1 1 -4 3 3 1 1 -9]
df['new'] = np.where(a > 0, a, 0)
print (df)
Value Target new
0 8 12 4
1 9 12 3
2 10 11 1
3 12 15 1
4 16 19 0
5 13 11 3
6 11 16 3
7 7 11 1
8 12 17 1
9 18 18 0
您可以将其缩短为只有一个 for 循环。使用 Series.first_valid_index() 和布尔条件:
df['Result'] = 0
for i, target in enumerate(df.Target):
val = df[(df.Value>target) & (df.index>i)]['Value'].first_valid_index()
if val is not None:
df.at[i, 'Result'] = val - i
df
Value Target Result
0 8 12 4
1 9 12 3
2 10 11 1
3 12 15 1
4 16 19 0
5 13 11 3
6 11 16 3
7 7 11 1
8 12 17 1
9 18 18 0
条件查找 Value
大于目标的每一行,但也仅在目标的索引之后,first_valid_index
将 return 条件所在的第一个索引很满意。
我只想在正向搜索 pandas 数据框列中的目标值,如果找到更大的值,那么我想将索引差异记录为结果列。我已经设法用两个内部 for 循环来做到这一点,但速度非常慢。
这就是我想在一个简化的例子中实现的。
import pandas as pd
d = {
'Value' : [8,9,10,12,16,13,11,7,12,18],
'Target' : [12,12,11,15,19,11,16,11,17,18]
}
df = pd.DataFrame(data=d)
>>> df
Target Value
0 12 8
1 12 9
2 11 10
3 15 12
4 19 16
5 11 13
6 16 11
7 11 7
8 17 12
9 18 18
我们的第一个值为 8,我们的目标值为 12。我们期待在 Value 列中找到超过此目标值的值。我们在第 4 行找到它,值为 16。我要记录的是索引差异,即 4-0=4.
下一个值为 9,目标值为 12。我们在值中向前看并再次找到第 4 行,值为 16.Now 索引差异为 4-1=3
让我们跳到第 4 行。我们开始寻找从索引 5 开始的目标值。如果未找到值,则结果为 0。
这是我想要达到的结果列。
Target Value Result
0 12 8 4
1 12 9 3
2 11 10 1
3 15 12 1
4 19 16 0
5 11 13 3
6 16 11 3
7 11 7 1
8 17 12 1
9 18 18 0
这可以不用 for 循环来完成吗?
使用numpy广播进行比较,将numpy上三角矩阵设置为False
,通过numpy.argmax
获取第一个True
个索引,通过arange
减去并设置为0
所有否定:
t = df['Target'].values[:, None]
v = df['Value'].values
m = v > t
m[np.tril_indices(m.shape[1])] = False
print (m)
[[False False False False True True False False False True]
[False False False False True True False False False True]
[False False False True True True False False True True]
[False False False False True False False False False True]
[False False False False False False False False False False]
[False False False False False False False False True True]
[False False False False False False False False False True]
[False False False False False False False False True True]
[False False False False False False False False False True]
[False False False False False False False False False False]]
a = np.argmax(m, axis=1) - np.arange(len(df))
print (a)
[ 4 3 1 1 -4 3 3 1 1 -9]
df['new'] = np.where(a > 0, a, 0)
print (df)
Value Target new
0 8 12 4
1 9 12 3
2 10 11 1
3 12 15 1
4 16 19 0
5 13 11 3
6 11 16 3
7 7 11 1
8 12 17 1
9 18 18 0
您可以将其缩短为只有一个 for 循环。使用 Series.first_valid_index() 和布尔条件:
df['Result'] = 0
for i, target in enumerate(df.Target):
val = df[(df.Value>target) & (df.index>i)]['Value'].first_valid_index()
if val is not None:
df.at[i, 'Result'] = val - i
df
Value Target Result
0 8 12 4
1 9 12 3
2 10 11 1
3 12 15 1
4 16 19 0
5 13 11 3
6 11 16 3
7 7 11 1
8 12 17 1
9 18 18 0
条件查找 Value
大于目标的每一行,但也仅在目标的索引之后,first_valid_index
将 return 条件所在的第一个索引很满意。