天猫双十一美妆销售数据分析
数据为天猫双十一女性美妆的数据集,围绕产品及其销量和评论撰写。数据具有7个特征,可以从多个维度解析文本。数据集中对店名的引用被处理为产品的品牌名以保护店家隐私,所以做了匿名处理数据包括27599行和7个特征变量。每一行对应一个产品的销售情况,包括以下变量:update_time 统计时间id 产品编号title 产品名称price 交易价格sale_count 销量comment_count 评论
项目介绍
数据为天猫双十一女性美妆的数据集,围绕产品及其销量和评论撰写。数据具有7个特征,可以从多个维度解析文本。数据集中对店名的引用被处理为产品的品牌名以保护店家隐私,所以做了匿名处理
数据包括27599行和7个特征变量。每一行对应一个产品的销售情况,包括以下变量:
update_time 统计时间
id 产品编号
title 产品名称
price 交易价格
sale_count 销量
comment_count 评论数量
店名 店铺名称
可参考的探索方向:
购买化妆品的客户的关注度(评论数)是多少?各产品销量分布情况? 哪些产品的卖得最好,哪些牌子最受欢迎,哪些化妆品是大家最需要的? 不同商家之间的差异,及促销打折力度? 模拟定价系统及推荐系统?
关键词
pandas数据处理、matplotlib、数据可视化、数据探索分析
一、读取数据
import pandas as pd
import numpy as np
data = pd.read_csv('双十一淘宝美妆数据.csv')
data.head()
update_time |
id |
title |
price |
sale_count |
comment_count |
店名 |
|
0 |
2016/11/14 |
A18164178225 |
CHANDO/自然堂 雪域精粹纯粹滋润霜50g 补水保湿 滋润水润面霜 |
139.0 |
26719.0 |
2704.0 |
自然堂 |
1 |
2016/11/14 |
A18177105952 |
CHANDO/自然堂凝时鲜颜肌活乳液120ML 淡化细纹补水滋润专柜正品 |
194.0 |
8122.0 |
1492.0 |
自然堂 |
2 |
2016/11/14 |
A18177226992 |
CHANDO/自然堂活泉保湿修护精华水(滋润型135ml 补水控油爽肤水 |
99.0 |
12668.0 |
589.0 |
自然堂 |
3 |
2016/11/14 |
A18178033846 |
CHANDO/自然堂 男士劲爽控油洁面膏 100g 深层清洁 男士洗面奶 |
38.0 |
25805.0 |
4287.0 |
自然堂 |
4 |
2016/11/14 |
A18178045259 |
CHANDO/自然堂雪域精粹纯粹滋润霜(清爽型)50g补水保湿滋润霜 |
139.0 |
5196.0 |
618.0 |
自然堂 |
# 查看各字段信息
data.info()
总结
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 27598 entries, 0 to 27597
Data columns (total 7 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 update_time 27598 non-null object
1 id 27598 non-null object
2 title 27598 non-null object
3 price 27598 non-null float64
4 sale_count 25244 non-null float64
5 comment_count 25244 non-null float64
6 店名 27598 non-null object
dtypes: float64(3), object(4)
memory usage: 1.5+ MB
- 这个数据集包含 27598 条记录,共有 7 列。其中有 3 列数值型数据 和 4 列文本型数据。
sale_count
和comment_count
列存在缺失数据,可能需要填充或删除这些缺失值。
# 分店铺统计
data['店名'].value_counts()
悦诗风吟 3021
佰草集 2265
欧莱雅 1974
雅诗兰黛 1810
倩碧 1704
美加净 1678
欧珀莱 1359
妮维雅 1329
相宜本草 1313
兰蔻 1285
娇兰 1193
自然堂 1190
玉兰油 1135
兰芝 1091
美宝莲 825
资生堂 821
植村秀 750
薇姿 746
雅漾 663
雪花秀 543
SKII 469
蜜丝佛陀 434
Name: 店名, dtype: int64
二、数据清洗
2.1 重复数据处理
# 对重复数据做删除处理
print(data.shape)
data = data.drop_duplicates(inplace=False)
print(data.shape)
(27598, 7)
(27512, 7)
data.drop_duplicates(inplace=False)
:
drop_duplicates()
是 pandas 中用来删除重复行的方法。inplace=False
表示 不在原地修改数据,而是返回一个 新的 DataFrame。如果设置为True
,则会直接在原数据上修改,不返回新的 DataFrame。
# 此处虽然删除了重复值,但索引未变,因此应用以下方法进行重置索引
print(data.index)
data = data.reset_index(drop=True)
print('新索引:',data.index)
Index([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
...
27588, 27589, 27590, 27591, 27592, 27593, 27594, 27595, 27596, 27597],
dtype='int64', length=27512)
新索引: RangeIndex(start=0, stop=27512, step=1)
上面删除了重复行,索引跟着也删了,比如 [0, 1, 3, 4, 6, 7, ...](出现跳跃)。
reset_index()
的作用是 重置索引,让索引从 0
开始重新排列,避免索引不连续的问题。
2.2 缺失值处理
# 查看缺失值
data.isnull().any()
update_time False
id False
title False
price False
sale_count True
comment_count True
店名 False
dtype: bool
有两列数据存在缺失值:sale_count, comment_count
# 查看数据结构
data.describe()
price |
sale_count |
comment_count |
|
count |
27512.000000 |
2.516200e+04 |
25162.000000 |
mean |
363.423512 |
1.231605e+04 |
1121.741197 |
std |
614.876153 |
5.241236e+04 |
5277.781581 |
min |
1.000000 |
0.000000e+00 |
0.000000 |
25% |
99.000000 |
2.780000e+02 |
21.000000 |
50% |
205.000000 |
1.443000e+03 |
153.000000 |
75% |
390.000000 |
6.353000e+03 |
669.000000 |
max |
11100.000000 |
1.923160e+06 |
202930.000000 |
# 查看sale_count列的众数
mode_01 = data.sale_count.mode()
print(mode_01)
# 查看comment_count列的众数
mode_02 = data.comment_count.mode()
print(mode_02)
0 0.0
dtype: float64
0 0.0
dtype: float64
此处两列的众数均为0,且由标签数据含义可知销售量和评论数有可能存在为0的情况,因此使用0来填充缺失值
mode()方法返回数据列中出现频率最高的值(众数)。
# 填充缺失值
data = data.fillna(0)
# 对空值行数求和,验证无剩余缺失值
data.isnull().sum()
update_time 0
id 0
title 0
price 0
sale_count 0
comment_count 0
店名 0
dtype: int64
2.3 提取表格中有用信息并新增为列
# 结巴分词库
import jieba
# jieba.load_userdict('addwords.txt')
title_cut = []
for i in data.title:
j = jieba.lcut(i)
title_cut.append(j)
# 对标题进行分词,新增item_name_cut列
data['item_name_cut'] = title_cut
data[['title','item_name_cut']].head()
|
item_name_cut |
|
0 |
CHANDO/自然堂 雪域精粹纯粹滋润霜50g 补水保湿 滋润水润面霜 |
[CHANDO, /, 自然, 堂, , 雪域, 精粹, 纯粹, 滋润霜, 50g, ,... |
1 |
CHANDO/自然堂凝时鲜颜肌活乳液120ML 淡化细纹补水滋润专柜正品 |
[CHANDO, /, 自然, 堂, 凝, 时鲜, 颜肌活, 乳液, 120ML, , 淡... |
2 |
CHANDO/自然堂活泉保湿修护精华水(滋润型135ml 补水控油爽肤水 |
[CHANDO, /, 自然, 堂, 活泉, 保湿, 修护, 精华, 水, (, 滋润, 型... |
3 |
CHANDO/自然堂 男士劲爽控油洁面膏 100g 深层清洁 男士洗面奶 |
[CHANDO, /, 自然, 堂, , 男士, 劲爽, 控油, 洁面膏, , 100g... |
4 |
CHANDO/自然堂雪域精粹纯粹滋润霜(清爽型)50g补水保湿滋润霜 |
[CHANDO, /, 自然, 堂, 雪域, 精粹, 纯粹, 滋润霜, (, 清爽型, ),... |
j = jieba.lcut(i)
使用 jieba.lcut(i)
对 i
进行分词,并返回一个列表(list)。
data['item_name_cut'] = title_cut
给 data
这个表新增一列 item_name_cut
,存储所有标题的分词结果。
# 给商品添加分类
basic_config_data = """护肤品 套装 套装
护肤品 乳液类 乳液 美白乳 润肤乳 凝乳 柔肤液' 亮肤乳 菁华乳 修护乳
护肤品 眼部护理 眼霜 眼部精华 眼膜
护肤品 面膜类 面膜
护肤品 清洁类 洗面 洁面 清洁 卸妆 洁颜 洗颜 去角质 磨砂
护肤品 化妆水 化妆水 爽肤水 柔肤水 补水露 凝露 柔肤液 精粹水 亮肤水 润肤水 保湿水 菁华水 保湿喷雾 舒缓喷雾
护肤品 面霜类 面霜 日霜 晚霜 柔肤霜 滋润霜 保湿霜 凝霜 日间霜 晚间霜 乳霜 修护霜 亮肤霜 底霜 菁华霜
护肤品 精华类 精华液 精华水 精华露 精华素
护肤品 防晒类 防晒霜 防晒喷雾
化妆品 口红类 唇釉 口红 唇彩
化妆品 底妆类 散粉 蜜粉 粉底液 定妆粉 气垫 粉饼 BB CC 遮瑕 粉霜 粉底膏 粉底霜
化妆品 眼部彩妆 眉粉 染眉膏 眼线 眼影 睫毛膏
化妆品 修容类 鼻影 修容粉 高光 腮红
其他 其他 其他"""
# 将字符串basic_config_data 转为字典 category_config_map
category_config_map = {}
for config_line in basic_config_data.split('\n'):
basic_cateogry_list = config_line.strip().strip('\n').strip(' ').split(' ')
main_category = basic_cateogry_list[0]
sub_category = basic_cateogry_list[1]
unit_category_list = basic_cateogry_list[2:-1]
for unit_category in unit_category_list:
if unit_category and unit_category.strip().strip(' '):
category_config_map[unit_category] = (main_category,sub_category)
category_config_map
{'乳液': ('护肤品', '乳液类'),
'美白乳': ('护肤品', '乳液类'),
'润肤乳': ('护肤品', '乳液类'),
'凝乳': ('护肤品', '乳液类'),
"柔肤液'": ('护肤品', '乳液类'),
'亮肤乳': ('护肤品', '乳液类'),
'菁华乳': ('护肤品', '乳液类'),
'眼霜': ('护肤品', '眼部护理'),
'眼部精华': ('护肤品', '眼部护理'),
'洗面': ('护肤品', '清洁类'),
'洁面': ('护肤品', '清洁类'),
'清洁': ('护肤品', '清洁类'),
'卸妆': ('护肤品', '清洁类'),
'洁颜': ('护肤品', '清洁类'),
'洗颜': ('护肤品', '清洁类'),
'去角质': ('护肤品', '清洁类'),
'化妆水': ('护肤品', '化妆水'),
'爽肤水': ('护肤品', '化妆水'),
'柔肤水': ('护肤品', '化妆水'),
'补水露': ('护肤品', '化妆水'),
'凝露': ('护肤品', '化妆水'),
'柔肤液': ('护肤品', '化妆水'),
'精粹水': ('护肤品', '化妆水'),
'亮肤水': ('护肤品', '化妆水'),
'润肤水': ('护肤品', '化妆水'),
'保湿水': ('护肤品', '化妆水'),
'菁华水': ('护肤品', '化妆水'),
'保湿喷雾': ('护肤品', '化妆水'),
'面霜': ('护肤品', '面霜类'),
'日霜': ('护肤品', '面霜类'),
'晚霜': ('护肤品', '面霜类'),
'柔肤霜': ('护肤品', '面霜类'),
'滋润霜': ('护肤品', '面霜类'),
'保湿霜': ('护肤品', '面霜类'),
'凝霜': ('护肤品', '面霜类'),
'日间霜': ('护肤品', '面霜类'),
'晚间霜': ('护肤品', '面霜类'),
'乳霜': ('护肤品', '面霜类'),
'修护霜': ('护肤品', '面霜类'),
'亮肤霜': ('护肤品', '面霜类'),
'底霜': ('护肤品', '面霜类'),
'精华液': ('护肤品', '精华类'),
'精华水': ('护肤品', '精华类'),
'精华露': ('护肤品', '精华类'),
'防晒霜': ('护肤品', '防晒类'),
'唇釉': ('化妆品', '口红类'),
'口红': ('化妆品', '口红类'),
'散粉': ('化妆品', '底妆类'),
'蜜粉': ('化妆品', '底妆类'),
'粉底液': ('化妆品', '底妆类'),
'定妆粉': ('化妆品', '底妆类'),
' 气垫': ('化妆品', '底妆类'),
'粉饼': ('化妆品', '底妆类'),
'BB': ('化妆品', '底妆类'),
'CC': ('化妆品', '底妆类'),
'遮瑕': ('化妆品', '底妆类'),
'粉霜': ('化妆品', '底妆类'),
'粉底膏': ('化妆品', '底妆类'),
'眉粉': ('化妆品', '眼部彩妆'),
'染眉膏': ('化妆品', '眼部彩妆'),
'眼线': ('化妆品', '眼部彩妆'),
'眼影': ('化妆品', '眼部彩妆'),
'鼻影': ('化妆品', '修容类'),
'修容粉': ('化妆品', '修容类'),
'高光': ('化妆品', '修容类')}
- 第 1 列(
main_category
)是大类,比如护肤品
、化妆品
- 第 2 列(
sub_category
)是子类,比如乳液类
、面霜类
- 后续列(
unit_category_list
)是具体商品类别,比如乳液
、美白乳
、润肤乳
def func1(row):
sub_type = '' #子类别
main_type = '' #主类别
exist = False
# 遍历item_name_cut 里每个词语
for temp in row:
# 如果词语包含在category_config_map里面,打上子类和主类标签
if temp in category_config_map:
sub_type = category_config_map.get(temp)[1]
main_type = category_config_map.get(temp)[0]
exist = True
break
if not exist:
sub_type= '其他'
main_type = '其他'
return [sub_type, main_type]
# 将子类别sub_type新增为一列
data['sub_type'] = data['item_name_cut'].map(lambda r:func1(r)[0])
# 将主类别main-type新增为一列
data['main_type'] = data['item_name_cut'].map(lambda r:func1(r)[1])
data.head()
update_time |
id |
title |
price |
sale_count |
comment_count |
店名 |
item_name_cut |
sub_type |
main_type |
|
0 |
2016/11/14 |
A18164178225 |
CHANDO/自然堂 雪域精粹纯粹滋润霜50g 补水保湿 滋润水润面霜 |
139.0 |
26719.0 |
2704.0 |
自然堂 |
[CHANDO, /, 自然, 堂, , 雪域, 精粹, 纯粹, 滋润霜, 50g, ,... |
面霜类 |
护肤品 |
1 |
2016/11/14 |
A18177105952 |
CHANDO/自然堂凝时鲜颜肌活乳液120ML 淡化细纹补水滋润专柜正品 |
194.0 |
8122.0 |
1492.0 |
自然堂 |
[CHANDO, /, 自然, 堂, 凝, 时鲜, 颜肌活, 乳液, 120ML, , 淡... |
乳液类 |
护肤品 |
2 |
2016/11/14 |
A18177226992 |
CHANDO/自然堂活泉保湿修护精华水(滋润型135ml 补水控油爽肤水 |
99.0 |
12668.0 |
589.0 |
自然堂 |
[CHANDO, /, 自然, 堂, 活泉, 保湿, 修护, 精华, 水, (, 滋润, 型... |
化妆水 |
护肤品 |
3 |
2016/11/14 |
A18178033846 |
CHANDO/自然堂 男士劲爽控油洁面膏 100g 深层清洁 男士洗面奶 |
38.0 |
25805.0 |
4287.0 |
自然堂 |
[CHANDO, /, 自然, 堂, , 男士, 劲爽, 控油, 洁面膏, , 100g... |
清洁类 |
护肤品 |
4 |
2016/11/14 |
A18178045259 |
CHANDO/自然堂雪域精粹纯粹滋润霜(清爽型)50g补水保湿滋润霜 |
139.0 |
5196.0 |
618.0 |
自然堂 |
[CHANDO, /, 自然, 堂, 雪域, 精粹, 纯粹, 滋润霜, (, 清爽型, ),... |
面霜类 |
护肤品 |
# 将“是否男士专用”新增为一列
gender = []
for i in range(len(data)):
if '男' in data.item_name_cut[i]:
gender.append('是')
elif '男士' in data.item_name_cut[i]:
gender.append('是')
elif '男生' in data.item_name_cut[i]:
gender.append('是')
else:
gender.append('否')
# 将“是否男士专用”新增为一列
data['是否男士专用'] = gender
data.head()
update_time |
id |
title |
price |
sale_count |
comment_count |
店名 |
item_name_cut |
是否男士专用 |
|
0 |
2016/11/14 |
A18164178225 |
CHANDO/自然堂 雪域精粹纯粹滋润霜50g 补水保湿 滋润水润面霜 |
139.0 |
26719.0 |
2704.0 |
自然堂 |
[CHANDO, /, 自然, 堂, , 雪域, 精粹, 纯粹, 滋润霜, 50g, ,... |
否 |
1 |
2016/11/14 |
A18177105952 |
CHANDO/自然堂凝时鲜颜肌活乳液120ML 淡化细纹补水滋润专柜正品 |
194.0 |
8122.0 |
1492.0 |
自然堂 |
[CHANDO, /, 自然, 堂, 凝, 时鲜, 颜肌活, 乳液, 120ML, , 淡... |
否 |
2 |
2016/11/14 |
A18177226992 |
CHANDO/自然堂活泉保湿修护精华水(滋润型135ml 补水控油爽肤水 |
99.0 |
12668.0 |
589.0 |
自然堂 |
[CHANDO, /, 自然, 堂, 活泉, 保湿, 修护, 精华, 水, (, 滋润, 型... |
否 |
3 |
2016/11/14 |
A18178033846 |
CHANDO/自然堂 男士劲爽控油洁面膏 100g 深层清洁 男士洗面奶 |
38.0 |
25805.0 |
4287.0 |
自然堂 |
[CHANDO, /, 自然, 堂, , 男士, 劲爽, 控油, 洁面膏, , 100g... |
是 |
4 |
2016/11/14 |
A18178045259 |
CHANDO/自然堂雪域精粹纯粹滋润霜(清爽型)50g补水保湿滋润霜 |
139.0 |
5196.0 |
618.0 |
自然堂 |
[CHANDO, /, 自然, 堂, 雪域, 精粹, 纯粹, 滋润霜, (, 清爽型, ),... |
否 |
# 新增销售额、购买日期(天)为一列
# 销售额=销售量*价格
data['销售额'] = data.sale_count*data.price
# 新增购买日期为一列
# 转换时间格式
data['update_time'] = pd.to_datetime(data['update_time'])
data[['update_time']].head()
update_time |
|
0 |
2016-11-14 |
1 |
2016-11-14 |
2 |
2016-11-14 |
3 |
2016-11-14 |
4 |
2016-11-14 |
# 将时间设置为新的index
data = data.set_index('update_time')
# 新增时间“天”为一列
data['day'] = data.index.day #由于 update_time 现在是索引,直接用 .index.day 提取日期的“日”部分。
# 删除中文分词的一列
del data['item_name_cut'] #存储的是商品标题的分词结果,后续不再需要了,所以用 del 删除,节省内存
# 查看最终数据表格
data.head()
update_time |
id |
title |
price |
sale_count |
comment_count |
店名 |
是否男士专用 |
销售额 |
day |
2016-11-14 |
A18164178225 |
CHANDO/自然堂 雪域精粹纯粹滋润霜50g 补水保湿 滋润水润面霜 |
139.0 |
26719.0 |
2704.0 |
自然堂 |
否 |
3713941.0 |
14 |
2016-11-14 |
A18177105952 |
CHANDO/自然堂凝时鲜颜肌活乳液120ML 淡化细纹补水滋润专柜正品 |
194.0 |
8122.0 |
1492.0 |
自然堂 |
否 |
1575668.0 |
14 |
2016-11-14 |
A18177226992 |
CHANDO/自然堂活泉保湿修护精华水(滋润型135ml 补水控油爽肤水 |
99.0 |
12668.0 |
589.0 |
自然堂 |
否 |
1254132.0 |
14 |
2016-11-14 |
A18178033846 |
CHANDO/自然堂 男士劲爽控油洁面膏 100g 深层清洁 男士洗面奶 |
38.0 |
25805.0 |
4287.0 |
自然堂 |
是 |
980590.0 |
14 |
2016-11-14 |
A18178045259 |
CHANDO/自然堂雪域精粹纯粹滋润霜(清爽型)50g补水保湿滋润霜 |
139.0 |
5196.0 |
618.0 |
自然堂 |
否 |
722244.0 |
14 |
# 保存清理好的数据为Excel格式
data.to_excel('./clean_beautymakeup.xlsx',sheet_name='clean_data')
三、数据探索
3.1 各品牌SKU数
import matplotlib.pyplot as plt #导入 matplotlib 进行数据可视化。
import seaborn as sns
%matplotlib inline # 只在 Jupyter Notebook 里有效
data.columns # 查看 DataFrame 的所有列名
Index(['id', 'title', 'price', 'sale_count', 'comment_count', '店名', '是否男士专用',
'销售额', 'day'],
dtype='object')
#rcParams是Matplotlib 的全局配置字典
plt.rcParams['font.sans-serif']=['SimHei'] #指定默认字体
plt.rcParams['axes.unicode_minus']=False #解决负号'-'显示为方块的问题,Matplotlib 默认不支持中文和负号一起显示,所以需要这行代码。
plt.figure(figsize=(12,7))
# 计算各店铺的商品数量
data['店名'].value_counts().sort_values(ascending=False).plot.bar(width=0.8,alpha=0.6,color='b')
plt.title('各品牌SKU数',fontsize=18) #给图表加标题
plt.ylabel('商品数量',fontsize=14) #给 Y 轴(纵轴)加标签
plt.show()
悦诗风吟的商品数量最多,其次为佰草集、欧莱雅
3.2 品牌总销量和总销售额
fig,axes = plt.subplots(1,2,figsize=(12,10))
#创建 1 行 2 列 的子图(即两个并排的图表)
#axes 是一个包含两个子图 ax1 和 ax2 的 数组
ax1 = data.groupby('店名').sale_count.sum().sort_values(ascending=True).plot(kind='barh',ax=axes[0],width=0.6)
ax1.set_title('品牌总销售量',fontsize=12)
ax1.set_xlabel('总销售量')
ax2 = data.groupby('店名')['销售额'].sum().sort_values(ascending=True).plot(kind='barh',ax=axes[1],width=0.6)
ax2.set_title('品牌总销售额',fontsize=12)
ax2.set_xlabel('总销售额')
plt.subplots_adjust(wspace=0.4)
plt.show()
相宜本草的销售量和销售额都是最高的。销量第二至第五,分别为美宝莲、悦诗风吟、妮维雅、欧莱雅;销售额第二至第五,分别为欧莱雅、佰草集、美宝莲、悦诗风吟。 宝莲、悦诗风吟、欧莱雅都在销量、销售额前五中。
plt.subplots(1,2)
:创建 两个子图groupby('店名').sum()
:按品牌计算 总销售量/销售额.plot(kind='barh', ax=axes[i])
:绘制 水平条形图plt.subplots_adjust(wspace=0.4)
:调整子图间距
3.3 各类别的销售量、销售额情况
fig,axes = plt.subplots(1,2,figsize=(18,12))
data1 = data.groupby('main_type')['sale_count'].sum()
ax1 = data1.plot(kind='pie',ax=axes[0],autopct='%.1f%%', # 设置百分比的格式,这里保留一位小数
pctdistance=0.8, # 设置百分比标签与圆心的距离
labels= data1.index,
labeldistance = 1.05, # 设置标签与圆心的距离
startangle = 60, # 设置饼图的初始角度
radius = 1.2, # 设置饼图的半径
counterclock = False, # 是否逆时针,这里设置为顺时针方向
wedgeprops = {'linewidth': 1.2, },# 设置饼图内外边界的属性值
textprops = {'fontsize':16, 'color':'k','rotation':80}, # 设置文本标签的属性值
)
ax1.set_title('主类别销售量占比',fontsize=20)
data2 = data.groupby('sub_type')['sale_count'].sum()
ax2 = data2.plot(kind='pie',ax=axes[1],autopct='%.1f%%',
pctdistance=0.8,
labels= data2.index,
labeldistance = 1.05,
startangle = 230,
radius = 1.2,
counterclock = False,
wedgeprops = {'linewidth': 1.2, },
textprops = {'fontsize':16, 'color':'k','rotation':80},
)
ax2.set_title('子类别销售量占比',fontsize=20)
# 设置坐标标签
ax1.set_xlabel(..., fontsize=16,labelpad=38.5)
ax1.set_ylabel(..., fontsize=16,labelpad=38.5)
ax2.set_xlabel(..., fontsize=16,labelpad=38.5)
ax2.set_ylabel(..., fontsize=16,labelpad=38.5)
plt.subplots_adjust(wspace=0.4)
plt.show()
从主类别销售量占比情况来看,护肤品的销量远大于化妆品;
从子类别销售量占比情况来看,底妆类、口红类在化妆品中销量最多,清洁类、化妆水、面霜类在护肤品中销量最多。
plt.figure(figsize=(18,8))
sns.barplot(x='店名',y='sale_count',hue='main_type',data=data,saturation=0.75,ci=0)# 分组依据:主类别(用颜色区分)
plt.title('各品牌各总类的总销量', fontsize=20)
plt.ylabel('销量',fontsize=16)
plt.xlabel('店名',fontsize=16)
plt.text(0,78000,'注:此处也可使用堆叠图,对比效果更直观',
verticalalignment='top', horizontalalignment='left',color='gray', fontsize=10)
# 设置刻度字体大小
plt.xticks(fontsize=16,rotation=45)
plt.yticks(fontsize=16)
plt.show()
各品牌的化妆品、护肤品销量、销售情况均不一样,这与品牌的定位有关, 有的品牌主打化妆品,化妆品会表现好很多,如蜜丝佛陀等。主打护肤品的品牌,护肤品的销量销售额会表现好很多,如欧莱雅、佰草集等。 有的品牌如美宝莲、兰蔻、悦诗风吟,化妆品和护肤品的销售、销售额都还不错。
plt.figure(figsize=(18,8))
sns.barplot( x = '店名',
y = '销售额',hue = 'main_type',data =data,saturation = 0.75,ci=0,)
plt.ylabel('销售额',fontsize=16)
plt.xlabel('店名',fontsize=16)
plt.title('各品牌各总类的总销售额',fontsize=20)
# 设置刻度字体大小
plt.xticks(fontsize=16,rotation=45)
plt.yticks(fontsize=16)
plt.show()
plt.figure(figsize = (16,6))
sns.barplot( x = '店名',
y = 'sale_count',hue = 'sub_type',data =data,saturation = 0.75,ci=0)
plt.title('各品牌各子类的总销量')
plt.ylabel('销量')
plt.show()
3.4 各品牌热度
plt.figure(figsize = (12,6))
data.groupby('店名').comment_count.mean().sort_values(ascending=False).plot(kind='bar',width=0.8)
plt.title('各品牌商品的平均评论数')
plt.ylabel('评论数')
plt.show()
plt.figure(figsize=(18,12))
# 获取数据(已经是Series/数组)
x = data.groupby('店名')['sale_count'].mean().values
y = data.groupby('店名')['comment_count'].mean().values
s = data.groupby('店名')['price'].mean().values
txt = data.groupby('店名').id.count().index
# 绘图(直接传递数组)
sns.scatterplot(x=x, y=y, size=s, hue=s, sizes=(100,1500))
# 添加标签
for i in range(len(txt)):
plt.annotate(txt[i], xy=(x[i], y[i]))
plt.ylabel('热度')
plt.xlabel('销量')
plt.legend(loc='upper left')
plt.show()
由上图所示:
越靠上的品牌热度越高,越靠右的品牌销量越高,颜色越深圈越大价格越高
热度与销量呈现一定的正相关; 美宝莲热度第一,销量第二,妮维雅热度第二,销量第四,两者价格均相对较低; 价格低的品牌热度和销量相对较高,价格高的品牌热度和销量相对较低,说明价格在热度和销量中有一定影响;
3.5 各品牌价格
#查看价格的箱型图
plt.figure(figsize=(18,10))
sns.boxplot(x='店名',y='price',data=data)
plt.ylim(0,3000)#如果不限制,就不容易看清箱型,所以把Y轴刻度缩小为0-3000
plt.show()
图中显示了不同类别的数据分布情况,通过比较中位数、四分位距和异常值,可以看出各类别之间的差异。
某些类别的数据分布较广且中心趋势较高,而另一些则较为集中且较低。
异常值的存在可能需要进一步调查,以确定是否为数据错误或特殊原因导致。
data.groupby('店名').price.sum()
avg_price=data.groupby('店名').price.sum()/data.groupby('店名').price.count()
avg_price
店名 AVG
SKII 1011.727079
佰草集 289.823171
倩碧 346.092190
兰芝 356.615809
兰蔻 756.400778
妮维雅 73.789053
娇兰 1361.043588
悦诗风吟 121.245945
植村秀 311.786667
欧珀莱 276.218543
欧莱雅 167.282698
玉兰油 329.657294
相宜本草 122.958446
美加净 44.694619
美宝莲 148.757576
自然堂 180.130213
薇姿 281.085791
蜜丝佛陀 142.118894
资生堂 577.438490
雅漾 212.618401
雅诗兰黛 872.470718
雪花秀 901.082873
Name: price, dtype: float64
fig = plt.figure(figsize=(12,6))
avg_price.sort_values(ascending=False).plot(kind='bar',width=0.8,alpha=0.6,color='b',label='各品牌平均价格')
y = data['price'].mean()
plt.axhline(y,0,5,color='r',label='全品牌平均价格') #添加了一条水平线,表示所有品牌的平均价格
plt.ylabel('各品牌平均价格')
plt.title('各品牌产品的平均价格',fontsize=24)
plt.legend(loc='best')
plt.show()
娇兰、SKII、雪花秀、雅诗兰黛、兰蔻、资生堂这几个国际大牌的产品价格很高,产品平均价格都在500以上,都是一线大牌;
兰芝、倩碧、玉兰油、植村秀、佰草集、薇姿、雅漾的平均价格在300-400元左右,其中佰草集是最贵的国货品牌;
美加净作为国货品牌,性价比高,平均价格最低,妮维雅的平均价格第二低,在100元左右;
全品牌平均价格低于400元,除了前五个国际大牌其余品牌的平均价格都低于全品牌平均价格
plt.figure(figsize=(18,10))
# 准备数据(确保使用.values转换为数组)
x = data.groupby('店名')['sale_count'].mean().values # 平均销量
y = data.groupby('店名')['销售额'].mean().values # 平均销售额
s = avg_price.values if hasattr(avg_price, 'values') else avg_price # 平均价格(确保是数组)
txt = data.groupby('店名').id.count().index # 店铺名称
# 绘制散点图(统一用数组传参)
sns.scatterplot(
x=x,
y=y,
size=s,
sizes=(100,1500),
marker='v',
alpha=0.5,
color='b' # 所有点用蓝色,若需按颜色分类改用hue参数
)
# 添加标签
for i in range(len(txt)):
plt.annotate(
txt[i],
xy=(x[i], y[i]),
xytext=(x[i]+0.2, y[i]+0.2) # 标签位置微调
)
plt.ylabel('销售额')
plt.xlabel('销量')
plt.legend(loc='upper left')
plt.show()
由上图所示,越靠上代表销售额越高,越靠左代表销量越高,图形越大代表平均价格越高
销售量和销售额呈现正相关;
相宜本草、美宝莲、蜜丝佛陀销量和销售额位居前三,且平均价格居中;
说明销量销售额与价格有很重要的联系;
3.6 男性护肤品销量情况
gender_data=data[data['是否男士专用']=='是']
gender_data_1=gender_data[(gender_data.main_type =='护肤品')| (gender_data.main_type=='化妆品')]
plt.figure(figsize = (12,6))
sns.barplot(x='店名',y='sale_count',hue='main_type',data =gender_data_1,saturation=0.75,ci=0,)
plt.show()
f,[ax1,ax2]=plt.subplots(1,2,figsize=(12,6))
gender_data.groupby('店名').sale_count.sum().sort_values(ascending=True).plot(kind='barh',width=0.8,ax=ax1)
ax1.set_title('男士护肤品销量排名')
gender_data.groupby('店名').销售额.sum().sort_values(ascending=True).plot(kind='barh',width=0.8,ax=ax2)
ax2.set_title('男士护肤品销售额排名')
plt.subplots_adjust(wspace=0.4)
plt.show()
男士购买的大多是护肤品;
妮维雅是男生护肤品中销量遥遥领先的品牌,第二第三分别为欧莱雅、相宜本草
3.7 分析时间与销量的关系,体现购买高峰期
from matplotlib.pyplot import MultipleLocator
plt.figure(figsize = (12,6))
day_sale=data.groupby('day')['sale_count'].sum()
day_sale.plot()
plt.grid(linestyle="-.",color="gray",axis="x",alpha=0.5)
x_major_locator=MultipleLocator(1) #把x轴的刻度间隔设置为1,并存在变量里
ax=plt.gca() #ax为两条坐标轴的实例
ax.xaxis.set_major_locator(x_major_locator)
#把x轴的主刻度设置为1的倍数
plt.xlabel('日期(11月)',fontsize=12)
plt.ylabel('销量',fontsize=12)
plt.show()
总结
1. 品牌SKU数量分析
● 悦诗风吟 的SKU数量最多,表明其产品线丰富,能够满足多样化的消费者需求,覆盖更广泛的市场细分。
2. 总销售量和销售额表现
● 相宜本草 和 欧莱雅 在总销售量和销售额上表现最为突出,显示出这两个品牌在市场中具有较强的竞争力和消费者认可度。
3. 主类别销售量占比
● 护肤品 类别的销量占比最高,其中 清洁类 和 化妆水类 产品最受欢迎,反映了消费者对基础护肤需求的高频次和高关注度。
4. 各品牌平均评论数
● 美宝莲 的平均评论数位居榜首,可能得益于其高性价比的产品定位或高效的营销策略,吸引了大量用户反馈。
5. 各品牌平均价格对比
● 娇兰 和 SKII 的平均价格最高,体现了其高端市场定位;而 美加净 的平均价格最低,可能更适合预算有限的消费者群体。
6. 销量与销售额的关系
● 销量和销售额呈现显著的正相关关系,但产品价格仍是影响消费者购买决策的关键因素之一。
美妆类别中护肤品销量远大于化妆品,其中清洁类、化妆水、面霜等基础护肤类销量最高;
男士购买美妆集中在护肤品类,其中妮维雅品牌是最受男士喜爱的品牌;
价格和热度对销售量有关联,平价基础产品是大多数消费者的选择;
由于商家在双十一提前预热,巨大的优惠力度和为了避免网络高峰,不少消费者选择提前消费,销量高峰出现在双十一前几天;双十一后3天商家持续打折优惠,消费者还保有购物余热,但远不如双十一之前。
建议
一、库存管理优化
重点品牌:悦诗风吟(SKU数量领先)
建议措施:
• 建立智能库存预警系统,实现库存周转实时监控
• 实施ABC分类管理法,差异化制定补货策略
• 针对畅销SKU设置安全库存,滞销品及时清仓
二、价格策略优化
高端品牌:娇兰、SK-II(高单价定位)
战略调整:
• 推出轻奢系列产品线,降低消费门槛
• 设计会员专属礼盒,提升复购率
• 开发节日限定套装,增强礼品属性
三、促销策略升级
关键时机:大促高峰期
执行方案:
• 建立72小时倒计时营销机制
• 设置阶梯式满减优惠(满300减50等)
• 针对高价值客户推送专属优惠
四、客户体验提升
标杆品牌:美宝莲(评论互动活跃)
改进方向:
• 建立月度消费者满意度追踪体系
• 重点优化差评集中的产品功能
• 开展新品试用官招募计划
五、市场细分运营
核心品类:
• 护肤品(清洁类、化妆水类)
• 化妆品(彩妆系列)
定制策略:
• 分肤质开发专属产品组合
• 打造场景化使用方案(晨间/夜间)
• 加强达人种草内容投放
六、产品创新规划
潜力品类:新兴细分市场产品
开发重点:
• 每季度开展竞品分析
• 建立产品创新实验室
• 实施"爆品孵化"计划
消费者对产品价格和热度关注度较高,品牌可以适当调整产品价格并通过诸如网络社交平台的方式提高品牌热度;
对于男性消费者,品牌可以定向推荐平价基础护肤产品,在销量中可以看到也有一部分男性购买化妆品,品牌可以在护肤品中适当捆绑化妆品产品带动消费;
消费者购买欲望并不集中在双十一当天,商家可以提前预热加大优惠力度刺激消费者提前消费,避免网络高峰。
更多推荐
所有评论(0)