完美的观察者模式实现,顺便吐槽下jdk自带的观察者模式

grafana部署监控tomcat

  返回  

02 单个变量的预分析

2021/7/20 15:06:06 浏览:

02 单个变量的预分析

  • 摘要
  • 1 预分析: (单个变量处理)
    • 1.1 缺失值
    • 1.2 异常值
      • 1.2.1 处理超过上下边缘的异常值(连续变量)
      • 1.2.2 内容评级转成多分类, 新增"app描述"的字数统计列
      • 1.2.3 对"种类"进行过滤
    • 1.3 特征筛选
    • 1.4 共线性
    • 1.5 变换
  • 2 预分析结果: 评分

摘要

上一篇文章已经对付费App进行了探索性数据分析, 初步了解了数据的类型与分布.
本文会基于之前对数据的分析结果, 继续对单个变量进行预分析, 为后面的多个变量预分析做好准备, 也为建模这步奠定好的基础.

之后还会陆续更新建模阶段: (多变量) 预分析 --> 建模 --> 修正
还有应用作为更下一阶段,包含但不限于: 评估–> 应用 --> 结果可视化

1 预分析: (单个变量处理)

1.1 缺失值

在描述统计中, 可以看到本例数据没有缺失值,不用处理

1.2 异常值

df.iloc[:,1:].hist(figsize=(15,15));

在这里插入图片描述

1.2.1 处理超过上下边缘的异常值(连续变量)

思路: 以上下边缘为边界,超过上/下边缘的值用边缘值来代替

# 查看各个变量的上下边缘(下边缘最小为0,有小于0的就直接用0代替)
# 1.价格
a1 = df['price'].quantile(0.75)
b1 = df['price'].quantile(0.25)
print('price的上下边缘:(',0,',',a1+1.5*(a1-b1),')') # 下边缘小于0
# 2.app大小
a2 = df['size_bytes_in_MB'].quantile(0.75)
b2 = df['size_bytes_in_MB'].quantile(0.25)
print('app大小的上下边缘:(',0,',',a2+1.5*(a2-b2),')') # 下边缘小于0
# 3.评论总人数
a3 = df['rating_count_tot'].quantile(0.75)
b3 = df['rating_count_tot'].quantile(0.25)
print('评论总人数的上下边缘:(',0,',',a3+1.5*(a3-b3),')') # 下边缘小于0

Out:
price的上下边缘:( 0 , 9.49 )
app大小的上下边缘:( 0 , 508.2725 )
评论总人数的上下边缘:( 0 , 3847.25 )

# 强异常值的处理:{变量的下边缘,名字,上边缘} 
var = [(0,'price',9.49),(0,'size_bytes_in_MB',558.42125),(0,'rating_count_tot',3847.25)]
# 分别处理上边缘和下边缘,(上下边缘的)中间那段就直接复制过来: df.copy()
for (t,i,j) in var: # 所有超出两端拐点的,(eg:值为100),都用t,j的值来代替
    df[i+str("01")] = np.where(df[i]>=j,j,np.where(df[i]<=t,t,df[i].copy()))

处理完成后, 查看总体的列,能看到多出来这3列带"01"的,就是已经处理好超过上下边缘值的总体了
在这里插入图片描述
把 ‘price’, ‘rating_count_tot’, 'size_bytes_in_MB’这三列删除, 将数据保存为: df12
再继续后面操作

1.2.2 内容评级转成多分类, 新增"app描述"的字数统计列

  1. 从之前的种类个数分布可以知道, 只有少数几个占了绝大部分, 因此想到"二八法则",
    把累积和到80%的种类保留,剩下的20%合并成一个新的种类"其他"(‘else’)
  2. 关于"app_desc"这个app描述的变量, 暂时新增一列,记录其字数’app_desc_counts’,作为一个能够参与到计算中的变量(考虑方向: app的描述字数越多, 能够描述的范围就越齐全, 在用户为app付费时, 用户也能够明白app是否与自身需求相符, 也就更愿意为其付费)
    在这里插入图片描述
# 还要处理的东西:
# 1.内容评级转成多分类(数值型1~4) #replace是不会在原来的字符串上面替换的,新建一个
df12['cont_rating01'] = df12['cont_rating'].replace({'4+':1,'9+':2,'12+':3,'17+':4})
df12.drop('cont_rating',inplace=True,axis=1)
# 2.换app描述: 增加一列app_desc_counts(记录app_desc的字数) 7'app_desc'
for i in range(0,df12.shape[0]):
    df12['app_desc_counts'][i] = len(df12['app_desc'][i])
df12.drop('app_desc',inplace=True,axis=1)

执行成功后, 会得到一个警告(后续会更新关于这个警告的内容)
在这里插入图片描述

1.2.3 对"种类"进行过滤

对"种类"进行处理, 占比为80%的种类保留,剩下的合并为"其他"类,(从下面计算结果来看: 一共7类)

# 1.对"种类"进行过滤: 看哪些变量是要保留的
list = [] 
k = 0 # 累加器
j = 0 # 定位器
for i in df12.prime_genre.value_counts()/df.shape[0]:
    if k <= 0.8:
        k += i
        list.append(df12.prime_genre.value_counts().index[j])
        print(j,df12.prime_genre.value_counts().index[j])
        j += 1
print(k)

从以下结果可以看到保留的是前6个(按多少排序后)种类, 累计占比为 82.21%
可以充分地说明大部分的数值是由这几个种类贡献的.
在这里插入图片描述

这一步是把剩下的20%合并为一个种类: "else"类别

# 2. 把占比太低的过滤掉,合并为"其他"一项
for i in range(df12.prime_genre.shape[0]): 
    if df12.prime_genre[i] not in list:
        df12.iloc[i,3] = df12.iloc[i,3].replace(df12.iloc[i,3],'else'); # 第3列 'prime_genre'
df12.prime_genre.value_counts().plot(kind='bar') # 按照多少的顺序0~6 变成哑变量还是多变量??

在这里插入图片描述
可以看到, 经过合并后, 种类这个变量算是满足分类变量里的"平衡"要求
把字符型的该成数值型, 分别用1~7 来对应七个变量

# 将字符型改为1~7
df12['prime_genre'] = df12['prime_genre'].replace({'Games':1,'else':2,'Education':3,'Entertainment':4,'Photo & Video':5,
       'Utilities':6, 'Productivity':7})
df12.prime_genre.value_counts()

把处理完的列合并成一个新表,之后的数据分析基于此新表: df123
在这里插入图片描述
完成后, 做一次回归,看看它的评分:

x,y = df123.iloc[:,3:],df123['price01']
reg = linear_model.LinearRegression().fit(x,y)
reg.score(x,y)

在这里插入图片描述
结果为: 0.245 (<0.35)(<经验值0.4) 说明此时的模型, 仅有很弱的解释性, 但还不够达到一般的解释意义 (后续会进一步更新 )

经过上述步骤的处理: 可以看到: 数据的直方图比起之前规整了不少
在这里插入图片描述

1.3 特征筛选

当前数据共有10个变量(含y), 共有2878条
本来这一块是需要业务专家的介入, 看哪些不重要的, 可以先直接删除
(但是没有业务专家, 自己先处理凑合一下)
理论上这次要删掉30%左右的变量, 可以通过调试:percentile 参数, 来决定要删掉多少

#1.3 特征筛选(Filter过滤法)--业务上不重要的
from sklearn.feature_selection import SelectKBest,SelectPercentile,f_regression
# 运行整个模型 # 1.3这步要删掉30%,*5.3删掉50%
x,y = df123.iloc[:,3:],df123['price01'] # df123
fit = SelectPercentile(score_func = f_regression,percentile=70) #根据最高分数的百分位数选择特征 
fitt = fit.fit_transform(x,y) #fitt.shape[0]=6 选出了6个特征/变量
fitt.shape[1]

最后是筛选了6个变量出来, 加上y, 一共7个
最后把筛选出来的变量(y与x)合并成一个新表: df13 (fit那句可以看有哪些x被留下来了)

1.4 共线性

d = df13.corr();
d[d <= 0.9] = 0.1#赋值显示高相关的变量
sns.heatmap(d)# 看下有哪些是高度线性相关的(>=0.9就算)

在这里插入图片描述从热图中可以看出来, 没有高线性相关的
(省下了些进一步看共线性的步骤)

1.5 变换

关注y是否需要变换:如果偏得厉害,就要用对数log变换进行纠正

这里可以看到, 不是很严重,就不纠正了
在这里插入图片描述

2 预分析结果: 评分

#评分
x,y = df13.iloc[:,1:],df13['price01']
reg = linear_model.LinearRegression()
reg.fit(x,y)
reg.score(x,y) 

在这里插入图片描述
0.8832, 说明预分析效果挺好,

但是前面评分0.245,到这突然0.8832! 有点诡异 (后续跟进,为什么会升这么多)

再查看一下R²评分和残差图

#图示
plt.subplots(1,2,figsize=(12,8));
plt.subplot(121);
#1. r方评分和图示
r2 = reg.score(x,y);
plt.plot(y , reg.predict(x), 'o', label=r2)
plt.legend();
# 2. 残差图示
plt.subplot(122);
resid = y - reg.predict(x);
std_resid = (resid-np.mean(resid))/np.std(resid);
plt.plot(reg.predict(x),std_resid,'o',label="残差图");
plt.legend();

在这里插入图片描述
此时说明模型是有点问题的:
因为残差主要有两个点: 随机性和不可预测性.
上图中,这两个点都没有, 所以需要返回再看是哪里出了问题

但是这上面的残差很明显是跟类别相关的, 有曲线的信息(?),拟合模型中的e是内含着xi的信息的,

考虑从以下三个方面入手来解决问题
1. 是否有: 一个缺失的变量?
2. 是否模型缺少一个变量的高阶项来解释曲率?
3. 模型缺少在已经存在的项之间的交叉项?

联系我们

如果您对我们的服务有兴趣,请及时和我们联系!

服务热线:18288888888
座机:18288888888
传真:
邮箱:888888@qq.com
地址:郑州市文化路红专路93号