熊猫:每行适用哪个阈值?

时间:2018-06-22 14:43:29

标签: python pandas

给出一个得分列,例如

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

3 个答案:

答案 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声称cutapply的{​​{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