import pandas as pd
import numpy as np
from collections import Counter
import statsmodels.api as sm
import scipy.stats
def rsr(data, weight=None, threshold=None, full_rank=False):
Result = pd.DataFrame()
n, m = data.shape
# 对数据编秩
if full_rank:
for i, X in enumerate(data.columns):
Result[f'X{str(i + 1)}:{X}'] = data.iloc[:, i]
Result[f'R{str(i + 1)}:{X}'] = data.iloc[:, i].rank(method="average") # 整次编制
else:
for i, X in enumerate(data.columns):
Result[f'X{str(i + 1)}:{X}'] = data.iloc[:, i]
Result[f'R{str(i + 1)}:{X}'] = 1 + (n - 1) * (data.iloc[:, i] - data.iloc[:, i].min()) / (
data.iloc[:, i].max() - data.iloc[:, i].min()) # 非整次编制,正向指标
# 计算秩和比
weight = 1 / m if weight is None else np.array(weight) / sum(weight)
Result['RSR'] = (Result.iloc[:, 1::2] * weight).sum(axis=1) / n # axis=1,将每一行的元素相加
# 加权的RSR
Result['RSR_Rank'] = Result['RSR'].rank(ascending=False) # RSR值的排序
# 绘制 RSR 分布表
RSR = Result['RSR']
RSR_RANK_DICT = dict(zip(RSR.values, RSR.rank().values))
Distribution = pd.DataFrame(index=sorted(RSR.unique())) # 编号
Distribution['f'] = RSR.value_counts().sort_index() # 频数
Distribution['Σ f'] = Distribution['f'].cumsum() # 累计频数
Distribution['Rf'] = [RSR_RANK_DICT[i] for i in Distribution.index] #
Distribution['R/n*100%'] = Distribution['Rf'] / n # 根据累计频数算累计频率
Distribution.iat[-1, -1] = 1 - 1 / (4 * n) # 修正最后一项累计频率
Distribution['Probit'] = 5 - scipy.stats.norm.isf(Distribution.iloc[:, -1]) # inverse survival function 将累计频率换算为概率单位
print(Distribution)
# 计算回归方差并进行回归分析
r0 = np.polyfit(Distribution['Probit'], Distribution.index, deg=1) # x,y
model = sm.OLS(Distribution.index, sm.add_constant(Distribution['Probit'])) # y,x
result = model.fit()
print(result.summary())
# 残差检验
z_error, p_error = scipy.stats.normaltest(
result.resid.values) # tests the null hypothesis that a sample comes from a normal distribution
print("残差分析: ", p_error)
if r0[1] > 0:
print(f"\n回归直线方程为:y = {r0[0]} Probit + {r0[1]}")
else:
print(f"\n回归直线方程为:y = {r0[0]} Probit - {abs(r0[1])}")
# 代入回归方程并分档排序
Result['Probit'] = Result['RSR'].apply(lambda item: Distribution.at[item, 'Probit'])
Result['RSR Regression'] = np.polyval(r0, Result['Probit'])
C_level=scipy.stats.norm.ppf(0.3) + 5
B_level=scipy.stats.norm.ppf(0.8)+5
A_level=10
threshold = np.polyval(r0, [0, C_level, B_level, A_level]) if threshold is None else np.polyval(r0, threshold)
Result['Level'] = pd.cut(Result['RSR Regression'], threshold,
labels=range(len(threshold) - 1, 0, -1)) # Probit分组[(2, 4] < (4, 6] < (6, 8]]
# 方差齐性检验
x1=Result.loc[Result["Level"]==1,"RSR Regression"]
x2 = Result.loc[Result["Level"] == 2, "RSR Regression"]
x3 = Result.loc[Result["Level"] == 3, "RSR Regression"]
stat, p = scipy.stats.bartlett(x1, x2, x3)
print(stat, p)
print(Counter(Result["Level"]))
print(Result)
return Result, Distribution
def rsrAnalysis(data, file_name=None, **kwargs):
Result, Distribution = rsr(data, **kwargs)
file_name = 'RSR 分析结果报告.xlsx' if file_name is None else file_name + '.xlsx'
Excel_Writer = pd.ExcelWriter(file_name)
Result.to_excel(Excel_Writer, '综合评价结果')
Result.sort_values(by='Level', ascending=False).to_excel(Excel_Writer, '分档排序结果')
Distribution.to_excel(Excel_Writer, 'RSR分布表')
Excel_Writer.save()
data=pd.read_csv("已清理数据问一.csv") # 默认将第一行认定为列名
# print(data.columns)
data_new=data[["总里程","运输时长","业务类型","运输等级","计划发车时间","车辆吨位","需求紧急程度","需求类型2"]]
# 将data成本类指标转化为效益类
data_new.loc[:,"业务类型"]=1/data_new.loc[:,"业务类型"]
data_new.loc[:,"运输等级"]=1/data_new.loc[:,"运输等级"]
rsr(data_new,weight=[0.359, 0.168, 0.075, 0.035, 0.065, 0.194, 0.087, 0.017])
rsrAnalysis(data_new,weight=[0.359, 0.168, 0.075, 0.035, 0.065, 0.194, 0.087, 0.017])