【Python】【数据分析】葡萄酒质量评价

时间:2024-03-06 17:45:17

摘要

本例为演示数据分析的流程和对概率论和数理统计基础知识的应用,使用Python的pandas和statmodels生成标准的描述性统计量和模型,对数据集进行探索和摘要分析,并利用多元线性回归进行回归分析。

本例以葡萄酒类型为标签,分为白葡萄酒和红葡萄酒。比较这两种葡萄酒的差别并选取葡萄酒的化学成分:固定酸度、挥发性酸度、柠檬酸、氯化物、游离二氧化硫、总硫度、密度、PH值、硫酸盐、酒精度数共11个,针对酒的各类化学成分建立线性回归模型,从而预测该葡萄酒的质量评分。

数据收集

数据集来源:UCI Machine Learning Repository

winequality-red.csv

winequality-white.csv

本实验应用UCI机器学习数据库中的红葡萄酒和白葡萄酒数据文件,将其合成一个数据集。

winequality-both.csv

数据预处理

首先进行数据预处理和数据描述性统计,其中描述性统计量包括总数、均值、标准差、最小值、第25个百分位数、中位数、第75个百分位数和最大值。

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import statsmodels.api as sm
from statsmodels.formula.api import ols,glm
#将数据集读入到pandas数据框中
wine=pd.read_csv(\'winequality-both.csv\',sep=\',\',header=0)
#列名重命名,用下划线替换空格,使之符合python命名规范
wine.columns=wine.columns.str.replace(\' \',\'_\')
print(wine.head())
#显示所有变量的描述性统计量
#这些统计量包括总数、均值、标准差、最小值、第25个百分位数、中位数、第75个百分位数和最大值
print(wine.describe())
#找出唯一值
print(sorted(wine.quality.unique()))
#计算值的频率
print(wine.quality.value_counts())


通过观察知,没有缺失值和异常值,不需进行补充和处理。

数据分析

分组、直方图与t检验

绘制直方图

在数据预处理步骤中,计算出的描述性统计量是针对红葡萄酒和白葡萄酒两个数据集。接下来我们针对两个数据集分别分析,查看二者的质量分布。

#按照葡萄酒类型显示质量的描述性统计量
print(wine.groupby(\'type\')[[\'quality\']].describe().unstack(\'type\'))
#按照葡萄酒类型显示质量的特定分位数值
print(wine.groupby(\'type\')[[\'quality\']].quantile([0.25,0.75]).unstack(\'type\'))
#按葡萄酒类型查看质量分布
red_wine=wine.loc[wine[\'type\']==\'red\',\'quality\']
white_wine=wine.loc[wine[\'type\']==\'white\',\'quality\']
#使用seaborn和matplotlib绘图
sns.set_style("dark")
print(sns.distplot(red_wine,\
                  norm_hist=True,kde=False,color="red",label="Red wine"))
print(sns.distplot(white_wine,\
                  norm_hist=True,kde=False,color="white",label="White wine"))
plt.xlabel("Quality Score")
plt.ylabel("Density")
plt.title("Distribution of Quality by Wine Type")
plt.legend()
plt.show()

从统计图中可以看出,两种葡萄酒的评分都近似正态分布。

t检验

为检验红葡萄酒和白葡萄酒质量是否不同,此处用到数理统计中的假设检验方法,此处使用t检验判断红葡萄酒和白葡萄酒的平均评分是否有区别。由于我们想知道红葡萄酒和白葡萄酒评分的标准差是否相同,所以在t检验中可使用合并方差。

原假设:红白两种葡萄酒质量的均值相同。

#检验红葡萄酒和白葡萄酒质量是否有所不同
print(wine.groupby([\'type\'])[[\'quality\']].agg([\'std\']))
#按葡萄酒类型分组,计算质量的标准差和均值
tstat,pvalue,df=sm.stats.ttest_ind(red_wine,white_wine)
#分别返回t值和p值
print(\'tstat: %.3f pvalue: %.4f\' % (tstat,pvalue))

从检验的结果来看,p值<0.0005。根据实际推断原理,拒绝原假设,即认为红白两种葡萄酒质量有显著性差异,并且从均值上来看白葡萄酒的平均质量等级在统计意义上大于红葡萄酒的平均质量等级。

成对变量之间的关系和相关性

接下来我们研究一下变量之间的相关性,并创建部分变量之间带有回归直线的散点图。

数据集中有6000多个点,如果将它们都画在统计图中,就很难分辨出清楚的点。因此我们使用take_sample函数进行抽样。

#计算所有变量的相关矩阵
print(wine.corr())
#从红葡萄酒和白葡萄酒的数据中取出一个“小”样本进行绘图
def take_sample(data_frame,replace=False,n=200):
                return data_frame.loc[np.random.choice(data_frame.index,\
                                                       replace=replace,size=n)]
reds_sample=take_sample(wine.loc[wine[\'type\']==\'red\',:])
whites_sample=take_sample(wine.loc[wine[\'type\']==\'white\',:])
wine_sample=pd.concat([reds_sample,whites_sample])
wine[\'in_sample\']=np.where(wine.index.isin(wine_sample.index),1.,0.)
print(pd.crosstab(wine.in_sample,wine.type,margins=True))
#查看成对变量之间的关系
sns.set_style("dark")
g=sns.pairplot(wine_sample,kind=\'reg\',plot_kws={"ci":False,\
                                               "x_jitter":0.25,"y_jitter":0.25},hue=\'type\',diag_kind=\'hist\',\
              diag_kws={"bins":10,"alpha":1.0},palette=dict(red="red",white="white"),\
              markers=["o","s"],vars=[\'quality\',\'alcohol\',\'residual_sugar\'])
print(g)
plt.suptitle(\'Histograms and Scatter Plots of Quality,Alcohol,and Residual\
Sugar\',fontsize=14,horizontalaligment=\'center\',verticalaligment=\'top\',\
            x=0.5,y=0.999)
plt.show()

从各变量的相关系数来看酒精含量、硫酸酯、pH 值、游离二氧化硫和柠檬酸这些指标与质量呈现正相关,即当这些指标的含量增加时,葡萄酒的质量会提高;非挥发性酸、挥发性酸、残余糖分、氯化物、总二氧化硫和密度这些指标与质量呈负相关即当这些指标的含量增加时,葡萄酒的质量会降低。从相关系数可以看出,对葡萄酒质量影响最大的是葡萄酒是酒精含量,其相关系数为0.444,其次是酒的密度,但酒的密度对酒的质量是负影响的。

使用最小二乘估计进行线性回归

系数解释

相关系数和两两变量之间的统计图有助于对两个变量之间的关系进行量化和可视化。但它们不能测量出每个自变量在其他自变量不变时与因变量之间的关系,线性回归可以解决这个问题。

线性回归模型如下:

对i=1,2,…,n个观测和p个自变量。

这个模型表示观测yi服从均值为μi方差为σ2的正态分布,其中μi依赖于自变量,σ2为一个常数。也就是说,给定了自变量的值以后,我们就可以得到一个具体的质量评分,但在另一天,给定同样的自变量值,我们可能会得到一个与前面不同的质量评分。但经过一个较长的周期,质量评分会落在μ±σ这个范围内。

下面我们使用statmodel包进行线性回归。

my_formula=\'quality~alcohol+chlorides+citric_acid+density\
+fixed_acidity+free_sulfur_dioxide+pH+residual_sugar+sulphates\
+total_sulfur_dioxide+volatile_acidity\'
lm=ols(my_formula,data=wine).fit()
print(lm.summary())
print("\nQuantities you can extract from the result:\n%s"%dir(lm))
print("\nCoefficients:\n%s"%lm.params)
print("\nCoefficient Std Errors:\n%s"%lm.bse)
print("\nAdj.R-squared\n%.2f"%lm.rsquared_adj)
print("\nF-statistic:%.1f Pvalue:%.2f"%(lm.fvalue,lm.f_pvalue))
print("\nNumber of obs:%d Number of fitted values:%d"%(lm.nobs,\
                                                      len(lm.fittedvalues)))

在这个模型中,某个自变量系数的意义是:在其他自变量保持不变的情况下,这个自变量发生一个单位的变化时,导致葡萄酒质量评分发生的平均变化。

自变量标准化

关于这个模型,还需要注意的一点是,普通最小二乘回归是通过使残差平方和最小化来估计未知的β参数值。由于残差大小依赖于自变量的测量单位。所以当自变量测量单位不同,我们需要将自变量标准化。

由上一步的观测数据知,各变量间最大值和最小值之间差别很大,因此应进行标准化。

pandas在数据框中对变量进行标准化非常容易。你可以对一个观测写一个变换公式,pandas将其扩展到行和列中,来标准化所有变量。

#创建一个名为dependent_variable的序列来保存质量数据
dependent_variable=wine[\'quality\']
#创建一个名为independent_variables的数据框
independent_variables=wine[wine.columns.difference([\'quality\',\'type\',\
                                                   \'in_sample\'])]
#对自变量进行标准化,减去均值、除以标准差
independent_variables_standardized=(independent_variables -\
                                   independent_variables.mean())/independent_variables.std()
#将因变量quality作为一列添加到自变量数据框
#创建一个带有标准化自变量的新数据集
wine_standardized=pd.concat([dependent_variable,independent_variables_standardized],axis=1)
#重新进行线性回归
lm_standardized=ols(my_formula,data=wine_standardized).fit()
print(lm_standardized.summary())

图片

观测数据知,线性回归模型为:quality= 0.0877fixed acidity -0.2186volatile acidity -0.0159citric_acid+ 0.2072residual_sugar-0.0169chlorides+ 0.1060free_sulfur_dioxide -0.1648density-0.1402total_sulfur_dioxide+0.0706pH+0.1143sulphates+ 0.3185*alcohol+5.8184

在我们的模型摘要中,截距系数的意义就是当一种葡萄酒的所有成分都取均值时,它的质量评分均值应该是5.8,标准差为0.009。

预测

有了线性回归模型,当给出了葡萄酒的化学成分的数据就可以预测该葡萄酒的质量评分。

在某些情况下,我们需要使用没有用来拟合模型的新数据进行预测。例如,你会收到关于葡萄酒成分的一个新的观测,并需要根据这些成分预测这种葡萄酒的质量评分。让我们通过选择现有数据集的前10个观测,根据它们的成分进行评分。

#使用葡萄酒数据集中的前10个观测创建10个“新”观测
#新观测只包含模型中是用的自变量
new_observations=wine.ix[wine.index.isin(range(10)),\
                        independent_variables.columns]
#基于新观测中的葡萄酒特性预测质量评分
y_predicted=lm.predict(new_observations)
#将预测值保留2位小数
y_predicted_rounded=[round(score,2) for score in y_predicted]
print(y_predicted_rounded)

result:

[5.0, 4.92, 5.03, 5.68, 5.0, 5.04, 5.02, 5.3, 5.24, 5.69]