本案例利用K-Means聚类算法来进行青少年市场细分,使用R语言编程对数据进行清洗,然后使用R中的stats包训练模型,并对聚类结果进行分析。
市场细分(market segmentation)是指营销者通过市场调研,依据消费者的需要和欲望、购买行为和购买习惯等方面的差异,把某一产品的市场整体划分为若干消费者群的市场分类过程。 每一个消费者群就是一个细分市场,每一个细分市场都是具有类似需求倾向的消费者构成的群体。 市场细分能够对企业的生产、营销起到极其重要的作用:
有利于选择目标市场和制定市场营销策略
有利于发掘市场机会,开拓新市场
有利于集中人力、物力投入目标市场
有利于企业提高经济效益
随着Facebook, Twitter等社交网络平台的流行,越来越多的青少年用户会在这些平台发布消息。 这些文本数据能够反映青少年的行为、兴趣爱好,结合社交网络平台上用户的性别、年龄、好友数等信息,对于挖掘青少年细分市场具有很大的价值。
细分市场都是具有类似需求倾向的消费者,而聚类算法很适合用来完成这一任务的。 本案例中,我们将使用一份从社交网络平台抽取的描述青少年基本信息和兴趣爱好的数据集,利用K-Means聚类算法来进行青少年市场细分。
我们使用一份包含30000个样本的美国高中生社交网络信息数据集。
数据均匀采样于2006年到2009年,对应的高中生年级有高中一年级、二年级、三年级和四年级。
每个样本包含40个变量,其中 gradyear
,gender
,age
和friends
四个变量代表高中生的毕业年份、性别、年龄和好友数等基本信息。
其余36个变量代表36个词语,这36个词语代表高中生的5大兴趣类:课外活动、时尚、宗教、浪漫和反社会行为。
每个词语变量的取值代表对应词语在高中生的社交网络服务平台发布的消息中出现的频次。
36个词语的列表如下:
basketball (篮球)
football (足球)
soccer (英式足球)
softball (垒球)
volleyball (排球)
swimming (游泳)
cheerleading (带领拉拉队)
baseball (棒球)
tennis (网球)
sports (运动)
cute (可爱的)
sex (性)
sexy (性感)
hot (火辣)
kissed (吻)
dance (跳舞)
band (乐队)
marching (游行)
music (音乐)
rock (摇滚)
god (上帝)
church (教堂)
jesus (耶稣)
bible (圣经)
hair (头发)
dress (服装)
blonde (金发女郎)
mall (商业街)
shopping (购物)
clothes (衣服)
hollister (hollister品牌,美国时尚休闲大牌)
abercrombie (abercrombie品牌,美国青少年最青睐的品牌)
die (死亡)
deat (死亡)
drunk (醉酒)
drugs (毒品)
teenager_sns <- read.csv("./input/teenager_sns.csv")
head(teenager_sns, n = 10)
通过观察,发现gender
和age
变量存在缺失值(missing value)。
很多机器学习模型不能直接处理带有缺失值的数据,例如我们将要使用的 K-Means聚类算法。
因此在正式构建模型之前,需要对缺失值进行处理:删除或者以某种方法进行填补。
在对缺失值进行处理之前,我们先分别统计gender
和age
这两个变量存在缺失值的样本数量。
对于gender
变量,我们使用R中的table()
函数来完成这一分析,注意table()
函数默认不对缺失值进行统计,需要将useNA
参数设置成 “ifany”。
对于连续型变量age
,使用summary()
函数。
table(teenager_sns$gender, useNA = "ifany")
summary(teenager_sns$age)
可见,在30000个样本中,有2724个样本(约9%)缺少性别数据,5086个样本(约17%)缺少年龄数据。
进一步观察 age
变量的描述统计信息发现,年龄的最小值为3.086,最大值为106.9。
因为我们的样本是青少年样本,所以该最小值和最大值似乎不可信,因为现实中不太可能会有一个3岁或者106岁的人就读高中。
这种异常数据往往会影响最终的建模分析结果,因此需要进行异常值处理。
高中生的合理年龄区间为13~20岁,因此对于我们的数据集,如果年龄在13~20岁之外,我们将其标记为空值NA
。
使用R中的 ifelse()
函数来完成这一处理:
teenager_sns$age <- ifelse(teenager_sns$age >= 13 & teenager_sns$age < 20, teenager_sns$age, NA)
summary(teenager_sns$age)
现在,对于异常值的处理完毕,但是这样引入了更多的缺失值,下一步我们需要对缺失值进行处理。
对于样本中的缺失值,一个最简单的方法是删除带有缺失值的样本。 然而直接删除缺失值会使我们的数据变少,特别是我们的数据中一共有40个变量,只有两个变量存在缺失值。 缺失值在数据中整体不多,但是如果直接删除会导致我们失去很多的可用数据。
对于gender
这种分类变量,如果缺失值的样本跟其他样本的差别明显,我们可以为gender
变量增加一个单独的分类 "unkown"。
由于K-Means聚类算法需要计算样本之间的距离,因此我们还需要对分类变量进行虚拟编码(也称为OneHot编码)。
虚拟编码将一个有K个取值的分类变量转换成K个二元变量。
我们的gender
变量现在有“M”,“F”和“unkown”三种取值,我们可以将其转换成三个变量:gender_M
,gender_F
和 gender_unkown
。
这三个变量取值为0和1,分别代表某一个高中生是否是某一性别类型。
对于一个样本,在这三个变量下同时只能一个变量取值为1,其他变量取值为0。
teenager_sns$gender_M <- ifelse(teenager_sns$gender == "M" & !is.na(teenager_sns$gender),1,0)
teenager_sns$gender_F <- ifelse(teenager_sns$gender == "F" & !is.na(teenager_sns$gender),1,0)
teenager_sns$gender_unkown <- ifelse(is.na(teenager_sns$gender),1,0)
age_mean <- mean(teenager_sns$age, na.rm = TRUE)
age_mean
现在,我们使用均值对缺失值进行填补:
teenager_sns$age_avg_imputated <- ifelse(is.na(teenager_sns$age), age_mean, teenager_sns$age)
head(teenager_sns , n = 10)
观察上表中的第6行的age
变量和age_avg_imputated
变量, 发现该样本的age
缺失值已经被正确填补为均值17.2523。
因为K-Means聚类算法需要计算样本的距离,在构建模型之前,我们需要进行数据标准化。
常用的标准化方法有 min-max
标准化和 z-score
标准化等。
在本例中,我们直接采用 z-score
标准化方法。
filtered_columns = c("gradyear","friends","basketball",
"football","soccer","softball","volleyball","swimming",
"cheerleading","baseball","tennis","sports","cute","sex",
"sexy","hot","kissed","dance","band","marching","music",
"rock","god","church",
"jesus","bible","hair","dress","blonde","mall","shopping","clothes",
"hollister","abercrombie","die","death","drunk","drugs",
"gender_M","gender_F","gender_unkown","age_avg_imputated")
teenager_sns_zscore <- as.data.frame(lapply(teenager_sns[filtered_columns], scale))
head(teenager_sns_zscore)
set.seed(4)
teenager_clusters <- kmeans(teenager_sns_zscore, centers = 5)
teenager_clusters$size
在我们的聚类的5个类中,最大的类中有11482名青少年,最小的类中有1216名青少年。
需要注意的是,因为K-Means聚类会随机选取初始的聚类中心,因此每次运行的结果可能会不同。
为了更好地理解每一个类所代表的青少年群体的特点,我们观察每一个类的聚类中心(cluster center)。
聚类中心结果保存在 teenager_clusters
的 centers
属性。
centers <- teenager_clusters$centers
centers
因为数据已经使用z-score
方法进行标准化,我们可以直接通过观察聚类中心在每一个变量上的取值情况来分析每一个聚类中心的含义。
如果聚类中心在某一个变量取值大于0,代表该聚类所代表的群体在该变量取值大于群体平均水平。
首先对上述聚类结果数据框进行转置,然后对每一个聚类中心的变量取值从大到小进行排序。
通过观察每个聚类前10个变量来分析聚类所代表的群体:
centers_t <- t(centers)
sort(centers_t[,1],decreasing = TRUE)[1:10]
第一个聚类所代表的青少年群体特点为:喜欢时尚、懂浪漫、爱好音乐、喜酗酒,似乎有些叛逆。
sort(centers_t[,2],decreasing = TRUE)[1:10]
第二个聚类所代表的青少年群体的特点为:男生居多,爱好体育运动。
sort(centers_t[,3],decreasing = TRUE)[1:10]
第三个聚类所代表的青少年群体为宗教群体。
sort(centers_t[,4],decreasing = TRUE)[1:10]
第四个聚类所代表的青少年群体为爱好运动、爱好购物,其中以女生居多。
sort(centers_t[,5],decreasing = TRUE)[1:10]
第五个聚类所代表的青少年群体特点为:高年级,女生居多,喜欢购物和时尚,好友较多。