12.5. 数据分析
随着数据科学的发展,数据分析或者数据挖掘已经越来越受到各种业务的重视,比如商业、生产等领域,各种决策也更多地依靠数据分析的结果,逐渐减少个人经验和“拍脑门”“抖机灵”等在决策中的成分。
如果要分析小量的结构化数据,用类似于电子表格的工具软件就能完成。但是,数据量如果很大(所谓“大数据”,是一个相对的模糊概念),还可能遇到非结构化的数据,再使用类电子表格的工具软件或许不太适合,这时候编程语言就有用武之地了。
下面以一个开网店的案例,说明数据分析对商业决策的支持作用。
张三发现网上购物已经成为了人们的习惯,就打算开个小网店——“梦想还是要有的,万一实现了呢”。他笃信广为流传的“犹太人赚钱法则”:“要想赚钱,就必须为女性服务”——此结论可用数据进行证实,有兴趣的读者不妨尝试。在“家庭会议上”,“大领导”支持了他的理想,还为网店所销售的商品做出了重要指示:专卖文胸。但是,卖什么类型的,什么颜色的,尺码多大的,就需要张三自己来决定了。张三就是一名数据分析师,他深知不能凭直觉来——更不能根据影视作品中看到的做出决策,必须要“依据数据决策”。于是张三根据“家庭会议”精神开始了有条不紊的数据分析工作。
首先,到某电商平台上,利用网络爬虫技术(数据工程师如果会这项技术,如虎添翼),获得了一些文胸的评论数据,准备通过这些数据分析出消费者的消费取向。本节的重点是数据分析,网络爬虫技术留给读者研究。
下面使用 Pandas 开始研究这些数据。Pandas 是数据科学中常用的第三方库,在 12.4.2 节已经安装,更多关于 Pandas 的使用方法,推荐参阅拙作《跟老齐学 Python:数据分析》(电子工业出版社出版)。
代码语言:javascript复制[1]: import pandas as pd
datas = pd.read_csv("./data/bra.csv")
datas.head()
[1]: creationTime productColor productSize
0 2016-06-08 17:17:00 22咖啡色 75C
1 2017-04-07 19:34:25 22咖啡色 80B
2 2016-06-18 19:44:56 02粉色 80C
3 2017-08-03 20:39:18 22咖啡色 80B
4 2016-07-06 14:02:08 22咖啡色 75B
将获取到的数据保存在了 bra.csv
文件中,读取其中的前几条,先对数据有直观认识。接下来要认真地查看特征 'productColor'
中的数据。
[2]: datas['productColor'].unique()
[2]: array(['22咖啡色', '02粉色', '071蓝色', '071黑色', '071肤色', '0993无痕肤色',
'0993无痕黑色', '071红色', '0993无痕酒红色', 'h03无痕蓝灰', '蓝灰色',
# .... (省略部分内容)
'黑色 单件', '蓝色 单件', '浅紫', '紫色套装(其他颜色备注)',
'粉色套装(含内裤)', '虾粉'], dtype=object)
这么多颜色,对于数据分析来说,应该进行“数据清洗”——这是数据科学中最耗费时间和精力的工作(参阅拙作《数据准备和特征工程》,电子工业出版社出版)。并且,对业务越熟悉,数据清洗得就越“干净”,且符合分析所需。此处为了突出“数据分析”,暂将重要的“数据清洗”过程省略,直接显示清洗后的数据。
代码语言:javascript复制[3]: cleaned_datas = pd.read_csv("./data/cleaned_data.csv", index_col=0)
cleaned_datas.head()
[3]: creationTime productColor productSize color
0 2016-06-08 17:17:00 22咖啡色 75C 棕色
1 2017-04-07 19:34:25 22咖啡色 80B 棕色
2 2016-06-18 19:44:56 02粉色 80C 粉色
3 2017-08-03 20:39:18 22咖啡色 80B 棕色
4 2016-07-06 14:02:08 22咖啡色 75B 棕色
所显示的 'color'
列是清洗之后的数据,后续分析所用数据即为此列。
为了知道样本的颜色分布,要绘制柱形图,反映出 color
特征下不同值的样本数量。
绘图的工具 Matplotlib 默认不支持中文(此第三方库已经在 12.4.2 节安装),要先把这个小问题解决了。
代码语言:javascript复制[4]: from matplotlib.font_manager import FontManager
import subprocess
mpl_fonts = set(f.name for f in FontManager().ttflist)
print('all font list get from matplotlib.font_manager:')
for f in sorted(mpl_fonts):
print('t' f)
[4]: all font list get from matplotlib.font_manager:
.Aqua Kana
.Arabic UI Display
.Arabic UI Text
... #(省略部分输出)
Songti SC
... #(省略部分输出)
用代码块 [4] 可以显示出本地计算机系统所支持的字体,可能很多,从中细心地找出中文字体。然后将该字体用于下面的代码块中(本例中使用的是 Songti SC
字体,读者可以根据自己的情况设置)。
[5]: import matplotlib.pyplot as plt
import matplotlib
matplotlib.rc("font",family='Songti SC') # 设置字体
color_count = cleaned_datas.groupby('color').count() # 分组统计
numbers = color_count['productColor']
labels = numbers.index
position = range(len(labels))
plt.bar(x=position, height=numbers.values,
width=0.6, tick_label=labels) # 绘制柱形图
plt.xticks(position, labels)
输出图示:
从输出结果中可以一目了然知道当前数据集中,哪些颜色的样本较少——购买者少,哪些颜色的样本较多——购买者多。
如此,张三就知道网店应该销售什么颜色的文胸了。
接下来,就要解决大小问题。路数与前面类似,先看看原始数据。
代码语言:javascript复制[6]: datas['productSize'].str.upper().unique()
[6]: array(['75C', '80B', '80C', '75B', '70C', '85B', '70B', '85C',
'75C/34C','80B/36B', '85C/38C', '85A/38A', '85B/38B', '80A/36A',
'70A/32A','80C/36C', '75B/34B', '75A/34A', '70B/32B', '70C/32C',
'B80','B75', 'C80', '170/82/XL', 'C75', '160/70/M', 'B70',
'165/76/L','C70', nan, '90C/40C', '90B/40B', '85D/38D',
'85B (内裤)套装','85E/38E', '80D/36D', '90D/40D', '80E/36E',
'75E/34E', '90E/40E','75D/34D', '95C', '95E', '85E (内裤)套装',
'95D', '75B (内裤)套装','75B=34B', '80B=36B', '80C=36C', '90D=40D',
'85B=38B', '80A=36A','85C=38C', '90B=40B', '75A=34A', '90C=40C',
'85A=38A', '75C=34C','85/38C', '75B/34', '85B/38', '80B/36',
'70B/32', 'A75', 'A80', 'A70', '75A', '80A', '70A', '85A',
'70A=32A', '70B=32B', 'A85', 'C85', 'B85', '90C', '40/90A=XL码',
'34/75D=L码', '32/70B=S码', '36/80B=L码', '38/85A=L码',
'38/85C=XL码', '36/80C=L码', '38/85B=XL码', '38/85D=XL码',
'34/75B=M码', '34/75C=M码', '34/75A=S码', '40/90C=XL码',
'36/80A=M码', '75B=34B ', '34/75AB中厚2CM', '75B=34AB',
'80B=36AB', '75B ', '38/85AB中厚2CM', '34/75C薄款0.8CM', '80B ',
'85B=38AB ', '85B=38AB', '70B=32AB', '80A=36A厚杯', '70A=32A厚杯',
'75A=34A厚杯', '75B=34B(粉色预发货17号)', '75B=34B粉色预计4天发',
'75B=34B(粉色预发货20号)', '75B=34B(粉色预发货26号)', '34B/75B',
'34/75B', '40C/90C', '32B/70B', '34A/75A', '36C/80C', '34C/75C',
'36B/80B', '34B=75B', '36A/80A', '32A/70A', '38B/85B',
'38A/85A'], dtype=object)
也很复杂——超出了张三的原有认识。还要继续进行数据清洗,在有关“专家”的指导下,经过如下一番操作(为了简化并好理解,“专家”特别建议将大小进行简化,用 A-E 表示),将数据清洗完毕。
代码语言:javascript复制[7]: size_1 = datas['productSize'].str.upper().str.findall('[a-zA-Z]').str[0]
size_2 = size_1.str.replace('M', 'B')
size_3 = size_2.str.replace('L', 'C')
size_4 = size_3.str.replace('XC', 'C')
size_5 = size_4.str.replace('AB', 'B')
size_6 = size_5.str.replace('X', 'D')
datas['size'] = size_6
datas.head()
[7]: creationTime productColor productSize size
0 2016-06-08 17:17:00 22咖啡色 75C C
1 2017-04-07 19:34:25 22咖啡色 80B B
2 2016-06-18 19:44:56 02粉色 80C C
3 2017-08-03 20:39:18 22咖啡色 80B B
4 2016-07-06 14:02:08 22咖啡色 75B B
新增的 size
列就是清洗的结果,下面对该特征进行分组统计,然后绘制饼图,显示不同尺寸的文胸的分布。
[8]: size_count = datas.groupby('size').count()
labels = ["A", "B", "C", "D", "E"]
fig, ax = plt.subplots()
explode = (0, 0.1, 0, 0, 0)
ax.pie(size_count['productColor'], explode=explode,
labels=labels, autopct="%1.1f%%",
radius=1.2, startangle=0)
ax.set(aspect='equal')
输出图示:
通过此图,也知道应该销售多大尺码的了。
诚然,上述数据对于网店的运营决策还比较单薄,这里仅仅以此为例,说明数据分析的作用。读者如果有兴趣深入研究,不妨参考拙作《跟老齐学 Python:数据分析》的有关内容。
★自学建议 1997年11月,统计学家吴建福提出将统计学重命名为“数据科学”,同时统计学家应称为“数据科学家”。现在一般认为数据科学(data science)综合了多个领域的理论和技术,包括但不限于统计分析、数据挖掘、机器学习等,其目标是从数据中提取出有价值的部分,应用于相关的数据产品之中。 在我的个人网站(www.itdiffer.com)有关于数据科学的学习内容和职业发展的讲座资料,有兴趣的读者可以参考。