如何使用Python计算一个数据列相对于另一个数据列的百分位排名。

8
我是一位有用的助手,能够翻译文本。

我有两列数据表示相同的数量; 一列来自我的训练数据,另一列来自我的验证数据。

我知道如何使用以下方法有效地计算训练数据的百分位数排名:

pandas.DataFrame(training_data).rank(pct = True).values

我的问题是,如何高效地获取验证数据列相对于训练数据列的类似百分位排名集合?也就是说,对于验证数据列中的每个值,我如何找到它在训练数据列中所有值中的百分位排名?我已经尝试过这样做:
def percentrank(input_data,comparison_data):
    rescaled_data = np.zeros(input_data.size)
    for idx,datum in enumerate(input_data):
        rescaled_data[idx] =scipy.stats.percentileofscore(comparison_data,datum)
    return rescaled_data/100

但我不确定这是否正确,而且它非常缓慢,因为它对于for循环中的每个值都执行了大量冗余计算。

任何帮助将不胜感激!

3个回答

20

这里有一个解决方案。 对训练数据进行排序,然后在验证数据上使用searchsorted函数。

import pandas as pd
import numpy as np

# Generate Dummy Data
df_train = pd.DataFrame({'Values': 1000*np.random.rand(15712)})

#Sort Data
df_train = df_train.sort_values('Values')

# Calculating Rank and Rank_Pct for demo purposes 
#but note that it is not needed for the solution
# The ranking of the validation data below does not depend on this
df_train['Rank'] = df_train.rank()
df_train['Rank_Pct']= df_train.Values.rank(pct=True)

# Demonstrate how Rank Percentile is calculated
# This gives the same value as .rank(pct=True)
pct_increment = 1./len(df_train)
df_train['Rank_Pct_Manual'] = df_train.Rank*pct_increment

df_train.head()

       Values  Rank  Rank_Pct  Rank_Pct_Manual
2724  0.006174   1.0  0.000064         0.000064
3582  0.016264   2.0  0.000127         0.000127
5534  0.095691   3.0  0.000191         0.000191
944   0.141442   4.0  0.000255         0.000255
7566  0.161766   5.0  0.000318         0.000318

现在使用searchsorted来获取验证数据的Rank_Pct。

# Generate Dummy Validation Data
df_validation = pd.DataFrame({'Values': 1000*np.random.rand(1000)})

# Note searchsorted returns array index. 
# In sorted list rank is the same as the array index +1
df_validation['Rank_Pct'] = (1 + df_train.Values.searchsorted(df_validation.Values))*pct_increment

这是最终df_validation数据框的前几行:

print df_validation.head()
      Values  Rank_Pct
0  307.378334  0.304290
1  744.247034  0.744208
2  669.223821  0.670825
3  149.797030  0.145621
4  317.742713  0.314218

5
上面的不错解决方案有一个小改进,就是对从左到右搜索和从右到左搜索找到的位置进行平均:
df_validation['Rank_Pct'] = (0.5 + 0.5*df_train.Values.searchsorted(df_validation.Values, side='left') + 0.5*df_train.Values.searchsorted(df_validation.Values, side='right'))*pct_increment

在某些情况下,该更改对于一个值多次出现的情况非常重要。考虑在[1,2,2,2,4]中搜索2-从左侧搜索得到1,而从右侧搜索则得到3.将两者平均得到的百分位排名与pandas .rank(pct=True)例程相同。


1
来晚了,但这里有一个简洁的解决方案。
from scipy import stats

training = pd.Series([64,63,67,69,67])
test = pd.Series([66,72])
training_percentiles = training.rank(pct=True) * 100
testing_percentiles = test.apply(lambda x: stats.percentileofscore(training, x))

训练百分位数:

0     40.0
1     20.0
2     70.0
3    100.0
4     70.0

测试百分位数:

0     40.0
1    100.0

我已经使用序列完成了这项任务,但同样的方法也可以应用于数据框架。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接