主要目标
在这个项目中,我将试图找出什么样的因素会影响Steam的折扣率并建立一个线性回归模型来预测折扣率。
数据
数据将直接从Steam的官方网站上获取。
https://store.steampowered.com/tags/en/Strategy/
我们使用Python编写抓取程序,使用的库包括:
“re”— regex”,用于模式查找。
“CSV”— 用于将数据写入.CSV文件中,使用pandas进行处理。
“requests”— 向Steam网站发送http/https请求
“BeautifulSoup”—用于查找html元素/标记。
当数据加载到Pandas中时,大概的显示如下所示:
我们训练模型的目标是:数据集中预测的目标是“折扣百分比”,DiscountPercentage
数据清洗
采集的原始数据包含许多我们不需要的东西:
一、 免费游戏,没有价格,包括演示和即将发布。
二、不打折的游戏。
三、非数值的数据
我们在把他们清洗的同时,还可以做一些特征工程。
在后面的章节中,我将介绍在建模和测试时所做的所有特性工程,但是对于基线模型,可以使用以下方式
添加一个“季节”栏,查看游戏发布的季节:
完成上述过程后,我们现在可以从dataframe中删除所有基于字符串的列:
这个过程还将把我们的结果从14806个和12个特征缩小到370个条目和7个特征。
不好的消息是这意味着由于样本量较小,该模型很容易出现误差。
数据分析
分析部分包括三个步骤:
- 数据探索分析(EDA)
- 特征工程(FE)
- 建模
一般工作流程如下所示:
EDA以找到的特征-目标关系(通过对图/热图、Lasso 系数等)
根据可用信息,进行特征工程(数学转换、装箱、获取虚拟条目
使用R方和/或其他指标(RMSE、MAE等)建模和评分
冲洗并重复以上步骤,直到尝试并用尽所有潜在的特征工程想法或达到可接受的评分分数(例如R方)。
# Plotting heat map as part of EDA sns.heatmap(df.corr(),cmap="YlGnBu",annot=True) plt.show() # A compiled function to automatically split data, make and score models. And showing you what's the most relevant features. def RSquare(df, col): X, y = df.drop(col,axis=1), df[col] X, X_test, y, y_test = train_test_split(X, y, test_size=.2, random_state=10) #hold out 20% of the data for final testing #this helps with the way kf will generate indices below X, y = np.array(X), np.array(y) kf = KFold(n_splits=5, shuffle=True, random_state = 50) cv_lm_r2s, cv_lm_reg_r2s, cv_lm_poly_r2s, cv_lasso_r2s = [], [], [], [] #collect the validation results for both models for train_ind, val_ind in kf.split(X,y): X_train, y_train = X[train_ind], y[train_ind] X_val, y_val = X[val_ind], y[val_ind] #simple linear regression lm = LinearRegression() lm_reg = Ridge(alpha=1) lm_poly = LinearRegression() lm.fit(X_train, y_train) cv_lm_r2s.append(lm.score(X_val, y_val)) #ridge with feature scaling scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_val_scaled = scaler.transform(X_val) lm_reg.fit(X_train_scaled, y_train) cv_lm_reg_r2s.append(lm_reg.score(X_val_scaled, y_val)) poly = PolynomialFeatures(degree=2) X_train_poly = poly.fit_transform(X_train) X_val_poly = poly.fit_transform(X_val) lm_poly.fit(X_train_poly, y_train) cv_lm_poly_r2s.append(lm_poly.score(X_val_poly, y_val)) #Lasso std = StandardScaler() std.fit(X_train) X_tr = std.transform(X_train) X_te = std.transform(X_test) X_val_lasso = std.transform(X_val) alphavec = 10**np.linspace(-10,10,1000) lasso_model = LassoCV(alphas = alphavec, cv=5) lasso_model.fit(X_tr, y_train) cv_lasso_r2s.append(lasso_model.score(X_val_lasso, y_val)) test_set_pred = lasso_model.predict(X_te) column = df.drop(col,axis=1) to_print = list(zip(column.columns, lasso_model.coef_)) pp = pprint.PrettyPrinter(indent = 1) rms = sqrt(mean_squared_error(y_test, test_set_pred)) print('Simple regression scores: ', cv_lm_r2s, '\n') print('Ridge scores: ', cv_lm_reg_r2s, '\n') print('Poly scores: ', cv_lm_poly_r2s, '\n') print('Lasso scores: ', cv_lasso_r2s, '\n') print(f'Simple mean cv r^2: {np.mean(cv_lm_r2s):.3f} +- {np.std(cv_lm_r2s):.3f}') print(f'Ridge mean cv r^2: {np.mean(cv_lm_reg_r2s):.3f} +- {np.std(cv_lm_reg_r2s):.3f}') print(f'Poly mean cv r^2: {np.mean(cv_lm_poly_r2s):.3f} +- {np.std(cv_lm_poly_r2s):.3f}', '\n') print('lasso_model.alpha_:', lasso_model.alpha_) print(f'Lasso cv r^2: {r2_score(y_test, test_set_pred):.3f} +- {np.std(cv_lasso_r2s):.3f}', '\n') print(f'MAE: {np.mean(np.abs(y_pred - y_true)) }', '\n') print('RMSE:', rms, '\n') print('Lasso Coef:') pp.pprint (to_print)
先贴一些代码,后面做详细解释
第一次尝试:基本模型,删除评论少于30条的游戏
# Setting a floor limit of 30 df1 = df1[df1.Reviews > 30] Best Model: Lasso Score: 0.419 +- 0.073
第二次:“Reviews” & “OriginalPrice” 进行对数变换
df2.Reviews = np.log(df2.Reviews) df2.OriginalPrice = df2.OriginalPrice.astype(float) df2.OriginalPrice = np.log(df2.OriginalPrice) Best Model: Lasso Score: 0.437 +- 0.104
第三次:将mantag进行onehot编码
# Checking to make sure the dummies are separated correctly pd.get_dummies(df3.Main_Tag).head(5) # Adding dummy categories into the dataframe df3 = pd.concat([df3, pd.get_dummies(df3.Main_Tag).astype(int)], axis = 1) # Drop original string based column to avoid conflict in linear regression df3.drop('Main_Tag', axis = 1, inplace=True) Best Model: Lasso Score: 0.330 +- 0.073