学习日志
本文章为天池“GitModel统计分析”学习的Task02EDA-学习日志
# !pip install jupyterlab "ipywidgets>=7.5"
# !pip install npm
# !conda install -c conda-forge nodejs
# !pip install plotly
# 加载必要库
import pandas as pd # 数据分析库
import numpy as np # 矩阵计算
import matplotlib.pyplot as plt # 画图
import plotly.express as px # 画图
from statsmodels.graphics.gofplots import qqplot # 统计模型
import seaborn as sns # 统计绘图
# 避免产生报警告
import warnings
warnings.filterwarnings('ignore')
plt.rcParams['font.sans-serif']=['SimHei']#引入中文字体
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['font.sans-serif']=['KaiTi']
plt.rcParams['axes.unicode_minus'] = False #引入中文字体
#
pd.set_option("display.max_rows", 50) #可显示100行
pd.set_option("display.max_columns", 40)#可显示10列
#----------------数据读取----------------
data = pd.read_csv("D:/python/ITEM/HousePrice of Boston/Data/boston.csv")
print(data.head(5))# 读前五行
"""
CRIM:按城镇划分的人均犯罪率
ZN:划分为超过 25,000 平方英尺地块的住宅用地比例。
INDUS:每个城镇的非零售商业用地的比例
CHAS:Charles River 虚拟变量(如果区域以河流为界,则为 1;否则为 0)
NOX:一氧化氮浓度(每 1000 万分之一)[parts/10M]
RM:每户住宅的平均房间数
AGE:1940 年之前建造的自住单元的比例
DIS:到波士顿五个就业中心的加权距离
RAD:通往径向高速公路的指数
TAX:全每 10,000 美元的价值财产税率 [$/10k]
PTRATIO:按城镇划分的师生比例
B:等式 B=1000(Bk-0.63)^2的结果,其中 Bk是城镇中黑人的比例
LSTAT:人口地位较低的百分比
"""
#----------------数据概况----------------
print(data.shape)
#(506, 14)
print(data.columns)
"""
Index(['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD', 'TAX',
'PTRATIO', 'B', 'LSTAT', 'MEDV'],
dtype='object')
"""
print(data.describe())
"""
CRIM ZN INDUS CHAS NOX RM \
count 506.000000 506.000000 506.000000 506.000000 506.000000 506.000000
mean 3.613524 11.363636 11.136779 0.069170 0.554695 6.284634
std 8.601545 23.322453 6.860353 0.253994 0.115878 0.702617
min 0.006320 0.000000 0.460000 0.000000 0.385000 3.561000
25% 0.082045 0.000000 5.190000 0.000000 0.449000 5.885500
50% 0.256510 0.000000 9.690000 0.000000 0.538000 6.208500
75% 3.677083 12.500000 18.100000 0.000000 0.624000 6.623500
max 88.976200 100.000000 27.740000 1.000000 0.871000 8.780000
AGE DIS RAD TAX PTRATIO B \
count 506.000000 506.000000 506.000000 506.000000 506.000000 506.000000
mean 68.574901 3.795043 9.549407 408.237154 18.455534 356.674032
std 28.148861 2.105710 8.707259 168.537116 2.164946 91.294864
min 2.900000 1.129600 1.000000 187.000000 12.600000 0.320000
25% 45.025000 2.100175 4.000000 279.000000 17.400000 375.377500
50% 77.500000 3.207450 5.000000 330.000000 19.050000 391.440000
75% 94.075000 5.188425 24.000000 666.000000 20.200000 396.225000
max 100.000000 12.126500 24.000000 711.000000 22.000000 396.900000
LSTAT MEDV
count 506.000000 506.000000
mean 12.653063 22.532806
std 7.141062 9.197104
min 1.730000 5.000000
25% 6.950000 17.025000
50% 11.360000 21.200000
75% 16.955000 25.000000
max 37.970000 50.000000
可以考虑将CRIM,ZN,INDUS化为[0,1]之间的实数
TAX,B,AGE方差较大,可以采用一些降维的手段如:主成分分析(PCA)等
"""
print(data.info())
"""
RangeIndex: 506 entries, 0 to 505
Data columns (total 14 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 CRIM 506 non-null float64
1 ZN 506 non-null float64
2 INDUS 506 non-null float64
3 CHAS 506 non-null int64
4 NOX 506 non-null float64
5 RM 506 non-null float64
6 AGE 506 non-null float64
7 DIS 506 non-null float64
8 RAD 506 non-null int64
9 TAX 506 non-null int64
10 PTRATIO 506 non-null float64
11 B 506 non-null float64
12 LSTAT 506 non-null float64
13 MEDV 506 non-null float64
dtypes: float64(11), int64(3)
显示无缺失值
"""
#----------------数据处理----------------
#----------------缺失值处理----------------
null = pd.read_csv("D:/python/ITEM/HousePrice of Boston/Data/boston_null.csv")
print(null.head(5))# 读前五行
print(null.info())
"""
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 CRIM 506 non-null float64
1 ZN 506 non-null float64
2 INDUS 506 non-null float64
3 CHAS 506 non-null int64
4 NOX 504 non-null float64
5 RM 504 non-null float64
6 AGE 505 non-null float64
7 DIS 491 non-null float64
8 RAD 506 non-null int64
9 TAX 506 non-null int64
10 PTRATIO 506 non-null float64
11 B 453 non-null float64
12 LSTAT 506 non-null float64
13 MEDV 506 non-null float64
dtypes: float64(11), int64(3)
由上可知NOX,RM,AGE,DIS,B 存在空值
"""
#----------------缺失值处理-1.null进行计数---------------
print(null.isnull().sum())
"""
None
CRIM 0
ZN 0
INDUS 0
CHAS 0
NOX 2
RM 2
AGE 1
DIS 15
RAD 0
TAX 0
PTRATIO 0
B 53
LSTAT 0
MEDV 0
dtype: int64
"""
#----------------缺失值处理-2.缺失值可视化---------------
# 缺失值可视化
missing = null.isnull().sum()
missing = missing[missing > 0] # 筛选出有缺失值(大于0)的特征
missing.sort_values(inplace = True) # 排序
missing.plot.bar() # 调用pandas内置的条形图绘制
plt.show()
sns.heatmap(null.isnull())
plt.show()
"""
如果缺失值少,或者大量特征缺失但是在样本足够大的情况下也可以考虑删除.否则不建议删除
"""
#----------------缺失值处理-3.统计缺失比例---------------
A = []
for col in null.columns:
A.append((col,
null[col].isnull().sum() * 100 / null.shape[0]))#每列NULL个数/样本含量
pd.DataFrame(A, columns=['Features', 'missing rate'])
print(A)
"""
[('CRIM', 0.0),
('ZN', 0.0),
('INDUS', 0.0),
('CHAS', 0.0),
('NOX', 0.3952569169960474),
('RM', 0.3952569169960474),
('AGE', 0.1976284584980237),
('DIS', 2.964426877470356),
('RAD', 0.0),
('TAX', 0.0),
('PTRATIO', 0.0),
('B', 10.474308300395258),
('LSTAT', 0.0),
('MEDV', 0.0)]
如果缺失值超过95%的特征,我们会考虑删除它,因为意义不大.
"""
print(null.nunique()) #另一类特征也可以考虑删除,那就是方差特别小,或者说取值唯一的特征是没有意义的.,即只有一种取值
"""
CRIM 504
ZN 26
INDUS 76
CHAS 2
NOX 81
RM 445
AGE 356
DIS 401
RAD 9
TAX 66
PTRATIO 46
B 326
LSTAT 455
MEDV 229
dtype: int64
Process finished with exit code 0
"""
#将missing和unique合在一起
def df_stats(df):
'''
统计该df的缺失值,比例以及唯一值个数.
'''
L = []
for col in df.columns:
L.append((col,
df[col].isnull().sum(),
df[col].isnull().sum() * 100 / df.shape[0],
df[col].nunique()))
res = pd.DataFrame(L, columns = ['Feature',
'missing num',
'missing rate',
'unique num'])
return res
print(df_stats(null))
"""
Feature missing num missing rate unique num
0 CRIM 0 0.000000 504
1 ZN 0 0.000000 26
2 INDUS 0 0.000000 76
3 CHAS 0 0.000000 2
4 NOX 2 0.395257 81
5 RM 2 0.395257 445
6 AGE 1 0.197628 356
7 DIS 15 2.964427 401
8 RAD 0 0.000000 9
9 TAX 0 0.000000 66
10 PTRATIO 0 0.000000 46
11 B 53 10.474308 326
12 LSTAT 0 0.000000 455
13 MEDV 0 0.000000 229
Process finished with exit code 0
#
"""
#----------------缺失值处理-4.缺失值填充---------------
null = null.fillna(null.mean()) # 用均值填充
"""
空值填充方法
一、直接填充
0值/-1值填充
单变量填补:用单一变量的均值/中位数/众数/二分之一最小值/零值进行补值
二、插值填充
所谓的插值法就是通过两点(x0,y0),(x1,y1)估计中间点的值
三、KNN预测缺失值进行填充
步骤是选择出其他不存在缺失值的列,同时去除掉需要预测缺失值的列存在缺失值的行,然后计算距离。
如果缺失值是离散的,使用K近邻分类器,投票选出K个邻居中最多的类别进行填补;如果为连续变量,则用K近邻回归器,拿K个邻居中该变量的平均值填补。
四、Kmeans预测缺失值进行填充
参考:https://blog.csdn.net/vivian_ll/article/details/91900323
"""
sns.heatmap(null.isnull())
plt.show()
#----------------变量分析----------------
"""
1.研究单变量随机变量的性质与特征刻画
分析一个变量的情况,包括但不限于:数据类型、分布情况、是否有离群值
2.研究随机变量之间的关系.
相关性分析、分组统计···
"""
#----------------单变量分析----------------
#1.分析标签
"""
明白任务的需求:数据挖掘任务主要分为两类:回归与分类.
回归:是指标签值是连续值的任务,例如预测房价信息,房价是一个连续的变量,任务属于回归问题(Regression).
分类:标签是离散的数据分析任务,鸢尾花(Iris)数据集,它收集了三种鸢尾花的萼片长度,宽度等信息,要求预测鸢尾花属于哪种类别,因此它的标签就是1,2,3,代表三类鸢尾花.
本次任务属于回归型任务
"""
print(data["MEDV"].nunique())
#229
print(data["MEDV"].describe())#统计信息
"""
count 506.000000
mean 22.532806
std 9.197104
min 5.000000
25% 17.025000
50% 21.200000
75% 25.000000
max 50.000000
Name: MEDV, dtype: float64
Process finished with exit code 0
方差不大但是不够集中,非正态,极值较正常
"""
#密度分布图
plt.figure()
sns.distplot(data["MEDV"],
bins=100,#柱子的个数
hist=True,#是否绘制直方图
kde=True,#是否绘制密度图
rug=True,#数据分布标尺
color='b',#颜色
# vertical=False,#是否水平绘制
# norm_hist=False,#标准化,kde为True时自动标准化
axlabel=None,#x轴标注
label=None,#图例标签,通过plt.legend()显示
ax=None,
)
plt.show()
#分布呈现轻微右偏,可以考虑用对数化处理让其符合正态分布
plt.figure()
sns.distplot(np.log(data["MEDV"]+1),
bins=100,#柱子的个数
hist=True,#是否绘制直方图
kde=True,#是否绘制密度图
rug=True,#数据分布标尺
color='r',#颜色
# vertical=False,#是否水平绘制
# norm_hist=False,#标准化,kde为True时自动标准化
axlabel=None,#x轴标注
label=None,#图例标签,通过plt.legend()显示
ax=None,
)
plt.show()
"""
分类任务:
采用此法画出频率分布直方图,或者直接更直接的画图条形统计图.
如果分类的标签分布是相似的,可以直接建模. 但如果标签出现很明显的一高一低的情况,说明标签的分布不均衡,那再建模前需要做一些操作(例如:欠采样、调整损失函数),再进行建模.
否则会出现一个问题,模型会对出现频率低的样本非常不敏感. 模型训练的过程就类似考前复习的过程,所以我们在建模前要尽量保证标签的均衡性.
"""
#----------------离散型变量----------------
data[['CHAS', 'RAD']].hist()
plt.show()
#类别型变量更大的作用是用于后续在特征工程中,用于进行特征交叉,继续特征的增强,挖掘更深层次的潜在信息.
#----------------连续型变量----------------
data[['CRIM', 'ZN', 'INDUS', 'NOX', 'RM', 'AGE', 'DIS', 'TAX', 'PTRATIO', 'B', 'LSTAT']].hist(bins=100)
plt.show()
"""
变量实际上是有相似(A高B高)的分布情况的,或者相反的分布情况的(A高B低),这样的性质称为变量之间的相关性. 相关性一般有两种情况:
正相关:如果特征A的增加(减少)会导致特征B增加(减少),即特征A与特征B变化趋势相同.
负相关:如果特征A的增加(减少)会导致特征B减少(增加),即特征A与特征B变化趋势相反.
当两个变量呈正相关或者负相关时,我们称两个变量是相关的. 如果两个变量有较强的相关性时,如果将这些变量一起用的话,会有很多是冗余的. 因为这样变量之间有较强的相关性,
那么变量与变量之间是可以相互表示的,所以在建模时,需要尽可能消除特征之间的共线性,也就是尽量使用相关性比较小的特征,这样可以减少训练时间,使得模型的学习效果更好.那么下面我们讲讲如何去刻画特征间的相关性.
"""
#----------------多变量分析----------------
#1. 相关性
"""
可视化而言,最简单的方式就是将两个特征对应的坐标点在坐标系下描出来,研究他们的变化趋势,也就是说每一个点的坐标试一个二元组(Xai,ybi),
其中Xai表示第i个样本,特征a的取值;
ybi表示第i个样本,特征b的取值. 我们用seaborn库可以很直观的任意两个特征之间的散点图.
"""
# 任意两个变量间的相关性散点图来判断
sns.set()
cols = data.columns # 罗列出数据集的所有列
sns.pairplot(data[cols], size = 2.5) # 成对画出任意两列的散点图
plt.show()
"""
分析:
1.先看图像呈“对角线分布的”,即/或者\这两种类型分布的图像,这样的图像说明这两个变量间有较强的相关性,是可以被消除共线性的“嫌疑对象”.
如图中的DIS和AGE,尽管他不是严格的直线分布,但至少其分布呈现带状
2.看那些趋势比较明显单调,但是不太像直线,而是类似于“对数函数”的图像,
例如图中的DIS和NOX,因为这类图像,只要做一下对数化,马上就可以得到类似直线的效果,那么也是可以被处理的.
3.关注需要得出的预测结果,一般最后一行(列)与其他行(列)的关系,也就是特征与标签的关系,
如果这两者出现了较强相关性,那么这些特征我们需要留意,因为这些特征对标签有着比较直接的关系,例如RM和LSTAT.
"""
sns.pairplot(data[["AGE", "DIS"]], size = 3) # 成对画出任意两列的散点图, size是点的大小
plt.show()
sns.pairplot(np.log(data[["NOX", "DIS"]]), size = 3)
plt.show()
sns.pairplot(np.log(data[["RM", "LSTAT", "MEDV"]]), size = 3)
plt.show()
#2.刻画两个随机变量的相关性的方法:协方差与相关系数.
print(data.cov())
# 直接计算相关性系数
Corr_Matrix = data.corr()
print(Corr_Matrix)
#相关性系数,采用热力图进行可视化
#correlation matrix
f, ax = plt.subplots(figsize=(12, 9)) # 设置画布
sns.heatmap(Corr_Matrix, vmax=.8, square=True # 画热力图
# , annot=True # s是否显示数值
)
plt.show()