一 汽车产品聚类分析说明
1.1赛题背景
赛题以竞品分析为背景,通过数据的聚类,为汽车提供聚类分类。对于指定的车型,可以通过聚类分析找到其竞品车型。通过这道赛题,鼓励学习者利用车型数据,进行车型画像的分析,为产品的定位,竞品分析提供数据决策。
1.2赛题数据
1.3赛题任务
对该汽车数据进行聚类分析,并找到vokswagen汽车的相应竞品。
二、作答
2.1数据处理
2.1.1数据导入
import pandas as pd
import numpy as np
import matplotlib.pyplt as plt
car_data=pd.read_csv('./car_price.csv')
car_data.head()
2.1.2查看数据类型以及重复项
car_data.info()#查看26个字段的类型
car_data.duplicated().sum()#查看是否有重复项
##调取每个类型下(int 64)的数据,并进行描述统计
car_data_int=car_data.select_dtypes(include='int64')
car_data_int.describe()#根据结果显示int类型的数据正常,没有异常值
##调取每个数值类型(float)下的数据,并进行描述统计
car_data_float=car_data.select_dtypes(include='float64')
car_data_float.describe()#根据结果显示float64类型的数据正常,没有异常值
##调取文本类型下的数据,并进行描述统计,查看文本值的分布情况
car_data_object=car_data.select_dtypes(include='object')
for i in car_data_object.columns:
print(i)
print(set(car_data_object[i]))#set是一组dict字典形式,可以过滤重复值
将潜在的数值型文本数据进行转化
object_dic={'two':2,'four':4, 'six':6, 'eight':8, 'twelve':12, 'three':3, 'five':5, 'four':4}
car_data['doornumber']=car_data['doornumber'].replace(object_dic)
car_data['cylindernumber']=car_data['cylindernumber'].replace(object_dic)
除此以外可以看出品牌名中有些错误拼写的问题,竞品分析是以'volkswagen'为基础,因此需要先对品牌名称进行处理。处理方法:1.只留下品牌名 2.改正拼写错误
car_data['CarName']=car_data['CarName'].apply(lambda x :str(x).split(' ')[0])
car_data.head()
#注意用str(x) 而不是x.split() 否则报错
其中车辆品牌列已经完全获取品牌名,但是还存在拼写错误,用replace进行替换
#查看有哪些品牌名
car_data_name=set(car_data['CarName'])
car_data_name
'maxda'、'porsche'等属于拼写错误
#改正拼写及大小写错误
car_data_name={'maxda':'mazda','Nissan':'nissan','porsche':'porcshce','toyouta':'toyota','vokswagen':'volkswagen','vw':'volkswagen'}#字典形式
car_data['CarName']=car_data['CarName'].replace(car_data_name)
car_data_name2=set(car_data['CarName'])
car_data_name2
更改以后只剩22个品牌
2.2 数据分析
2.2.1 数值型异常值分析--箱型图与描述型统计相结合
car_data_float=car_data.select_dtypes(include='float64')
car_data_float.describe()
绘制数值型的箱型图
num_cols=car_data_float.columns
import seaborn as sns
fig=plt.figure(figsize=(12,8))
i=1
for col in num_cols:
ax=fig.add_subplot(2,4,i)
sns.boxplot(data=car_data[col],ax=ax,sym="r+")
i=i+1
plt.title(col)
plt.show()
对显示出异常值的wheelbase、carwidth等变量进行复查,从描述性统计中确定该变量是否真正有异常值。经过确定这部分变量的异常符合现实情况。
2.2.2 数值型数据相关性分析
#对数值型进行相关性分析,corr只对数值型进行操作
car_data_corr=car_data.corr()
car_data_corr
#使用mask只绘制热力图其中的一半
mask = np.zeros_like(car_data_corr)
mask[np.triu_indices_from(mask)] = True
with sns.axes_style("white"):
f, ax = plt.subplots(figsize=(25, 10))
ax = sns.heatmap(car_data_corr,annot = True, mask=mask,vmin=0,vmax=1, square=True)
ax.set_title('correlation between car')
相关系数分类: 0.8-1.0 极强相关;0.6-0.8 强相关;0.4-0.6 中等程度相关;0.2-0.4 弱相关;0.0-0.2 极弱相关或⽆相关
可以看出:车长与车宽、轴距具有极强相关关系,与空车重有强相关关系;发动机大小与车宽强相关,与空车重和气缸数量极强相关;马力和发动机大小、气缸数量、空车重也具有相关关系,城市里程和公路里程强相关,价格和空车重、发动机大小有关。可见数据冗余,应该进行处理
2.2.3 划分车辆类型--以车长为依据
在汽车销售等实际业务中,很多消费者购买需求有时会根据考虑车型的⼤⼩来考虑。
欧系分类,按德国标准,车型⼤⼩可按照车长,轴距划分为6类:
1、微型车(A00):车长⼩于3.7M;轴距⼩于:2.35M;
2、⼩型车(A0):车长⼩于4.3M;轴距⼩于:2.5M;
3、紧凑型车(A):车长⼩于4.6M;轴距⼩于:2.7M;
4、中型车(B):车长⼩于4.9M;轴距⼩于:2.8M;
5、中⼤型车(C):车长⼩于5.1M;轴距⼩于:2.9M;
6、豪华车(D):车长⼤于5.1M;轴距⼤于:2.9M。
⽽要注意,数据集中车长宽⾼和轴距单位均为英⼨,需要进⾏单位的转换:1英⼨=0.0254⽶。
按车⾝长度分类界限:微型车: A00 <145.67 ;⼩型车: A0<169.29 ;紧凑型车:A <181.10 ;中型车: B <192.91 ;中⼤型车:C<200.79;大型车:D>200.79
根据分类标准进行分箱操作
bin=[min(car_data.carlength)-0.01,145.67,169.29,181.10,192.91,200.79,max(car_data.carlength)+0.01]#确定分组标准
groupnames=['A00','A0','A','B','C','D']#定义箱名
car_group=pd.cut(car_data.carlength,bin,labels=groupnames)
#新建一列将分组情况放入数据集
car_data['cargroup']=car_group
car_data.head()
三 聚类前预处理
3.1 特征数值化
3.1.1 LabelEncoder编码
LabelEncoder编码是将有大小意义的非数值变量进行编码,比如cargroup('A00'<'A0'<'A'<'B'<'C'<'D')
cardata=car_data.copy()
cardata.head()
cardata['cargroup']=cardata['cargroup'].astype(str)
#进行编码之前将cargroup转换成字符型,否则报错
from sklearn.preprocessing import LabelEncoder
cargroup_copy=LabelEncoder().fit_transform(cardata['cargroup'])
cardata['cargroup']=cargroup_copy
3.1.2 one-hot编码
对没有大小意义的非数值变量进行one-hot编码
#剔除车长度,用车型代替(车型是根据车长来的)
cardata=cardata.drop(['carlenrth'],axis=1)
cardata_features=cardata.select_dtypes(include='object')
cardata_features.head()
#进行one-hot编码
cardata_onehot=pd.get_dummies(cardata_features,drop_first='True')#drop_first去除冗余特征,避免特征重复
cardata2=cardata.join(cardata_onehot).drop(cardata_features,axis=1)#把处理后的数据加上,处理前的数据删除
cardata2.info()
3.2 数据标准化处理
由于数值存在量纲的不同,因此对其进行区间化(标准化的一种),把值限定在0~1之间
from sklearn.preprocessing import MinMaxScaler
cardata2=MinMaxScaler().fit_transform(cardata2)
cardata2.shape
#将数据转化成矩阵形式
cardata2=pd.DataFrame(cardata2)
cardata2.head()
3.3 利用PCA对高维数据降维
主成分,将线性相关的高维数据转换成线性无关的低维数据,注意不是原特征变量,而是新建立的变量
from sklearn.decomposition import PCA
pca=PCA(.99)#可解释方差比例设为0.99
cardata3=pca.fit_transform(cardata2)
ratio=pca.explained_variance_ratio_
print('各主成分的解释方差占比:', ratio)
print('降维后有几个成分:', pca.n_components_)
cum_ratio=np.cumsum(ratio)
print('累计解释方差占比:',cum_ratio)
由原来的61个成分降维至39个成分
fig=plt.figure(figsize=(10,5))
X=range(1,len(ratio)+1)
plt.bar(X,ratio,edgecolor='blue')
plt.plot(X,cum_ratio,'r.-')
plt.xlabel('PCA')
plt.ylabel('explained_variance_ratio_')
plt.grid(b="True",axis="y")
plt.grid(b="True",axis="x")
plt.show()
根据28法则,累计解释方差达到80%的主成分有12个,保留主成分
pca=PCA(n_components=12)#提取出12个主成分
cardata4=pca.fit_transform(cardata3)
print('降维后累计解释方差占比:',sum(pca.explained_variance_ratio_))
cardata4=pd.DataFrame(cardata4)#将多维数组转化成矩阵形式
四 利用K-Means进行数据聚类
4.1 肘部法确定聚类个数
k均值聚类有一个缺点,无法提前确定聚类的个数,因此使用肘部法,先确定聚类个数
from sklearn.cluster import KMeans
sse=[]
kvals=range(1,20)#20是自己设置,确保明显的看到拐点
for k in kvals:
Kmeans=KMeans(n_clusters=k,init='k-means++',n_init=10,max_iter=300,random_state=0)#构造聚类器
Kmeans.fit(cardata4)#放入数据
sse.append(Kmeans.inertia_)
X=kvals
plt.xlabel('k')
plt.ylabel('sse')
plt.plot(X,sse,'o-')
plt.grid(b="True",axis="y")
plt.grid(b="True",axis="x")
plt.show()#可以看出拐点在第7个(不太明显)
进行k-means均值聚类,散点图查看聚类效果
kms=KMeans(n_clusters=5,init='k-means++',n_init=10,max_iter=300,random_state=123)#random_state没有特殊含义,保证每次运行代码选取的中心点一致
#n_clusters先根据肘部法设置为7,后尝试了7的左右值发现,聚类个数为5的情况下聚类效果最好
kms.fit(cardata4)
label=kms.labels_#获取聚类结果
print(label)
fig=plt.figure(figsize=(8,8))
plt.scatter(cardata4[label==0].iloc[:,0],cardata4[label==0].iloc[:,1],c="red",marker='o',label='class0')#红色圆圈样式绘制散点图
plt.scatter(cardata4[label==1].iloc[:,0],cardata4[label==1].iloc[:,1],c="red",marker='+',label='class1') #红色圆圈样式绘制散点图
plt.scatter(cardata4[label==2].iloc[:,0],cardata4[label==2].iloc[:,1],c="green",marker='o',label='class2') #红色圆圈样式绘制散点图
plt.scatter(cardata4[label==3].iloc[:,0],cardata4[label==3].iloc[:,1],c="green",marker='+',label='class3') #红色圆圈样式绘制散点图
plt.scatter(cardata4[label==4].iloc[:,0],cardata4[label==4].iloc[:,1],c="blue",marker='o',label='class4') #红色圆圈样式绘制散点图
plt.scatter(cardata4[label==5].iloc[:,0],cardata4[label==5].iloc[:,1],c="blue",marker='+',label='class5') #红色圆圈样式绘制散点图
plt.xlabel('pc1')
plt.ylabel('pc2')
plt.title('K-Means PCA')
plt.show()
通过对比聚类分析图,发现5类的聚类效果最好(省略了一步专业的评估,我不会哈哈哈)
五 聚类结果展示
将k=5时的分类结果数据(label)放到原特征数据中
cardata_km=car_data.copy()
cardata_km['km_result']=label
#统计每个集群,每个车品牌的车型数
cardata_km_num2=cardata_km.groupby(by=['km_result','CarName'])['car_ID'].count()
cardata_km_num2
其中0,1,4中有volkswage,把这三类的数据提取出来并合并
cardata_km_result0=cardata_km.loc[cardata_km['km_result']==0]
cardata_km_result1=cardata_km.loc[cardata_km['km_result']==1]
cardata_km_result4=cardata_km.loc[cardata_km['km_result']==4]
cardata_km_result=pd.concat([cardata_km_result0,cardata_km_result1,cardata_km_result4],axis=0)#pd.concat将数据合并,行向合并
cardata_km_result.loc[cardata_km_result['CarName']=='volkswagen']#查看'volkswagen'的车型
#A车型占比最大,故将A车型下的品牌作为volkswagen的竞品
dfa=df.loc[df['cargroup']=='A']
df_com=set(dfa['CarName'])
df_com
综上,'audi', 'dodge','honda', 'isuzu', 'mazda', 'mitsubishi', 'nissan', 'plymouth', 'renault', 'subaru','toyota'为 'volkswagen'的竞品品牌。
注:更完善的是细化至品牌内部,根据车型的车身重、动力性、安全性等对volkswagen及竞品的优劣势进行分析,给出销售建议。