给出一个得分列,例如
scores = pd.DataFrame({"score":np.random.randn(10)})
和阈值
thresholds = pd.DataFrame({"threshold":[0.2,0.5,0.8]},index=[7,13,33])
我想找到每个分数的适用阈值,例如
score threshold
0 -1.613293 NaN
1 -1.357980 NaN
2 0.325720 7
3 0.116000 NaN
4 1.423171 33
5 0.282557 7
6 -1.195269 NaN
7 0.395739 7
8 1.072041 33
9 0.197853 NaN
IOW,对于每个得分s
,我都希望阈值t
如此
t = min(t: thresholds.threshold[t] < s)
我该怎么做?
PS。根据已删除的答案:
pd.cut(scores.score, bins=[-np.inf]+list(thresholds.threshold)+[np.inf],
labels=["low"]+list(thresholds.index))
答案 0 :(得分:2)
使用 pd.cut
scores['threshold'] = pd.cut(
scores.score,
bins=thresholds.threshold.values.tolist() + [np.nan],
labels=thresholds.index.values
)
score threshold
0 -1.613293 NaN
1 -1.357980 NaN
2 0.325720 7.0
3 0.116000 NaN
4 1.423171 33.0
5 0.282557 7.0
6 -1.195269 NaN
7 0.395739 7.0
8 1.072041 33.0
9 0.197853 NaN
This answer声称cut
比apply
的{{1}}慢。尽管digitize
在这里会发出警告,但这些时间是在很小的数据帧上,我相信它们会误导人们。这是一些较大的数据框:
cut
scores = pd.DataFrame({"score":np.random.randn(10)})
scores = pd.concat([scores]*10000)
%timeit pd.cut(scores.score,thresholds.threshold.values.tolist() + [np.nan],labels=thresholds.index.values)
4.41 ms ± 39.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
indeces = [None,] + thresholds.index.tolist()
%timeit scores["score"].apply(lambda x: indeces[np.digitize(x, thresholds["threshold"])])
1.64 s ± 18.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
只是隐藏了一个明确的for循环,而矢量被剪切了。
答案 1 :(得分:1)
您可以使用np.digitize
来实现:
indeces = [None,] + thresholds.index.tolist()
scores["score"].apply(
lambda x: indeces[np.digitize(x, thresholds["threshold"])])
答案 2 :(得分:0)
您可以使用merge_asof
进行一些操作以获得准确的结果。
(pd.merge_asof( scores.reset_index().sort_values('score'),
thresholds.reset_index(),
left_on='score', right_on= 'threshold', suffixes = ('','_'))
.drop('threshold',1).rename(columns={'index_':'threshold'})
.set_index('index').sort_index())
以及您的数据,您将得到:
score threshold
index
0 -1.613293 NaN
1 -1.357980 NaN
2 0.325720 7.0
3 0.116000 NaN
4 1.423171 33.0
5 0.282557 7.0
6 -1.195269 NaN
7 0.395739 7.0
8 1.072041 33.0
9 0.197853 NaN