本文是《机器学习算法竞赛实战》的读书笔记2:在进行建模之前如何进行数据探索,了解数据的基本情况。通过系统的探索加深对数据的理解。
最好使用多种思路和方法来探索每个变量并比较结果。
如果跳过数据探索阶段或者只做肤浅的分析工作,可能导致数据倾斜,出现异常值或者缺失值。
数据探索的目的:
数据探索阶段必须做的7件事:
In [1]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
from sklearn.model_selection import KFold # K折交叉验证
from sklearn.metrics import mean_squared_error #评价指标mse
from sklearn.preprocessing import OneHotEncoder # 独热码
import lightgbm as lgb # lgb模型
import warnings
warnings.filterwarnings("ignore")
导入数据:
In [2]:
train = pd.read_csv("train.csv")
test = pd.read_csv("test.csv")
展示特征字段的nunique和缺失值情况:
In [3]:
train.head()
Out[3]:
字段的缺失值情况:
In [4]:
train.isnull().sum()
Out[4]:
Id 0
MSSubClass 0
MSZoning 0
LotFrontage 259
LotArea 0
...
MoSold 0
YrSold 0
SaleType 0
SaleCondition 0
SalePrice 0
Length: 81, dtype: int64
In [5]:
train["LotFrontage"].value_counts(normalize=True,dropna=True)
Out[5]:
60.0 0.119067
70.0 0.058285
80.0 0.057452
50.0 0.047460
75.0 0.044130
...
137.0 0.000833
141.0 0.000833
38.0 0.000833
140.0 0.000833
46.0 0.000833
Name: LotFrontage, Length: 110, dtype: float64
In [6]:
train["LotFrontage"].value_counts(normalize=True)
Out[6]:
60.0 0.119067
70.0 0.058285
80.0 0.057452
50.0 0.047460
75.0 0.044130
...
137.0 0.000833
141.0 0.000833
38.0 0.000833
140.0 0.000833
46.0 0.000833
Name: LotFrontage, Length: 110, dtype: float64
In [7]:
stats = []
for col in train.columns:
stats.append((col, # 字段名称
train[col].nunique(), # 唯一值数目
train[col].isnull().sum() * 100 / train.shape[0], # 该字段的缺失值比例
train[col].value_counts(normalize=True,dropna=False).values[0] * 100, # 字段中每个值的占比,取最高的那个值
train[col].dtype # 字段类型
))
stats_df = pd.DataFrame(stats,
columns=["Feature","Unique_values","Percentage of missing values",
"Percentage of values in biggest category","type"])
# 某些字段的缺失值比例高达95%,可以直接删除
stats_df.sort_values("Percentage of missing values", ascending=False)[:10]
使用柱状图直观显示缺失值分布情况:
In [8]:
missing = train.isnull().sum()
missing = missing[missing > 0]
missing.sort_values(inplace=True)
missing.plot.bar()
单变量分为:
In [9]:
train["SalePrice"].describe()
Out[9]:
count 1460.000000
mean 180921.195890
std 79442.502883
min 34900.000000
25% 129975.000000
50% 163000.000000
75% 214000.000000
max 755000.000000
Name: SalePrice, dtype: float64
In [10]:
# 可视化查看数据分布情况
plt.figure(figsize=(9,8))
sns.distplot(train["SalePrice"], color="g",bins=100, hist_kws={"alpha":0.4})
plt.show()
小结:数据呈现正态分布,向右倾斜,存在峰值。
对字段的取值进行取对数操作:
In [11]:
# 取对数np.log
plt.figure(figsize=(9,8))
sns.distplot(np.log(train["SalePrice"]), color="b",bins=100, hist_kws={"alpha":0.4})
plt.show()
In [12]:
# 可视化查看数据分布情况
plt.figure(figsize=(10,8))
sns.displot(
data=train,
x="LotArea",
kind="hist",
aspect=2
)
# plt.grid()
plt.show()
In [13]:
# # 可视化查看数据分布情况
# plt.figure(figsize=(10,8))
# sns.displot(
# data=train,
# x="LotFrontage",
# kind="hist",
# aspect=2
# )
# # plt.grid()
# plt.show()
In [14]:
# 可视化查看数据分布情况
plt.figure(figsize=(10,8))
sns.displot(data=train,x="MSSubClass",kind="hist",aspect=2)
plt.show()
In [15]:
# # 可视化查看数据分布情况
# plt.figure(figsize=(10,8))
# sns.displot(data=train,x="MSSubClass",kind="hist",aspect=2)
# plt.show()
In [16]:
plt.figure(figsize=(10,8))
sns.displot(data=train,x="OverallQual",kind="hist",aspect=2)
plt.show()
<Figure size 720x576 with 0 Axes>
In [17]:
df_num = train.select_dtypes(include=["float64","int64"])
df_num = df_num[df_num.columns.tolist()[1:5]]
df_num.hist(figsize=(16,20), bins=50,xlabelsize=8,ylabelsize=8)
plt.show()
如果两个特征完全正相关,这意味着两个特征包含高度相似的信息,信息中几乎没有或者完全没有差异,这就是多重线性。
所以可以尽可能删除冗余特征,降低训练时间和难度。
In [18]:
corrmat = train.corr()
f, ax = plt.subplots(figsize=(20,9))
sns.heatmap(corrmat, vmax=0.8, square=True)
plt.show()
数据字段:
字段的基本统计量信息:
In [22]:
plt.figure(figsize=(8,6))
sns.countplot(df_cat["MSZoning"])
plt.show()
plt.figure(figsize=(8,6))
sns.countplot(df_cat["Street"])
plt.show()
In [24]:
plt.style.use("seaborn-white")
type_cluster = train.groupby(["Neighborhood","OverallQual"]).size()
type_cluster.head()
Out[24]:
Neighborhood OverallQual
Blmngtn 7 14
8 3
Blueste 6 2
BrDale 5 5
6 11
dtype: int64
In [25]:
type_cluster.unstack() # 部分截图
# plt.figure(figsize=(20,10))
type_cluster.unstack().plot(kind="bar",
stacked=True,
colormap="coolwarm_r",
figsize=(13,11),
grid=False)
plt.xlabel("OverallQual",fontsize=16)
plt.show()
plt.figure(figsize=(18,12))
sns.boxplot(data=train, x="Neighborhood",y="SalePrice")
plt.show()
小结:上面的图形说明高评价位置(NoRidge、NrigHt和StoneBr)对应高SalePrice,也说明房屋位置评价和高房价有较强的相关性。可以构造新特征:
学习曲线是机器学习中用来进行模型效果评估的工具,能够反映训练集和验证集在训练迭代中的分数变化情况。
欠拟合:指模型无法学习到训练集中数据所展现的信息。一般如果训练的损失曲线是一条平坦的线或者相对较高的线,这就表明该模型根本无法学习训练集。 过拟合:模型对训练集学习得很好,但是对新数据的学习效果很差,导致泛化能力差
欠拟合和过拟合曲线的对比:
通过模型训练可以得到特征重要性,比如树模型通过计算特征的信息增益或者分裂次数等得到特征的重要性,模型LR或者SVM等使用特征系数作为特征重要组成部分(特征系数越大,则表示对模型的影响越大)。
误差分析就是我们通过模型预测的结果来发现问题的关键所在。