在实验的时候遇到一个比较实际的问题,就是怎样对数据进行评分。比如我想根据样本的正确率进行打分,有两种方法,一种是将准确率排序,然后根据序号进行打分,这样可以排除极端数据的影响,但是准确率之间的差距就不能有效体现。第二种方法是将数据归一化作为评分,但这样容易受到极端数据的影响。有没有一种评分算法能两者兼顾?问了chatGPT4后给出了一种我觉得比较符合需求的想法
首先,将数据进行排序,然后计算每个数据点在总体中所处的位置(即其百分位数)。最后可以将这些百分位数转换为Z得分(也就是标准正态分布下的得分),这样就完成了归一化。
具体步骤如下:
1、将所有数据按照大小进行排序。
2、计算每个数据点在总体中所处的位置(即其百分位数)。例如,在100个观测值中,最小值为第1百分位,最大值为第100百分位。
3、将每个观测值对应到一个标准正态随机变量上。例如,如果一个观测值处于第25百分位,则它对应到标准正态随机变量上就是-0.6745(因为在标准正态随机变量上, 25% 的区域左侧对应着 Z = -0.6745)。
通过以上步骤,“极端”的原始评价会被映射到相对较小或较大但不极端的Z得分上,而原始评价之间的相对差异也会被保留下来。这样就可以在一定程度上兼顾到排除极端数据和体现准确率之间差距两个方面。
代码:
"""
获取一个列表数据的
基于分位数-正态分布转换的评分算法
"""
from scipy.stats import norm
def percentile_to_zscore(percentiles: list):
"""
获取一个百分比列表数据的z_scores
"""
z_scores = [norm.ppf(p) for p in percentiles]
return z_scores
def list_to_percentile(list_data: list, need_sort=False):
"""
对数据进行排名,生成百分比列表
"""
if need_sort:
list_data = sorted(list_data)
percentiles = [(list_data.index(data) + 1) / len(list_data) for data in list_data]
# 需要对最后的结果进行处理,否则最大数据的百分比为1在计算z_score会报错
percentiles.pop(-1)
percentiles.append(0.99)
return percentiles
def zscore_to_score(z_scores, min_score=1, max_score=100):
"""
把z分数重新映射指定分数区间
"""
min_z, max_z = min(z_scores), max(z_scores)
scores = [round((z - min_z) / (max_z - min_z) * (max_score - min_score) + min_score,2) for z in z_scores]
return scores
def list_to_score(list_data: list, need_sort=False):
"""
输入一个列表数据,返回基于分位数-正态分布转换的评分
:param list_data: 列表数据
:param need_sort: 是否需要排序,True/False
:return: 评分列表
"""
percentile = list_to_percentile(list_data, need_sort)
print(percentile)
zscore = percentile_to_zscore(percentile)
score = zscore_to_score(zscore)
return score
if __name__ == "__main__":
input_data = [1, 3, 5, 7, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19]
result_scores = list_to_score(input_data)
print(result_scores)