数据分析——房价分析

我们来使用kaggle的埃姆斯市房价的数据进行影响房价的相关因素的分析。
数据下载:https://www.kaggle.com/c/house-prices-advanced-regression-techniques/data

我们所要做的事情是:

  1. 理解问题。要研究没一个变量,并且对其意义和重要性进行分析。
  2. 单变量研究。我们只关注SalePrice这个因变量。
  3. 多变量研究。将试着去理解因变量和自变量是如何关联的。
  4. 数据处理。处理缺失值、异常值以及分类变量。
  5. 检验假设。检验数据是否符合研究多变量所要求的假设。

Now,Lets have fun!

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from scipy.stats import norm
from sklearn.preprocessing import StandardScaler
from scipy import stats  #检验正态分布
import warnings
warnings.filterwarnings('ignore')
%matplotlib inline
#SciPy函数库在NumPy库的基础上增加了众多的数学、科学以及工程计算中常用的库函数。
#例如线性代数、常微分方程数值求解、信号处理、图像处理、稀疏矩阵等等。
file_path="./data/train.csv"
df_train=pd.read_csv(file_path)
#花一些时间了解这些变量的意义,与这个问题的相关性
#对SalePrice(美元)的总体的统计描述
df_train['SalePrice'].describe()

image.png

#histogram
sns.distplot(df_train['SalePrice'])

image.png
偏离正态分布,有明显的正偏态,有尖峰

#显示偏度skewness和峰度kurtosis
print("Skewness:%f" %df_train['SalePrice'].skew())
print("Kurtosis:%f" %df_train['SalePrice'].kurt())
#首先研究很相近的变量GrLivArea(地面以上的居住面积)和TotalBsmtSF(地下室总面积)
#scatter plot grlivarea/saleprice
var='GrLivArea'
data=pd.concat([df_train['SalePrice'],df_train[var]],axis=1)
data.plot.scatter(x=var,y='SalePrice',ylim=(0,800000))

image.png
看样子,房价saleprice和grlivarea是线性关系

#scatter plot totalbsmtsf/saleprice
#pd.concat数据拼接,axis=1表示纵向拼接(列数增加)
var='TotalBsmtSF'
data=pd.concat([df_train['SalePrice'],df_train[var]],axis=1)
data.plot.scatter(x=var,y='SalePrice',ylim=(0,800000))

image.png
似乎是指数关系?并且还有一些为0的情况
与分类特征的关系

#box plot箱图 overallqual/saleprice 总体材料和加工质量,1-10等级
#df_train['OverallQual'].describe()

var='OverallQual'
data=pd.concat([df_train['SalePrice'],df_train[var]],axis=1)
#f,ax=plt.subplots(figsize=(8,6))
plt.figure(figsize=(8,6))
fig=sns.boxplot(x=var,y='SalePrice',data=data)
fig.axis(ymin=0,ymax=800000)

image.png

#原始施工日期YearBuilt与SalePrice的关系
var='YearBuilt'
data=pd.concat([df_train['SalePrice'],df_train[var]],axis=1)
plt.figure(figsize=(20,8))
fig=sns.boxplot(x=var,y="SalePrice",data=data)
fig.axis(ymin=0,ymax=800000)
plt.xticks(rotation=45)#x坐标轴标签的倾斜度

image.png
虽然不是很明显的趋势,但是我认为新的房子应该要比旧的销售价格高
In summary
1.GrLivArea和TotalBsmtSF似乎与SalePrice线性相关。两种关系都是积极的,这意味着当一个变量增加时,另一个也会增加。TotalBsmtSF与SalePrice的关系的斜率特别高
2.OverallQual和YearBuilt似乎也和SalePrice有关。在OverallQual中,关系更强。
以上分析的四个变量都是从主观上认为应该与saleprice相关的,我们需要更客观地来分析
1.关系矩阵(热图)
2.与saleprice的关系矩阵
3.最相关的变量之间的散点图

#correlation matrix
#计算了每一列之间的相关性
corrmat=df_train.corr()
#print(corrmat)
#plt.figure(figsize=(12,9))
f,ax=plt.subplots(figsize=(12,9))
sns.heatmap(corrmat,vmax=.8,square=True)

image.png

  • totalbsmtsf和1stflrsf形成的白色小方块还有garageX(3个)形成的白色小方块显示了强烈的相关性,热图在展示多重共线的情况很有用。
  • 也可以看到GrLivArea、TotalBsmtSF和OverallQual与salePrice很明显的相关性,但是也可以看到其他一些变量也应该被考虑到。
#SalePrice correlation matrix
k=10 #10 variables for heatmap,选10是因为?
cols=corrmat.nlargest(k,'SalePrice')['SalePrice'].index #和saleprice相关性最高的10个行索引
cm=np.corrcoef(df_train[cols].values.T) #.T是啥呀??
sns.set(font_scale=1.25)
hm=sns.heatmap(cm,cbar=True,annot=True,square=True,fmt='.2f',annot_kws={'size':10},yticklabels=cols.values,xticklabels=cols.values)
plt.show()

image.png
根据我们的预测,这些是与salePrice最相关的变量

  • overallqual、grlivarea、totalbsmtsf确实是与saleprice相关性很高
  • garagecars和garagearea只需保留一个进行分析即可。因为车库的面积直接决定了可容纳的车辆数,保留garagecars,因为它相关性更高一些。
#sns.pairplot函数画出变量两两间的关系,kind="reg"可以为散点图拟合一条直线,hue=“某一字段”可以根据某字段进行分类,platte控制分类的颜色
sns.set()
cols=['SalePrice','OverallQual','GrLivArea','GarageCars','TotalBsmtSF','FullBath','YearBuilt']
sns.pairplot(df_train[cols],kind="reg",size=2.5)
plt.show()

image.png
可以从中发现许多有趣的关系,比如总地下室面积totalbsmtsf与grlivarea生活面积,形成一条分界线,点基本分布在下方,因为一般地下室的面积不会超过生活面积。

处理缺失值,missing value
思考:缺失的情况普遍吗?是随机的缺失还是有模式的缺失

#missing data
total=df_train.isnull().sum().sort_values(ascending=False)
percent=(df_train.isnull().sum()/df_train.isnull().count()).sort_values(ascending=False)
# print(total)
# print(percent)
missing_data=pd.concat([total,percent],axis=1,keys=['Total','Percent'])
missing_data.head(20)

image.png

#有20个字段包含null值
#分别是泳池的质量、其他类别特性、路的类型、栅栏的质量等我们可以删去,因为本身买房也不太会考虑到这些因素。
#garageX等也可以删去,因为我们已经分析了garagecars这个最重要的因素,bsmtX也是(已经有了totalbsmtSF)
#MasVnrX,我们可以认为不重要,并且他们和yearbuilt、overallqual有很强的相关性,而这两个我们已经考虑进去了,所以删掉MasVnrX不会丢失信息
#最后是electrical,只有一个缺失值,我们将缺失值删去,保留这个变量
#dealing with missing data
df_train=df_train.drop((missing_data[missing_data['Total']>1]).index,1)
# df_train剩余18 columns
#删掉electrical的一个空值所在的行
df_train=df_train.drop(df_train.loc[df_train['Electrical'].isnull()].index)
#检验一下
df_train.isnull().sum().max()

离群值outliers!

离群值通常是很重要的部分,它可能会影响我们的模型,也会给我们带来一些关于特定的行为的信息,值得关注!

我们用标准差和散点图来分析saleprice

#首先要确定一个threshold来定义离群值。
#对数据进行标准化,即均值为0,方差为1
#newaxis增加维度,索引多维数组的
saleprice_scaled=StandardScaler().fit_transform(df_train['SalePrice'][:,np.newaxis])
#argsort()返回按升序排序后各元素原始的序号(from 0)
#saleprice_scaled一共1459,返回前10个和最后10个
low_range=saleprice_scaled[saleprice_scaled.flatten().argsort()][:10]
high_range=saleprice_scaled[saleprice_scaled.flatten().argsort()][-10:]
print('outer range (low) of the distribution:')
print(low_range)
print('\nouter range (high) of the distribution:')
print(high_range)

low range都比较相似,离0不远 high range从0到7不等,有些值超过了范围 要小心两个7以上的值
双变量分析

#saleprice/grlivarea
var='GrLivArea'
data=pd.concat([df_train['SalePrice'],df_train[var]],axis=1)
data.plot.scatter(x=var,y='SalePrice',ylim=(0,800000))

image.png
可以观察到右侧有两个特殊的值,面积很大房价却比较低,有可能是农业区域之类的,它不能代表总体的趋势,所以可以将他们定义为离群值删掉。

#deleting
df_train.sort_values(by='GrLivArea',ascending=False)[:2] # index:1299、523
df_train=df_train.drop(df_train[df_train['Id']==1299].index)
df_train=df_train.drop(df_train[df_train['Id']==524].index)
#saleprice/totalbsmtsf(地下室总面积)
var='TotalBsmtSF'
data=pd.concat([df_train[var],df_train['SalePrice']],axis=1)
data.plot.scatter(x=var,y='SalePrice',ylim=(0,800000))

image.png
一些离散的点在可以接受的范围内,可以不用删除

四种假设需要被检验

  • Normality-检验saleprice是否是正态分布
  • Homoscedasticity-同方差是指假设因变量(s)在预测变量(s)的范围内具有相同水平的方差 ???
  • Linearity-常用的方法就是画散点图寻找线性模式,如果不是线性的,要研究数据转换
  • Absence of correlated errors-关联错误,发生在一个错误与另一个错误相关联的时候。通常发生在时间序列中,如果检测到什么,就尝试添加一个变量来解释得到的效果,这是相关错误最常见的解决方案。
#normality
#直方图:检验峰度和偏态
#正态分布概率图:数据的分布应该尽量与正态分布一致
sns.distplot(df_train['SalePrice'],fit=norm)
#QQ图,检验样本数据概率分布的方法(默认检验正态分布),红色表示正态分布,蓝色是样本数据,蓝色越接近红色表明越符合期望分布
fig=plt.figure()
res=stats.probplot(df_train['SalePrice'],plot=plt)

image.png
saleprice不是正态分布,是正偏态的情况(右偏态),可以用对数转换。

#log transformation
df_train['SalePrice']=np.log(df_train['SalePrice'])
sns.distplot(df_train['SalePrice'],fit=norm)
fig=plt.figure()
res=stats.probplot(df_train['SalePrice'],plot=plt)

image.png

#grlivarea
sns.distplot(df_train['GrLivArea'],fit=norm)
fig=plt.figure()
res=stats.probplot(df_train['GrLivArea'],plot=plt)

image.png

#log transform
df_train['GrLivArea']=np.log(df_train['GrLivArea'])
sns.distplot(df_train['GrLivArea'],fit=norm)
fig=plt.figure()
res=stats.probplot(df_train['GrLivArea'],plot=plt)

image.png

#totalbsmtsf
sns.distplot(df_train['TotalBsmtSF'],fit=norm)
fig=plt.figure()
res=stats.probplot(df_train['TotalBsmtSF'],plot=plt)
#现在有一个问题,发现数据中有很多0的情况,这不能做log转换,采用将所有不为0的进行对数转换,对0值不做处理,这样也保留了0代表没有地下室的特性。
#创建一个新变量,if area>1 it gets 1,for area==0 it gets 0
df_train['HasBsmt']=pd.Series(len(df_train['TotalBsmtSF']),index=df_train.index)
df_train['HasBsmt']=0
df_train.loc[df_train['TotalBsmtSF']>0,'HasBsmt']=1
df_train.loc[df_train['HasBsmt']==1,'TotalBsmtSF']=np.log(df_train['TotalBsmtSF'])
sns.distplot(df_train[df_train['TotalBsmtSF']>0]['TotalBsmtSF'],fit=norm)
fig=plt.figure()
res=stats.probplot(df_train[df_train['TotalBsmtSF']>0]['TotalBsmtSF'],plot=plt)

image.png

#验证同方差性
#GrLivArea
plt.scatter(df_train['GrLivArea'],df_train['SalePrice'])

image.png
可以看到正态转换之后,散点图不再呈现圆锥形了

#TotalBsmtSF
plt.scatter(df_train[df_train['TotalBsmtSF']>0]['TotalBsmtSF'],df_train[df_train['TotalBsmtSF']>0]['SalePrice'])

image.png
我们可以说,在一般情况下,saleprice在totalbsmtsf范围内表现出相同水平的差异

#将分类变量转换为哑变量(dummy)
df_train=pd.get_dummies(df_train)

summary

以上分析了销售价格和最相关的一些变量,处理了数据的缺失值和异常值,检验了一些基本的统计假设,最后将分类变量转变为哑变量。Python helps a lot!

你可能感兴趣的:(python,数据分析)