前言
本文所采用的数据为2020年8月率土之滨藏宝阁的上架商品的数据。数据搜集过程在上一篇文章:使用python+Selenium动态爬取《率土之滨》藏宝阁账号信息_GreyLZ的博客-CSDN博客。获取的数据包括账号价格,武将数量,战法数量,宝物数量,武将卡牌,典藏数量,武将卡牌进阶数量。以账号价格为因变量,武将数量,战法数量,宝物数量,武将卡牌,典藏数量,武将卡牌进阶数量为自变量,其中武将数量,战法数量,宝物数量,武将卡牌进阶数量为离散型变量,武将卡牌为0-1变量(表示是否拥有此武将,1表示拥有,0表示不拥有)。一共有5005个样本,227个变量。所使用的预测方法是随机森林以及XGBoost。
1.数据预处理
将武将卡牌转化为0,1向量,武将卡牌为0-1变量(表示是否拥有此武将,1表示拥有,0表示不拥有),将武将进阶数量转化为矩阵,每一个武将进阶数量最大为5次。(战法是否拥有与武将卡牌的操作类似)
# 对每个账号的武将是否拥有进行编码,有:1,没有:0
# 读取武将库
with open('AllWJ.json', 'r') as AllWJ:
ALLWJ = json.load(AllWJ)
# AllWJ0 = ALLWJ
# 创建武将矩阵
WJhave = np.zeros((numAccount,len(ALLWJ)))
# 武将进阶矩阵
WJJJ = np.zeros((numAccount,len(ALLWJ)))
for i in range(numAccount):
k = i + 1
# 读取每个账号的数据
with open('data/account%d.json' % k, 'r') as Alist:
ac = json.load(Alist)
ac8 = np.array(ac[8]) # 武将进阶
wujiang = ac[9] # 武将拥有
for jj in range(len(ALLWJ)):
if ALLWJ[jj] in wujiang:
WJhave[i, jj] = 1
# index0 = wujiang.index(ALLWJ[jj])
index0 = [i2 for i2, x in enumerate(wujiang) if x == ALLWJ[jj]]
#进阶数量
if sum(ac8[index0]) > 5:
WJJJ[i,jj] = 5
else:
WJJJ[i, jj] = sum(ac8[index0])
else:
WJhave[i, jj] = 0
画出价格分布直方图
可以明显看出,因变量价格并不服从正态分布,因此需要进行Box-Cox变换。
from scipy import stats
# 对价格进行正态性检验
Price_ks_test = stats.kstest(Price, 'norm')
Price, _ = stats.boxcox(Price) #对价格进行BoxCox变换
2.随机森林以及XGBoost预测价格
首先划分训练集与测试集。
# 分割数据集
from sklearn.model_selection import train_test_split
train_features, test_features, train_labels, test_labels = train_test_split(Features,Price, test_size = 0.25,random_state = 123)
构造随机森林模型以及训练模型。
from sklearn.ensemble import RandomForestRegressor
# Instantiate model 随机森林
rf = RandomForestRegressor(n_estimators= 200, random_state=648)
# Train the model on training data
rf.fit(train_features, train_labels)
计算模型的准确率。
from sklearn.metrics import r2_score
from sklearn.metrics import mean_squared_error
pre_test = rf.predict(train_features)
predictions = rf.predict(test_features)
def TEST(predictions,test_labels):
errors = abs(predictions - test_labels)
R2 = r2_score(test_labels, predictions)
print('R2:', R2)
print('Mean Absolute Error:', round(np.mean(errors), 2), 'degrees.')
# 均方误差
MSE = mean_squared_error(test_labels, predictions)
print('MSE:', MSE)
TEST(pre_test,train_labels)
TEST(predictions,test_labels)
其中R2是决定系数R-square ,Mean Absolute Error是平均绝对误差,MSE是均方误差。
接下来构造XGBoost模型,训练模型以及评估模型,模型效果如下表所示
# XGBoost模型
XGBRE = xgb.XGBRegressor(max_depth=5, learning_rate=0.1, n_estimators=200, silent=False, objective='reg:gamma')
XGBRE.fit(train_features, train_labels)
predictions2 = XGBRE.predict(test_features)
pre_test2 = XGBRE.predict(train_features)
TEST(pre_test2,train_labels)
TEST(predictions2,test_labels)
决定系数R-square |
均方误差MSE |
平均绝对误差MAE |
|
(随机森林)训练集 |
0.98371 |
192499.76 |
210.76 |
(随机森林)测试集 |
0.9023 |
1163607.211 |
544.63 |
(Xgboost)训练集 |
0.97365 |
311369.2249 |
302.76 |
(Xgboost)测试集 |
0.91767 |
980529.5865 |
509.24 |
决定系数R-square的取值(0-1),决定系数越大,说明自变量对因变量的解释程度越高,拟合效果越好。由表1可以看出,随机森林和Xgboost的回归决定系数R-square均大于0.9,达到好的拟合优度。
随机森林与XGBoost的plot scatter matrix:
接下来计算随机森林与XGBoost的特征重要性
# 武将importance排名
def WJFI(feature_importances,ALLWJ):
FI = list()
INPindex = 0
for fi in feature_importances:
if(fi[0] in ALLWJ):
INPindex = INPindex + 1
FI.append(list(fi))
print('Variable%d:'%INPindex,fi[0],'Importance:',fi[1])
return FI
# 所有变量importance排名
def Feature_Importances(fis,start,end):
importances = list(fis)
# sum(importances)
# List of tuples with variable and importance
feature_list = VarName[start:end]
feature_importances = [(feature, round(importance, 5)) for feature, importance in zip(feature_list, importances)]
# Sort the feature importances by most important first
feature_importances = sorted(feature_importances, key=lambda x: x[1], reverse=True)
wji = WJFI(feature_importances,ALLWJ)
return feature_importances,wji
importances = list(rf.feature_importances_)
FI0,WJI0 = Feature_Importances(importances,F_start,len(VarName))
将结果弄成表格形式
随机森林 |
Xgboost |
|||
变量名 |
重要性 |
变量名 |
重要性 |
|
1 |
武将数量 |
0.3007 |
武将数量 |
0.07675 |
2 |
典藏数量 |
0.29562 |
典藏数量 |
0.06218 |
3 |
吴吕蒙进阶 |
0.03022 |
蜀马云禄进阶 |
0.02873 |
4 |
吴陆逊进阶 |
0.01486 |
魏夏侯惇进阶 |
0.02177 |
5 |
蜀庞统进阶 |
0.01384 |
群甄洛进阶 |
0.02082 |
6 |
蜀马云禄进阶 |
0.01237 |
吴周瑜进阶 |
0.01747 |
7 |
吴周瑜进阶 |
0.01053 |
吴吕蒙进阶 |
0.01568 |
随机森林 |
Xgboost |
|||
武将名字 |
重要性 |
武将名字 |
重要性 |
|
1 |
蜀刘备 |
0.00606 |
蜀刘备 |
0.01431 |
2 |
汉皇甫嵩 |
0.00312 |
群马超 |
0.01311 |
3 |
蜀关银屏 |
0.00257 |
吴吕蒙 |
0.01261 |
4 |
吴吕蒙 |
0.00224 |
蜀关银屏 |
0.01246 |
5 |
魏徐晃 |
0.0017 |
汉皇甫嵩 |
0.01193 |
6 |
魏荀攸 |
0.0013 |
吴孙权 |
0.01178 |
7 |
蜀马岱 |
0.00117 |
魏曹操 |
0.00972 |
8 |
蜀庞统 |
0.00114 |
魏张辽 |
0.00939 |
9 |
汉董卓 |
0.00095 |
汉张机 |
0.00872 |
10 |
群马超 |
0.00089 |
汉董卓 |
0.00864 |
武将特征重要性可以表现玩家对不同武将的偏好程度。蜀刘备在武将特征重要性排在首位,接着是汉皇甫嵩(排名分别为2和5)和蜀关银屏(排名分别为3和4),吴吕蒙排名4和3。