概述
DATA_ANALYSE
一、数据分析概述
步骤:数据获取,探索分析与可视化,预处理理论,分析建模,模型评估
二、数据获取
-
数据获取手段:
(1) 数据仓库(DW)
- 将所有业务数据汇总整理
- 全部事实的记录
- 部分维度与数据的整理(数据集市-DM)
- 数据库VS仓库:
- 数据库面向业务存储,仓库面向主题存储(主题:较高层次上对分析对象数据的一个完整并且一致的描述)
- 数据库针对应用(OLTP)仓库针对分析(OLAP)
- 数据库组织规范。仓库可能冗余,相对变化大,数据量大
(2) 监测与抓取
- 监测:使用监测设备或算法直接获取数据,如传感器网络等
- 抓取:
- 直接解析网页、接口、文件的信息
- Python常用工具:urllib urllib2 requests scrapy PhantomJS beautifulSoup Xpath(lxml)
(3) 填写、日志、埋点
- 填写:用户填写信息
- 埋点:APP或网页埋点(特定流程的信息记录点)
- 操作日志:前端日志,后端日志
(4) 计算
- 通过已有数据计算生成衍生数据
- 将所有业务数据汇总整理
-
数据学习网站
(1)数据竞赛网站(Kaggle&天池)
(2)数据集网站(ImageNet/Open Images)
(3)各领域统计数据(统计局、政府机构、公司财报等)
import pandas as pd
df = pd.read_csv("./data/HR.csv")
print(df.head(10))
三、探索分析与可视化
-
探索性数据分析(单因子与对比分析)可视化
(1)理论:
- 集中趋势:均值,中位数,分位数,众数
- 数据聚拢位置的衡量
- 均值:衡量分布较规律的连续值的集中趋势
- 中位数:衡量异常值的集中趋势
- 众数:衡量离散值的集中趋势
- 分位数:与其他几个值共同作用产生效果
- 离中趋势:标准差,方差
- 值越大表示数据越离散,值越小表示数据越聚拢
- 数据分布:偏态与峰态,正态分布与三大分布
- 偏态系数:数据平均值偏离状态的衡量,偏是指平均值的偏
- 峰态分布:数据分布集中强度的衡量,值越大,分布越尖,值越小,分布越平缓(正态分布的峰态系数一般定为3,与正态分布的峰态系数相差2时可以判断其不是正态分布)
- 三大分布:卡方分布,t分布,f分布
- 卡方分布:几个变量都是标准正态分布(均值为0,方差为1),几个变量的平方和满足的分布就是卡方分布
- t分布:正态分布的一个随机变量/一个服从卡方分布的变量,经常用于根据小样本来估计成正态分布且方差未知的总体的均值
- f分布:由构成两个服从卡方分布的随机变量的比构成的
- 抽样理论
- 抽样误差与精度
(2)代码实现
- 集中趋势:均值,中位数,分位数,众数
import pandas as pd
import scipy.stats as ss
df = pd.read_csv("./data/HR.csv") # 可以加sep参数作为分隔符
print(df.mean()) # 均值
print(df["satisfaction_level"].mean())
print(df.median()) # 中位数
print(df["satisfaction_level"].median())
print(df.quantile(q=0.25)) # 分位数,q=0.25 表示四分位数
print(df["satisfaction_level"].quantile(q=0.25))
print(df.mode()) # 众数
print(df["satisfaction_level"].mode())
print(df.std()) # 标准差,离中趋势
print(df["satisfaction_level"].std())
print(df.var()) # 方差
print(df["satisfaction_level"].var())
print(df.sum()) # 求和,离散数据求和是直接连起来
print(df["satisfaction_level"].sum())
print(df.skew()) # 偏态系数
print(df["satisfaction_level"].skew())
print(df.kurt()) # 峰度系数,以正态分布为0作为标准
print(df["satisfaction_level"].kurt())
print(ss.norm.stats(moments="mvsk")) # 正态分布的性质,m:均值 v:方差 s:偏态系数 k:峰态系数
print(ss.norm.pdf(0.0)) # 正态分布指定横坐标返回纵坐标的值
print(ss.norm.ppf(0.9)) # 输入的值必须是0到1之间的,从负无穷累积的值
print(ss.norm.cdf(2)) # 从负无穷累积到2,累积概率是多少
print(ss.norm.cdf(2) - ss.norm.cdf(-2)) # 正态分布中-2到2的累积概率
print(ss.norm.rvs(size=10)) # 得到10个符合正态分布的数字
print(ss.chi2) # 卡方分布
print(ss.t) # t分布
print(ss.f) # f 分布
print(df.sample(n=10)) # 抽样,抽n个
print(df["satisfaction_level"].sample(10))
print(df.sample(frac=0.001)) # 抽样,frac参数指定百分比
-
数据分类
(1)定类(类别):根据事物离散、无差别属性进行分类(男,女)
(2)定序(顺序):可以界定数据的大小,但不能测定差值。数据间有差距但不能测定差距的大小(收入低,中,高)
(3)定距(间隔):可以界定数据大小的同时,可测定差值,但无绝对零点。乘法除法和比率没有意义(摄氏度)
(4)定比(比率):可以界定数据的大小,可测定差值,有绝对零点(身高,体重)
-
单属性分析
(1)异常值分析:离散异常值,连续异常值,常识异常值
- 连续异常值处理:直接舍弃,也可以直接取边界值来代替异常值
- 离散异常值处理(离散属性定义范围外的所有值):直接舍弃,可以把所有异常值当成单独的值来处理
- 常识异常值(在限定知识与常识范围外的所有值)
(2)对比分析:绝对数与相对数,时间,空间,理论维度比较
- 比什么
- 绝对数比较(收入,身高,评分)
- 相对数比较:几个有联系的指标进行联合构成新的数
- 结构相对数(产品合格率,考试通过率):部分与整体进行相比
- 比例相对数(三大产业的比例):总体内用不同部分的数值进行比较
- 比较相对数(不同时机下同一商品的价格,不同电商互联网公司的待遇水平):同一时空下相似或同质的指标进行对比
- 动态相对数(速度,用户数量的增数):有时间概念
- 强度相对数(人均GDP,密度):性质不同,带有相互联系的属性进行联合
- 怎么比
- 时间维度:同比(和去年同期进行比较),环比(和今年之前进行比较)
- 空间维度:方位空间(城市,国家),逻辑空间(不同部门)
- 经验与计划维度:工作进度与计划排期进行比较
(3)结构分析:各组成部分的分布与规律
- 静态结构分析:直接分析总体的组成(产业结构)
- 动态结构分析:以时间为轴,分析结构变化的趋势(十一五期间三大产业的占比)
(4)分布分析:数据分布频率的显式分析
- 直接获得概率分布
- 是不是正态分布
- 极大似然:相似程度的衡量
import pandas as pd
import numpy as np
df = pd.read_csv("./data/HR.csv")
#### satisfaction_level的分析 ####
sl_s = df["satisfaction_level"]
print(sl_s.isnull()) # 判断是否为空
print(sl_s[sl_s.isnull()]) # 寻找异常值
print(df[df["satisfaction_level"].isnull()]) # 显示存在异常的数据
sl_s = sl_s.dropna() # 丢弃异常值
# sl_s = sl_s.fillna() # 填充异常值
print(sl_s.mean()) # 均值
print(sl_s.std()) # 标准差
print(sl_s.max()) # 最大值
print(sl_s.min()) # 最小值
print(sl_s.median()) # 中位数
print(sl_s.quantile(q=0.25)) # 下四分位数
print(sl_s.quantile(q=0.75)) # 上四分位数
print(sl_s.skew()) # 偏态系数
print(sl_s.kurt()) # 峰态系数
print(np.histogram(sl_s.values, bins=np.arange(0.0, 1.1, 0.1))) # 第一个参数:要切分的值,第二个参数:切分的临界值,np.arrange(开始值,结束值,间隔)
#### last_evaluation的分析 ####
le_s = df["last_evaluation"]
print(le_s[le_s.isnull()]) # 找出空值
print(le_s.mean()) # 均值
print(le_s.std()) # 标准差
print(le_s.median()) # 中位数
print(le_s.max()) # 最大值
print(le_s.min()) # 最小值
print(le_s.skew()) # 偏态系数
print(le_s.kurt()) # 峰态系数
# 异常值:四分位间距: 上四分位数 - 下四分位数 上界:上四位数 + 1.5~3 * 四分位间距 下界:下四位数 - 1.5~3 * 四分位间距 上下界之间为正常值,上下界以外的为异常值
print(le_s[le_s > 1]) # 均值出现异常,且偏态系数和峰态系数过大,寻找异常值
le_s = le_s[le_s <= 1] # 去掉异常值
q_low = le_s.quantile(q=0.25) # 下四分位数
q_high = le_s.quantile(q=0.75) # 上四分位数
q_interval = q_high - q_low # 四分位间距
k = 1.5
le_s = le_s[le_s < q_high + k * q_interval][le_s > q_low - k * q_interval] # 去掉异常值
print(np.histogram(le_s.values, bins=np.arange(0, 1.1, 0.1))) # 统计不同取值区间内的数有多少个
print(le_s.mean()) # 平均值
print(le_s.std()) # 标准差
print(le_s.median()) # 中位数
print(le_s.max()) # 最大值
print(le_s.skew()) # 偏度系数
print(le_s.kurt()) # 峰度系数
#### number_project的分析 ####
np_s = df["number_project"]
print(np_s[np_s.isnull()]) # 寻找空值
print(np_s.mean()) # 均值
print(np_s.std()) # 标准差
print(np_s.median()) # 中位数
print(np_s.max()) # 最大值
print(np_s.min()) # 最小值
print(np_s.skew()) # 偏态系数
print(np_s.kurt()) # 峰态系数
print(np_s.value_counts()) # 计算不同的值出现了多少次
print(np_s.value_counts(normalize=True)) # 计算不同的值出现的比例
print(np_s.value_counts(normalize=True).sort_index()) # 根据数据的index进行排序
#### average_montly_hours的分析 ####
amh_s = df["average_monthly_hours"]
print(amh_s.mean()) # 平均值
print(amh_s.std()) # 标准差
print(amh_s.max()) # 最大值
print(amh_s.min()) # 最小值
print(amh_s.skew()) # 偏态系数
print(amh_s.kurt()) # 峰态系数
q_low = amh_s.quantile(q=0.25) # 下四分位数
q_high = amh_s.quantile(q=0.75) # 上四分位数
q_interval = q_high - q_low # 四分位间距
k = 1.5
amh_s = amh_s[amh_s < q_high + k * q_interval][amh_s > q_low - k * q_interval] # 去除异常值
print(len(amh_s))
print(np.histogram(amh_s.values, bins=10)) # bins=数字 表示直接分成几分
print(np.histogram(amh_s.values, bins=np.arange(amh_s.min(), amh_s.max() + 10, 10))) # 左闭右开区间
print(amh_s.value_counts(bins=np.arange(amh_s.min(), amh_s.max() + 10, 10))) # 左开右闭区间
#### time_spend_company的分析 ####
tsc_s = df["time_spend_company"]
print(tsc_s.value_counts().sort_index()) # 按照数据的index排序
print(tsc_s.mean()) # 平均值
#### Work_accident的分析 ####
wa_s = df["Work_accident"]
print(wa_s.value_counts())
print(wa_s.mean()) # 事故率和均值相同
#### left的分析 ####
l_s = df["left"]
print(l_s.value_counts())
#### promotion_last_5years的分析 ####
pl5_s = df["promotion_last_5years"]
print(pl5_s.value_counts()) # 查看数据的分布
#### salary的分析 ####
s_s = df["salary"]
print(s_s.value_counts())
print(s_s.where(s_s!="nme")) # 寻找异常值,s_s.where(s_s!="nme")将 nme 取成空
s_s.where(s_s!="nme").dropna() # 去掉异常值
#### department的分析 ####
d_s = df["department"]
print(d_s.value_counts(normalize=True)) # 计算不同数据出现的概率
d_s = d_s.where(d_s != "sale") # 此时sale处的数据变成了空
d_s.dropna() # 去掉异常值
import pandas as pd
import numpy as np
df = pd.read_csv("./data/HR.csv")
sl_s = df["satisfaction_level"]
le_s = df["last_evaluation"]
np_s = df["number_project"]
amh_s = df["average_monthly_hours"]
tsc_s = df["time_spend_company"]
wa_s = df["Work_accident"]
l_s = df["left"]
pl5_s = df["promotion_last_5years"]
s_s = df["salary"]
d_s = df["department"]
#### 去除异常值
df = df.dropna(axis=0, how="any") # 去除空值,axis指定坐标轴,0为横坐标,1为纵坐标,how="all"这一行全是空值时才去掉 how="any"这一行有一个空值就去掉
df = df[le_s <= 1][s_s != "nme"][d_s != "sale"] # 去除异常值
#### 对比分析
print(df.groupby("department").mean()) # 根据部门进行分组,并取均值
print(df.loc[:, ["last_evaluation", "department"]].groupby("department").mean()) # 切片后分组并取均值
print(df.loc[:, ["average_monthly_hours", "department"]].groupby("department")["average_monthly_hours"].apply(lambda x:x.max() - x.min())) # 切片后分组,并计算极差
-
可视化
(1)柱状图
import pandas as pd import numpy as np import seaborn as sns import matplotlib.pyplot as plt sns.set_style(style="darkgrid") sns.set_context(context="paper") sns.set_palette("Reds") df = pd.read_csv("./data/HR.csv") #### seaborn绘制 #### sns.countplot(x="salary", hue="department", data=df) # hue:进行多层绘制,以department为分割,又进行了一次绘制 plt.show() #### matplotlib绘制 #### plt.title("SALARY") # 标题 plt.xlabel("salary") # 横轴名称 plt.ylabel("number") # 纵轴名称 plt.xticks(np.arange(len(df["salary"].value_counts()))+0.5, df["salary"].value_counts().index) # 在横轴做标记 plt.axis([0, 4, 0, 10000]) # axis([横轴最小值, 横轴最大值, 纵轴最小值, 纵轴最大值]) # 显示设置 plt.bar(np.arange(len(df["salary"].value_counts()))+0.5, df["salary"].value_counts(), width=0.5) # +0.5是为了在正中间显示, width设置柱子的宽度 for x, y in zip(np.arange(len(df["salary"].value_counts()))+0.5, df["salary"].value_counts()): plt.text(x, y, y, ha="center", va="bottom") # plt.text(横坐标, 纵坐标, 添加文本, 水平位置, 垂直位置) plt.show()
(2)直方图
import pandas as pd import numpy as np import seaborn as sns import matplotlib.pyplot as plt sns.set_style(style="darkgrid") sns.set_context(context="paper") sns.set_palette("Reds") df = pd.read_csv("./data/HR.csv") f = plt.figure() f.add_subplot(1, 3, 1) sns.distplot(df["satisfaction_level"], bins=10) # bins=n, 分成n份 f.add_subplot(1, 3, 2) sns.distplot(df["last_evaluation"], bins=10) f.add_subplot(1, 3, 3) sns.distplot(df["average_monthly_hours"], bins=10) plt.show()
(3)箱线图
import pandas as pd import numpy as np import seaborn as sns import matplotlib.pyplot as plt sns.set_style(style="darkgrid") sns.set_context(context="paper") sns.set_palette("Reds") df = pd.read_csv("./data/HR.csv") sns.boxplot(x=df["time_spend_company"], saturation=0.75, whis=3) # 计算异常值时k的取值 plt.show()
(4)折线图
import pandas as pd import numpy as np import seaborn as sns import matplotlib.pyplot as plt sns.set_style(style="darkgrid") sns.set_context(context="paper") sns.set_palette("Reds") df = pd.read_csv("./data/HR.csv") #### 第一种方法 sub_df = df.groupby("time_spend_company").mean() sns.pointplot(sub_df.index, sub_df["left"]) # 横坐标,纵坐标 plt.show() #### 第二种方法 sns.pointplot(x="time_spend_company", y="left", data=df) plt.show()
(5)饼图
import pandas as pd import numpy as np import seaborn as sns import matplotlib.pyplot as plt sns.set_style(style="darkgrid") sns.set_context(context="paper") sns.set_palette("Reds") df = pd.read_csv("./data/HR.csv") lbs = df["department"].value_counts().index # 设置标签 explodes = [0.1 if i == "sales" else 0 for i in lbs] # 强调 plt.pie(df["department"].value_counts(normalize=True), explode=explodes, labels=lbs, autopct="%1.1f%%", colors=sns.color_palette("Reds")) # autopct 显示百分比数字 plt.show()
四、探索性数据分析(多因子与复合分析)
-
理论
(1)假设检验与方差检验
- 假设检验
- 根据一定的假设条件,从样本推断总体或者推断样本与样本之间关系的一种方法。做出一个假设,根据数据或者已知的分布性质推断假设成立的概率。
- 过程
- 建立原假设H0(包含等号),H0的反命题为H1,也叫备择假设;
- 选择检验统计量(检验统计量是指根据数据的均值方差等构造的一个函数,目的是让数据符合已知分布);
- 根据显著水平(接受假设失真程度的最大限度,一般为0.05,显著性水平和相似度的加和为1,人为定义),确定拒绝域(检验统计量落入拒绝域,则H0判断为假);
- 计算p值或样本统计值,做出判断(判断思路一:计算检验统计量的分布区间,看区间是否包含要比较的分布的特征;判断思路二:计算一个p值和显著性水平进行比较,p较小则判断假设为假)
- 方差检验(f检验)
- 多个样本
(2)相关系数:皮尔逊、斯皮尔曼
- 衡量两组数据或两组样本的分布趋势,变化取数,一致性程度的因子
- 正相关,负相关,不相关
- 相关系数越大,越接近与1,二者变化趋势越正向同步;相关系数越小,越接近于-1,二者变化趋势越反向同步;相关系数趋近于0,二者可以认为没有相关关系
- Pearson相关系数
- Spearman相关系数:只和名次差有关,适用于相对比较的情况
(3)回归:线性回归
- 回归:确定两种或两种以上变量间相互依赖的定量关系的一种统计分析方法。若自变量与因变量之间的依赖关系为线性关系,则为线性回归。
- 效果判定
- 关键指标:决定系数(决定系数越接近于1,回归效果越好;越接近于0,回归效果越差)
- 残差不相关(DW检验)(DW取值在0到4之间,取值为2代表残差不相关,取值接近于4代表残差正相关,取值接近于0代表残差负相关;好的回归残差应该不相关,DW值接近于2 )
(4)PCA(主成分分析)与奇异值分解
- 主成分分析(PCS)
- 通过正交变换,将一组可能存在相关性的变量转化为一组线性不相关的变量
- 过程
- 求特征协方差矩阵
- 求协方差的特征值和特征向量
- 将特征值按照从大到小的顺序排序,选择其中最大的k个
- 将样本点投影到选取的特征向量上
- 降维,将最主要的成分提出来
- 奇异值分解(SVA)
- 线性降维与成分提取
- 假设检验
-
import numpy as np import scipy.stats as ss from statsmodels.graphics.api import qqplot from matplotlib import pyplot as plt import pandas as pd from sklearn.linear_model import LinearRegression from sklearn.decomposition import PCA norm_dist = ss.norm.rvs(size=20) # 生成符合标准正态分布的20个数字 print(norm_dist) print(ss.normaltest(norm_dist)) # 检测是否符合正态分布,normaltest是基于偏度和峰度的检验方法 #### NormaltestResult(statistic=0.5846482217637807, pvalue=0.7465265393835774) #### 统计值为0.58,p值为0.75,若显著性水平定为0.05,p>0.05,假设成立,即符合正态分布 print(ss.chi2_contingency([[15, 95], [85, 5]])) # 卡方检验 #### (126.08080808080808, 2.9521414005078985e-29, 1, array([[55., 55.],[45., 45.]])) #### (检验统计量,p值,自由度,理论分布) print(ss.ttest_ind(ss.norm.rvs(size=10), ss.norm.rvs(size=20))) # 独立分布t检验 #### Ttest_indResult(statistic=-1.234591943541198, pvalue=0.2272434915525291) #### (检验统计量, p值),若显著性水平为0.05,则p > 0.05,假设成立,两个的均值没有差别 print(ss.ttest_ind(ss.norm.rvs(size=100), ss.norm.rvs(size=200))) # 独立分布t检验,数据量增多 #### Ttest_indResult(statistic=1.6229545891329094, pvalue=0.10565647447598514) print(ss.f_oneway([49, 50, 39, 40, 43], [28, 32, 30, 26, 34], [38, 40, 45, 42, 48])) # 方差检验 #### F_onewayResult(statistic=17.619417475728156, pvalue=0.0002687153079821641) #### (统计值,p值) qqplot(ss.norm.rvs(size=100)) # 通过图检验该分布是否为正态分布 plt.show() s1 = pd.Series([0.1, 0.2, 1.1, 2.4, 1.3, 0.3, 0.5]) s2 = pd.Series([0.5, 0.4, 1.2, 2.5, 1.1, 0.7, 0.1]) print(s1.corr(s2)) # 计算s1和s2的相关系数 #### 0.9333729600465923 print(s1.corr(s2, method="spearman")) # 计算s1和s2的斯皮尔曼相关系数 #### 0.7142857142857144 df = pd.DataFrame([s1, s2]) # pd.DataFrame:针对于列进行相关性计算 print(df.corr()) #### 0 1 2 3 4 5 6 #### 0 1.0 1.0 1.0 1.0 -1.0 1.0 -1.0 #### 1 1.0 1.0 1.0 1.0 -1.0 1.0 -1.0 #### 2 1.0 1.0 1.0 1.0 -1.0 1.0 -1.0 #### 3 1.0 1.0 1.0 1.0 -1.0 1.0 -1.0 #### 4 -1.0 -1.0 -1.0 -1.0 1.0 -1.0 1.0 #### 5 1.0 1.0 1.0 1.0 -1.0 1.0 -1.0 #### 6 -1.0 -1.0 -1.0 -1.0 1.0 -1.0 1.0、 df = pd.DataFrame(np.array([s1, s2]).T) print(df.corr()) #### 0 1 #### 0 1.000000 0.933373 #### 1 0.933373 1.000000 print(df.corr(method="spearman")) # 计算斯皮尔曼相关系数 #### 0 1 #### 0 1.000000 0.714286 #### 1 0.714286 1.000000 x = np.arange(10).astype(np.float_).reshape((10, 1)) y = x * 3 + 4 + np.random.random((10, 1)) reg = LinearRegression() # 构建线性回归 res = reg.fit(x, y) # 拟合过程 y_pred = reg.predict(x) # 预测值 print(y_pred) print(reg.coef_) # 参数 #### [[3.02021707]] print(reg.intercept_) # 截距 #### [4.35690495] data = np.array([np.array([2.5, 0.5, 2.2, 1.9, 3.1, 2.3, 2, 1, 1.5, 1.1]), np.array([2.4, 0.7, 2.9, 2.2, 3, 2.7, 1.6, 1.1, 1.6, 0.9])]).T lower_dim = PCA(n_components=1) # 降维,n_components=n,即降为n维,PCA算法用到的是奇异值分解的方法 lower_dim.fit(data) print(lower_dim.explained_variance_ratio_) #### [0.96318131] #### 降维后得到了96%的信息量 print(lower_dim.fit_transform(data)) # 得到转换后的数值 #### [[-0.82797019] #### [ 1.77758033] #### [-0.99219749] #### [-0.27421042] #### [-1.67580142] #### [-0.9129491 ] #### [ 0.09910944] #### [ 1.14457216] #### [ 0.43804614] #### [ 1.22382056]]
import pandas as pd import numpy as np from scipy import linalg #### 自己构造主成分分析降维 #### def myPCA(data, n_components=100000000): mean_vals = np.mean(data, axis=0) # 针对列取均值 mid = data - mean_vals cov_mat = np.cov(mid, rowvar=False) # 若不指定rowvar=False则对行进行协方差计算,应对列进行协方差计算 eig_vals, eig_vects = linalg.eig(np.mat(cov_mat)) # 求协方差矩阵的特征值和特征向量 eig_val_index = np.argsort(eig_vals) # np.argsort()得到排序后的索引,取最大的特征值对应的特征向量 eig_val_inedx = eig_val_index[:-(n_components + 1):-1] # 取最大值的索引 eig_vects = eig_vects[:, eig_val_inedx] # 取出对应的特征向量 low_dim_mat = np.dot(mid, eig_vects) # 进行转换 return low_dim_mat, eig_vals # 返回转化后的特征和特征值 data = np.array([np.array([2.5, 0.5, 2.2, 1.9, 3.1, 2.3, 2, 1, 1.5, 1.1]), np.array([2.4, 0.7, 2.9, 2.2, 3, 2.7, 1.6, 1.1, 1.6, 0.9])]).T print(myPCA(data, n_components=1))
-
复合分析
(1)交叉分析
-
分析属性和属性之间关系的方法
-
import pandas as pd import numpy as np import scipy.stats as ss import matplotlib.pyplot as plt import seaborn as sns sns.set_context(font_scale=1.5) # 调字体 df = pd.read_csv("./data/HR.csv") sl_s = df["satisfaction_level"] le_s = df["last_evaluation"] np_s = df["number_project"] amh_s = df["average_monthly_hours"] tsc_s = df["time_spend_company"] wa_s = df["Work_accident"] l_s = df["left"] pl5_s = df["promotion_last_5years"] s_s = df["salary"] d_s = df["department"] #### 去除异常值 df = df.dropna(axis=0, how="any") # 去除空值,axis指定坐标轴,0为横坐标,1为纵坐标,how="all"这一行全是空值时才去掉 how="any"这一行有一个空值就去掉 df = df[le_s <= 1][s_s != "nme"][d_s != "sale"] # 去除异常值 #### 交叉分析 #### #### 各个部门的离职率之间是否有明显差异,使用独立t检验方法 #### #### 基本思路:得到各个部门的离职分布,两两间求t检验统计量,并求出p值,目的是得到各个部门的离职分布 #### dp_indices = df.groupby(by="department").indices # indices属性可以得到分组后的索引 sales_values = df["left"].iloc[dp_indices["sales"]].values technical_values = df["left"].iloc[dp_indices["technical"]].values print(ss.ttest_ind(sales_values, technical_values)) # 打印t统计量和p值 dp_keys = list(dp_indices.keys()) # 必须用list()进行转化 dp_t_mat = np.zeros([len(dp_keys), len(dp_keys)]) for i in range(len(dp_keys)): for j in range(len(dp_keys)): p_value = ss.ttest_ind(df["left"].iloc[dp_indices[dp_keys[i]]].values, df["left"].iloc[dp_indices[dp_keys[j]]].values)[1] # 索引取1时,只打印p值 if p_value < 0.05: dp_t_mat[i][j] = 1 else: dp_t_mat[i][j] = p_value sns.heatmap(dp_t_mat, xticklabels=dp_keys, yticklabels=dp_keys) # 颜色越深,说明部门之间的离职率有显著差异;颜色越浅,说明部门之间的离职率没有显著差异 plt.show() #### 通过透视表进行交叉分析 #### piv_tb = pd.pivot_table(df, values="left", index=["promotion_last_5years", "salary"], columns=["Work_accident"], aggfunc=np.mean) # index横坐标, columns纵坐标,aggfunc聚合方法 print(piv_tb) sns.heatmap(piv_tb, vmin=0, vmax=1, cmap=sns.color_palette("Reds", n_colors=256)) plt.show()
(2)分组与钻取
-
分组分析(一般要结合其他分析方法进行配合使用)
- 将数据进行分组后进行分析比较
- 根据数据的特征将数据进行切分,分成不同的组,使得组内的成员尽可能靠拢,组间的成员尽可能远离
- 分类:指定了每一条数据的分组,来计算当未知分组的数据出现的时候,更精确地判断是哪个分组;聚类:不知道分组,仅是想让数据尽可能地物以类聚
- 离散属性的分组比较容易,连续属性的分组在分组前需要进行离散化
- 连续分组:在进行连续属性的离散化之前,需要注意数据分布,是否有明显的可以区分的标志
- 分隔(相邻两个数据的差):一阶差分;拐点:二阶差分
- 聚类(连续属性的分组要尽可能满足相同的分组比价聚拢,不同的分组比较分离的特点):k-means进行指定分组数目的连续属性分组
- 不纯度(Gini系数):先将表按照连续值的大小进行排序,相邻两两之间划定界限,分别确定分组值,分别计算Gini系数,取Gini系数最小的切分为界,就可以根据目标标注将连续数值进行分组
- 连续分组:在进行连续属性的离散化之前,需要注意数据分布,是否有明显的可以区分的标志
-
钻取(分组分析最常用到的分析手段)
- 钻取是改变数据维度地层次,变换分析粒度的过程
- 根据钻取方向的不同,可分为向上钻取和向下钻取
- 向下钻取:展开数据,查看数据细节
- 向上钻取:汇总分组数据
-
import pandas as pd import numpy as np import scipy.stats as ss import matplotlib.pyplot as plt import seaborn as sns sns.set_context(font_scale=1.5) df = pd.read_csv("./data/HR.csv") sl_s = df["satisfaction_level"] le_s = df["last_evaluation"] np_s = df["number_project"] amh_s = df["average_monthly_hours"] tsc_s = df["time_spend_company"] wa_s = df["Work_accident"] l_s = df["left"] pl5_s = df["promotion_last_5years"] s_s = df["salary"] d_s = df["department"] #### 去除异常值 df = df.dropna(axis=0, how="any") # 去除空值,axis指定坐标轴,0为横坐标,1为纵坐标,how="all"这一行全是空值时才去掉 how="any"这一行有一个空值就去掉 df = df[le_s <= 1][s_s != "nme"][d_s != "sale"] # 去除异常值 #### 通过绘制柱状图,直观了解分组情况 #### # sns.barplot(x="salary", y="left", hue="department", data=df) # hue:向下根据部门钻取 # plt.show() #### 连续值 #### sll_s = df["satisfaction_level"] sns.barplot(list(range(len(sll_s))), sll_s.sort_values()) # 根据值进行排序 plt.show() # 需要等较长的一段时间,长到会以为可能出问题了
(3)相关分析
-
衡量两组数据分布趋势或者变化趋势大小的分析方法,用相关系数直接衡量相关性的大小。
-
相关系数:pearson相关系数,spearman相关系数
import pandas as pd import numpy as np import scipy.stats as ss import matplotlib.pyplot as plt import seaborn as sns sns.set_context(font_scale=1.5) df = pd.read_csv("./data/HR.csv") sl_s = df["satisfaction_level"] le_s = df["last_evaluation"] np_s = df["number_project"] amh_s = df["average_monthly_hours"] tsc_s = df["time_spend_company"] wa_s = df["Work_accident"] l_s = df["left"] pl5_s = df["promotion_last_5years"] s_s = df["salary"] d_s = df["department"] #### 去除异常值 #### df = df.dropna(axis=0, how="any") # 去除空值,axis指定坐标轴,0为横坐标,1为纵坐标,how="all"这一行全是空值时才去掉 how="any"这一行有一个空值就去掉 df = df[le_s <= 1][s_s != "nme"][d_s != "sale"] # 去除异常值 #### 计算相关系数 #### sns.heatmap(df.corr(), vmin=-1, vmax=1, cmap=sns.color_palette("RdBu", n_colors=128)) # df.corr():计算相关系数,去掉离散值 plt.show()
-
离散属性相关性系数的计算
- 二类离散属性的相关性可以用pearson相关系数直接衡量相关性大小,但会有些失真
- 二类属性和连续值属性的相关性可以用不纯度进行解决和计算
- 多类离散属性的相关系数:若都是定序数据(low medium high),可以直接编码成0,1,2之类的值进行pearson相关系数计算,但会有失真
- 使用熵进行离散属性的相关性计算
- 熵:熵是用来衡量不确定性的值,熵越接近于0,不确定性越小;若样本分布为0.5,0.5,则熵为1比特,若样本都属于一个类别,则熵为0,若样本类别越多,分布越均匀,信息熵就越大
- 条件熵:条件熵相对于原来的熵减少了,不对称
- 互信息(熵增益):过程中减少的熵;信息增益的缺点,对于分类数目多的特征,有不正确的偏向,不具有归一化的特点,不确定性是上不封顶的
- 熵增益率:大于0小于1,X,Y不具有对称性
- 相关性:大于0小于1,X,Y具有对称性
import pandas as pd import numpy as np import scipy.stats as ss import matplotlib.pyplot as plt import seaborn as sns import math sns.set_context(font_scale=1.5) #### 计算离散值的相关系数 #### s1 = pd.Series(["X1", "X1", "X2", "X2", "X2", "X2"]) s2 = pd.Series(["Y1", "Y1", "Y1", "Y2", "Y2", "Y2"]) def getEntropy(s): # 熵 if not isinstance(s, pd.core.series.Series): # 判断是否是series,若不是则转化为series s = pd.Series(s) prt_ary = s.groupby(by=s).count().values/float(len(s)) # 计算分布,得到概率分布 return -(np.log2(prt_ary) * prt_ary).sum() # 根据公式求和计算熵 print("Entropy", getEntropy(s1)) #### Entropy 0.9182958340544896 print("Entropy", getEntropy(s2)) #### Entropy 1.0 #### 0.5和0.5的分布 def getCondEntropy(s1, s2): # 条件熵 d = dict() # 创建一个新的字典 for i in list(range(len(s1))): # 先求出s1的分布 d[s1[i]] = d.get(s1[i], []) + [s2[i]] # 记录s1的值下,s2的分布 return sum([getEntropy(d[k])*len(d[k])/float(len(s1)) for k in d]) print("CondEntropy", getCondEntropy(s1, s2)) #### CondEntropy 0.5408520829727552 print("CondEntropy", getCondEntropy(s2, s1)) #### CondEntropy 0.4591479170272448 条件熵是不对称的 def getEntropyGain(s1, s2): # 熵增益 return getEntropy(s2) - getCondEntropy(s1, s2) print("EntropyGain",getEntropyGain(s1, s2)) #### EntropyGain 0.4591479170272448 print("EntropyGain",getEntropyGain(s2, s1)) #### EntropyGain 0.4591479170272448 熵增益是对称的 def getEntropyGainRatio(s1, s2): # 熵增益率 return getEntropyGain(s1, s2)/getEntropy(s2) print("EntropyGainRatio", getEntropyGainRatio(s1, s2)) #### EntropyGainRatio 0.4591479170272448 print("EntropyGainRatio", getEntropyGainRatio(s2, s1)) #### EntropyGainRatio 0.5 熵增益率不是对称的 def getDiscreteCorr(s1, s2): # 衡量离散值的相关性 return getEntropyGain(s1, s2)/math.sqrt(getEntropy(s1) * getEntropy(s2)) print('DiscreteCorr', getDiscreteCorr(s1, s2)) #### DiscreteCorr 0.4791387674918639 print('DiscreteCorr', getDiscreteCorr(s2, s1)) #### DiscreteCorr 0.4791387674918639 对称 def getProbSS(s): # 求概率平方和的函数 if not isinstance(s, pd.core.series.Series): # 判断是否是series,若不是则转化为series s = pd.Series(s) prt_ary = s.groupby(by=s).count().values/float(len(s)) # 计算分布,得到概率分布 return sum(prt_ary**2) def getGini(s1, s2): # 求Gini系数 d = dict() # 创建一个新的字典 for i in list(range(len(s1))): # 先求出s1的分布 d[s1[i]] = d.get(s1[i], []) + [s2[i]] # 记录s1的值下,s2的分布 return 1 - sum([getProbSS(d[k]) * len(d[k])/float(len(s1)) for k in d]) print("Gini", getGini(s1, s2)) #### Gini 0.25 print("Gini", getGini(s2, s1)) #### Gini 0.2222222222222222 Gini系数不对称
(4)因子分析(成分分析)
-
从多个属性变量中分析共性,相关因子的方法
-
分为探索性因子分析和验证性因子分析
- 探索性因子分析:通过协方差矩阵、相关性矩阵等指标分析多元属性变量的本质结构,并可以进行转化、降维等操作,得到数据空间中影响目标属性的最主要的因子(主成分分析法等)
- 验证性因子分析:验证一个因子与我们关注的属性之间是否有关联,有什么样的关联,是否符合预期等(假设检验,相关分析,回归分析等)
import pandas as pd import numpy as np import scipy.stats as ss import matplotlib.pyplot as plt import seaborn as sns from sklearn.decomposition import PCA sns.set_context(font_scale=1.5) df = pd.read_csv("./data/HR.csv") sl_s = df["satisfaction_level"] le_s = df["last_evaluation"] np_s = df["number_project"] amh_s = df["average_monthly_hours"] tsc_s = df["time_spend_company"] wa_s = df["Work_accident"] l_s = df["left"] pl5_s = df["promotion_last_5years"] s_s = df["salary"] d_s = df["department"] #### 去除异常值 #### df = df.dropna(axis=0, how="any") # 去除空值,axis指定坐标轴,0为横坐标,1为纵坐标,how="all"这一行全是空值时才去掉 how="any"这一行有一个空值就去掉 df = df[le_s <= 1][s_s != "nme"][d_s != "sale"] # 去除异常值 my_pca = PCA(n_components=7) # 共7个属性 lower_mat = my_pca.fit_transform(df.drop(labels=["salary", "department", "left"], axis=1)) # 数据表中不允许出现离散数据 print("Ratio:", my_pca.explained_variance_ratio_) #### Ratio: [9.98565340e-01 8.69246970e-04 4.73865973e-04 4.96932182e-05 #### 2.43172315e-05 9.29496619e-06 8.24128218e-06] # 9.98565340e-01只有这个结果接近于1,其他结果都较小,故通过主成分分析后,需要保留的因子只有这一个 sns.heatmap(pd.DataFrame(lower_mat).corr(), vmin=-1, vmax=1, cmap=sns.color_palette("RdBu", n_colors=128)) plt.show()
(5)聚类分析
(6)回归分析
-
-
总结
数据类型 可用方法 连续—连续 相关系数,假设检验 连续—离散(二值) 相关系数,连续二值化(最小Gini切分,最大熵增益切分) 连续—离散(非二值) 相关系数(定序) 离散(二值)—离散(二值) 相关系数,熵相关,F分值 离散—离散(非二值) 熵相关,Gini,相关系数(定序)
五、预处理理论
-
特征工程概述
(1)数据和特征决定了机器学习的上限,模型和算法只是逼近这个上限
(2)特征工程一般包括特征使用,特征获取,特征处理,特征监控四个方面
- 特征使用:包括两个小方面,数据的选择和数据的可用性判断,主要关注点放在特征的原数据上。数据选择是分析和目标最相关的数据都有哪些,这些数据如何获取;数据的可用性中的可用性是指数据特征是否能持续输出
- 特征获取:确定与存储数据的过程,包括两个部分,特征来源的确认和特征的规整与存储
- 特征处理:特征的预处理过程,是数据的属性和特征能尽可能大的发挥作用,分为数据清洗和特征预处理。
- 特征监控:对模型,特征的契合程度进行不断监控,两个监控方向,一个是针对现有特征,看是否对数据任务有积极作用,另一个是探询新的特征是否有助于提高效果,更能代表数据任务目标
-
数据清洗
(1)数据样本抽样
- 有时候数据量特别大,通过抽样可以以较小的失真的代价,方便的获得较为准确的统计结果。有时获取全量数据的特征不现实。
- 抽样
- 样本要具备代表性,样本的各个特征的比例应该尽可能与整体的比例保持一致
- 样本比例要平衡以及样本不平衡是如何处理
- 考虑全量数据
(2)异常值(空值)处理
- 将异常值丢弃或者转换
- 常用方法:
- 识别异常值和重复值(Pandas: isnull() / duplicated())
- 直接丢弃(包括重复数据)(Pandas: drop() / dropna() / drop_duplicated())
- 当是否有异常当作一个新的属性,替代原值(Pandas: fillna())(把这个属性是否是异常值这个判断结果代替这个属性)
- 集中值指代(Pandas: fillna()):集中值可以是除异常值之外的均值、中位数或者众数等)
- 边界值指代(Pandas: fillna())(在连续数据中,用四分位间距确定的上下边界来确定超过上下边界的数)
- 插值(连续数据还可以用插值的方法填充异常值)(Pandas: interpolate()–Series)
import numpy as np import pandas as pd df = pd.DataFrame({"A": ["a0", "a1", "a1", "a2", "a3", "a4"], "B": ["b0", "b1", "b2", "b2", "b3", None], "C": [1, 2, None, 3, 4, 5], "D": [0.1, 10.2, 11.4, 8.9, 9.1, 12], "E": [10, 19, 32, 25, 8, None], "F": ["f0", "f1", "g2", "f3", "f4", "f5"]}) print(df) #### A B C D E F #### 0 a0 b0 1.0 0.1 10.0 f0 #### 1 a1 b1 2.0 10.2 19.0 f1 #### 2 a1 b2 NaN 11.4 32.0 g2 #### 3 a2 b2 3.0 8.9 25.0 f3 #### 4 a3 b3 4.0 9.1 8.0 f4 #### 5 a4 None 5.0 12.0 NaN f5 #### NaN:not a number print(df.isnull()) #### A B C D E F #### 0 False False False False False False #### 1 False False False False False False #### 2 False False True False False False #### 3 False False False False False False #### 4 False False False False False False #### 5 False True False False True False #### 去掉所有空值 #### df_1 = df.dropna() print(df_1) #### A B C D E F #### 0 a0 b0 1.0 0.1 10.0 f0 #### 1 a1 b1 2.0 10.2 19.0 f1 #### 3 a2 b2 3.0 8.9 25.0 f3 #### 4 a3 b3 4.0 9.1 8.0 f4 #### 有空值的行都被去掉了 #### 去掉某一行的空值 #### df_2 = df.dropna(subset=["B"]) print(df_2) #### A B C D E F #### 0 a0 b0 1.0 0.1 10.0 f0 #### 1 a1 b1 2.0 10.2 19.0 f1 #### 2 a1 b2 NaN 11.4 32.0 g2 #### 3 a2 b2 3.0 8.9 25.0 f3 #### 4 a3 b3 4.0 9.1 8.0 f4 #### 只去掉B的空值 #### 识别重复值 #### df_3 = df.duplicated(["A"]) # A中重复的元素 print(df_3) #### 0 False #### 1 False #### 2 True #### 3 False #### 4 False #### 5 False #### dtype: bool df_4 = df.duplicated(["A", "B"]) # 必须A和B中都为重复的,才显示True print(df_4) #### 0 False #### 1 False #### 2 False #### 3 False #### 4 False #### 5 False #### dtype: bool #### 去掉重复值 #### df_5 = df.drop_duplicates(["A"]) # 去掉A中的重复值 print(df_5) #### A B C D E F #### 0 a0 b0 1.0 0.1 10.0 f0 #### 1 a1 b1 2.0 10.2 19.0 f1 #### 3 a2 b2 3.0 8.9 25.0 f3 #### 4 a3 b3 4.0 9.1 8.0 f4 #### 5 a4 None 5.0 12.0 NaN f5 df_6 = df.drop_duplicates(["A"], keep="first") # keep参数表示保留哪一个,first, last, false(去掉所有的重复行),inplace参数为True是,原始的df会发生变化 print(df_6) #### A B C D E F #### 0 a0 b0 1.0 0.1 10.0 f0 #### 1 a1 b1 2.0 10.2 19.0 f1 #### 3 a2 b2 3.0 8.9 25.0 f3 #### 4 a3 b3 4.0 9.1 8.0 f4 #### 5 a4 None 5.0 12.0 NaN f5 #### 异常值标注 #### df_7 = df["B"].fillna("b*") # 将B中的异常值标注为b* print(df_7) #### 0 b0 #### 1 b1 #### 2 b2 #### 3 b2 #### 4 b3 #### 5 b* #### Name: B, dtype: object #### 集中值指代 #### df_8 = df["E"].fillna(df["E"].mean()) # 用E的均值替换E中的异常值,求E的均值的时候,自动忽略E中的异常值 print(df_8) #### 0 10.0 #### 1 19.0 #### 2 32.0 #### 3 25.0 #### 4 8.0 #### 5 18.8 #### Name: E, dtype: float64 #### 插值 #### df_9 = df["E"].interpolate() # 插值的方法只能用于Series print(df_9) #### 0 10.0 #### 1 19.0 #### 2 32.0 #### 3 25.0 #### 4 8.0 #### 5 8.0 #### Name: E, dtype: float64 #### 如果在末尾,则取前面那个数的值,在开头则取后面那个数的值 print(pd.Series([1, None, 4, 5, 20]).interpolate()) #### 0 1.0 #### 1 2.5 #### 2 4.0 #### 3 5.0 #### 4 20.0 #### dtype: float64 #### 取的是相邻两个值的平均值 #### 过滤异常值 #### upper_q = df["D"].quantile(0.75) # 上四分位数 lower_q = df["D"].quantile(0.25) # 下四分位数 q_int = upper_q - lower_q k = 1.5 df_10 = df[df["D"] > lower_q - k * q_int][df["D"] < upper_q + k * q_int] print(df_10) #### A B C D E F #### 1 a1 b1 2.0 10.2 19.0 f1 #### 2 a1 b2 NaN 11.4 32.0 g2 #### 3 a2 b2 3.0 8.9 25.0 f3 #### 4 a3 b3 4.0 9.1 8.0 f4 #### 5 a4 None 5.0 12.0 NaN f5 df_11 = df.drop(2) # 去掉第二行 print(df_11) #### A B C D E F #### 0 a0 b0 1.0 0.1 10.0 f0 #### 1 a1 b1 2.0 10.2 19.0 f1 #### 3 a2 b2 3.0 8.9 25.0 f3 #### 4 a3 b3 4.0 9.1 8.0 f4 #### 5 a4 None 5.0 12.0 NaN f5 df_12 = df[[True if item.startswith("f") else False for item in list(df["F"].values)]] # 过滤掉F中不是f开头的行 print(df_12) #### A B C D E F #### 0 a0 b0 1.0 0.1 10.0 f0 #### 1 a1 b1 2.0 10.2 19.0 f1 #### 3 a2 b2 3.0 8.9 25.0 f3 #### 4 a3 b3 4.0 9.1 8.0 f4 #### 5 a4 None 5.0 12.0 NaN f5
-
特征预处理
(1)标注(标记、标签、label)
- 数学建模或者机器学习的目的是建立其他属性与目的之间的关系,反应目的的属性就是所谓的标注,其他属性就是特征
(2)特征预处理主要内容
- 特征选择
- 剔除与标注不相关或者冗余的特征,减少特征的个数,带来的效果是减少了模型训练的时间,有时还可以有效减少过拟合,提升模型的准确度。
- 依靠模型本身的特征,进行与标注影响大小的排序后,剔除排序靠后的特征,实现降维
- 数据归约的思路之一(另一个思路是抽样)
- 切入思路:过滤思想(直接评价某个特征与标注的相关性等特征,如果与标注的相关性非常小就去掉);包裹思想(假设所有特征是一个集合X,最佳的特征组合是X的一个子集,任务是找到这个子集。先确定评价指标,如正确率,遍历特征子集,找到正确率评价下最佳的子集;也可以一步一步进行迭代,先拆分成几个大点的自己找到最优的子集再继续进行拆分,直到评价指标下降过快,整个过程结束(RFE算法:列出特征集合X;构造简单模型,根据系数去掉弱特征;余下的特征重复过程,直到评价指标下降较大或者低于阈值,停止));嵌入思想(嵌入的主体是特征,被嵌入的实体是简单的模型,根据一个简单的模型来分析特征的重要性,最常用的方式是使用正则化来进行特征选择。比如通过一个回归模型对标注进行回归,得到一些W系数,对W系数进行正则化,将其转化为一个0到1之间的数,此时W系数就反应了特征的分量和重要程度,若有的系数比较小则可以把相应特征去掉。存在模型选择不当导致重要属性被丢弃的风险)
- 特征变换(对指化,离散化,数据平滑,归一化(标准化),数值化,正规化)
- 特征降维
- 特征衍生
最后
以上就是喜悦期待为你收集整理的数据分析笔记的全部内容,希望文章能够帮你解决数据分析笔记所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复