虽然这些步骤更多是写给业余分析师的指引,但它们同样是数据科学家,甚至更严格的商业分析和学术分析的基础。每一位数据科学家都理解这些步骤的重要意义,会在实践过程中严格遵守它们。
5个步骤概览
数据科学的5个必备步骤分别是:
(1)提出有意思的问题;
(2)获取数据;
(3)探索数据;
(4)数据建模;
(5)可视化和分享结果。
首先,我们从宏观上了解以上5个步骤。
1.1.1 提出有意思的问题
这是我最喜欢的一步。作为一个创业者,我经常问自己(和他人)很多有意思的问题。我像对待头脑风暴会议一样对待这一步。现在开始写下问题,不要关心回答这些问题所需的数据是否存在。这样做的原因有两个。
第一,你不会希望在没有找到数据之前,就被自己的偏见影响。第二,获取数据可能涉及公开渠道和私有渠道,因此不会轻松和显而易见。
你可能想到一个问题,然后自言自语说:“我打赌没有这样的数据可以帮到我们!”然后就将它从问题列表中删除。千万不要这样做,把它留在你的问题列表中!
1.1.2 获取数据
一旦你确定了需要关注的问题,接下来就需要全力收集回答上述问题所需要的数据。正如之前所说,数据可能来自多个数据源,所以这一步非常具有挑战性。
1.1.3 探索数据
一旦得到数据,我们将使用第2章学习的知识,将数据归类到不同的数据类型。这是数据科学5个步骤中最关键的一步。当这一步骤完成时,分析师通常已经花费了数小时学习相关的领域知识,利用代码或其他工具处理和探索数据,对数据蕴含的价值有了更好的认识。
1.1.4 数据建模
这一步涉及统计学和机器学习模型的应用。我们不仅仅选择模型,还通过在模型中植入数学指标,对模型效果进行评价。
1.1.5 可视化和分享结果
毫无疑问,可视化和分享结果是最重要的一步。分析结果也许看起来非常明显和简单,但将其总结为他人易于理解的形式比看起来困难得多。我们将通过一些案例,演示糟糕的分享和改善后的效果。
本文将重点关注第(3)、(4)、(5)步。
为什么本书跳过了第(1)、(2)步?
虽然前两步对数据科学整个过程是非常必要的,但它们通常先于统计模型和程序处理。本书的后面章节将介绍不同的数据收集方法,在此之前,我们更加关注数据科学过程中“科学”的部分。所以,我们先从探索数据开始。
探索数据
数据探索的过程并不简单。它涉及识别数据类型、转换数据类型、使用代码系统性提高数据质量为模型做准备的能力。为了更好地演示和讲解数据探索的艺术,我将使用Python的Pandas包,对几个不同的数据集进行探索。在此过程中,我们将看到多种数据处理技巧。
当我们接触新数据集时,有5个基本问题需要回答。请牢记,这些问题并不是数据科学的起点和终点,它们是我们面对新数据集时需要遵循的基本原则。
1.2.1 数据探索的基本问题
每当接触新数据集时,不论你是否熟悉它,在初次进行分析前回答以下问题都非常有必要。
● 数据是有组织格式的,还是无组织格式的?
我们需要确认数据是否是行列结构。大部分情况下,我们处理的数据都是结构化数据。本书中,超过90%的例子都是结构化数据。尽管如此,在我们进行更深入的数据分析之前,还是要弄清楚这个最基本的问题。
根据经验,如果数据是无组织格式的,我们需要将其转换为有组织的行列结构。在本书前面的例子中,我们通过对文本中词语计数的方式将其转换为行列结构。
● 每一行代表什么?
一旦我们弄清楚了数据的组织形式,得到了行列结构的数据集,接下来就需要弄清楚每一行代表的意思。这一步通常不需要花费多少时间,却大有裨益。
● 每一列代表什么?
我们需要识别每一列的数据层次、定性/定量属性等。分类结果可能随着分析的不断深入而改变,但越早开始这一步越好。
● 是否有缺失值?
数据并不完美。很多时候,人工或机械的错误将导致数据缺失。当这种错误发生时,作为数据科学家,我们需要决定如何处理这些错误。
● 是否需要对某些列进行数据转换?
我们可能需要对某些列进行数据转换,当然,这取决于该列的数据层次和定性/定量属性。比如,为了使用统计模型和机器学习模型,数据集中的每一列都需要是数值型的。我们可以使用Python对数据集进行转换。
自始至终,我们的核心问题是:我们能从前期的推理统计中得到哪些信息?我们希望对数据的理解比初次接触时更深。
好了,我们已经介绍了很多内容,下面看一些具体的例子。
1.2.2 数据集1:Yelp点评数据
我们使用的第1个数据集来自点评网站Yelp的公开数据,数据集中所有的身份识别信息已经被删除。首先读取数据,如下所示。
import pandas as pd
yelp_raw_data = pd.read_csv("yelp.csv")
yelp_raw_data.head()
上述代码的作用是:
● 导入Pandas包,并缩写为pd。
● 读取文件yelp.csv,并命名为yelp_raw_data。
● 查看数据的表头(仅前几行),如图3.1所示。
图3.1 数据的表头
问题1:数据是有组织格式的,还是无组织格式的?
● 数据源是非常好的行列结构,我们可以认为它是有组织格式的。
问题2:每一行代表什么?
● 很明显,每一行代表一条用户的评价。我们还会查看每一行和每一列的数据类型。我们使用DataFrame的shape方法查看数据集的大小,如下所示。
yelp_raw_data.shape
# (10000, 10)
● 结果显示,数据集有10 000行和10列。换言之,数据集有10 000个观测值和10个观测特征。
问题3:每一列代表什么?
请注意,数据集有10列。
● business_id:本列看起来是每条评价对应的交易的唯一识别码。本列是定类尺度,因为识别码没有天然的顺序。
● date:本列是每条评价的提交日期。请注意,它只精确到了年、月和日。虽然时间通常被认为是连续数据,但本列应该被视为离散数据。本列属于定序尺度,因为日期有天然的顺序。
● review_id: 本列看起来是每条评价的唯一识别码。本列同样属于定类尺度,因为识别码没有天然的顺序。
● stars:本列看起来(别担心,我们随后会对它进行深入的分析)是评价者给每一个餐馆的最终评分。本列是有次序的定性数据,因此属于定序尺度。
● text:本列看起来是用户撰写的评价。对于大部分文本数据,我们将其归为定类尺度。
● type:本列前5行均为“review”,我们猜测它是标记每行是否为“review”的列,也就是说很可能存在不是“review”的行。我们随后将进行更深入的分析。本列属于定类尺度。
● user_id:本列是每个提交评价的用户的唯一识别码。和其他唯一识别码一样,本列也属于定类尺度。
问题4:是否有缺失值?
● 使用isnull方法判断是否有缺失值。比如,对于名为awesome_dataframe的DataFrame数据集,使用Python代码awesome_dataframe.isnull().sum()可显示每一列的缺失值总数。
问题5:是否需要对某些列进行数据转换?
● 我们想知道是否需要改变定量数据的数值范围,或者是否需要为定性数据创建哑变量?由于本数据集只有定性数据,所以我们将焦点放在定序和定类范围。
在进行数据探索之前,我们先对Python数据分析包Pandas的术语做一个简单了解。
DataFrame
当我们读取数据集时,Pandas将创建一个名为DataFrame类型的对象。你可以将它想象成Python版本的电子表格(但是更好用)。
在本例中,变量yelp_raw_data就是一个DataFrame。
我们使用以下代码验证以上说法。
type(yelp_raw_data)
# pandas.core.frame.Dataframe
DataFrame本质上是一种二维结构,它和电子表格一样以行列结构存储数据。但是相对于电子表格,DataFrame最重要的优点是它可以处理的数据量远超大多数电子表格。
如果你熟悉R语言,可能认识DataFrame这个词,因为Python中的DataFrame正是从R语言借过来的!
由于我们处理的大部分数据都是有组织数据,所以DataFrame是Pandas中使用频率仅次于Series的对象。
Series
Series是简化版的DataFrame,它只有一个维度。Series本质上是由数据点组成的列表。DataFrame的每一列都可以被看作一个Series对象。下面用代码进行验证。我们首先从DataFrame中抽取单独一列(通常用中括号),代码如下:
yelp_raw_data['business_id']# grab a single column of the Dataframe
我们列出其中几行。
0 9yKzy9PApeiPPOUJEtnvkg
1 ZRJwVLyzEJq1VAihDhYiow
2 6oRAC4uyJCsJl1X0WZpVSA
3 _1QQZuf4zZOyFCvXc0o6Vg
4 6ozycU1RpktNG2-1BroVtw
5 -yxfBYGB6SEqszmxJxd97A
6 zp713qNhx8d9KCJJnrw1xA
接下来使用type函数检查该列是否是Series类型。
type(yelp_raw_data['business_id'])
# pandas.core.series.Series
定性数据的探索技巧
下面我们使用以上两个Pandas数据类型开始数据探索!对于定性数据,我们主要关注定类尺度和定序尺度。
定类尺度
对于定类尺度列,列名描述了该列的含义,数据类型是定性数据。在Yelp数据集中,定类尺度列有business_id、review_id、text、type和user_id。我们使用Pandas进行更深入的分析,如下所示:
yelp_raw_data['business_id'].describe()
# count 10000
# unique 4174
# top JokKtdXU7zXHcr20Lrk29A
# freq 37
describe函数用于输出指定列的快速统计信息。请注意,Pandas自动识别出business_id列为定性数据,所以给出的快速统计是有意义的。实际上,当describe函数作用于定性数据时,我们将得到以下4个统计信息。
● count:该列含有多少个值。
● unique:该列含有多少个非重复值。
● top:该列出现次数最多的值。
● freq:该列出现次数最多的值的次数。
对于定类尺度数据,我们通常观察以下几个特征,以决定是否需要进行数据转换。
● 非重复项的个数是否合理(通常小于20个)?
● 该列是自由文本吗?
● 该列所有的行都不重复吗?
我们已经知道business_id列有10 000个值,但千万别被骗了!这并不意味着真的有10 000条交易评价,它仅仅意味着business_id列被填充了10 000次。
统计指标unique显示数据集有4 174个不重复的餐馆,其中被评价次数最多的餐馆是JokKtdXU7zXHcr20Lrk29A,总评价次数是37次。
yelp_raw_data['review_id'].describe()
# count 10000
# unique 10000
# tope Ta5KD-LTgQv6UT1Zmijmw
# freq 1
count和unique值均为10 000。请你思考几秒,这个结果合理吗?请结合每一行和每一列代表的意思。(插入《Jeopardy》的主题曲。)
当然是合理的!因为该列是每条评价的唯一识别码,每一行代表独立的、不重复的点评,所以review_id列含有10 000个不重复值是合理的。
但为什么eTa5KD-LTgQv6UT1 Zmijmw是出现次数最多的值呢?它只是从10 000个值中随机选择的结果。
yelp_raw_data['text'].describe()
count 10000
unique 9998
top This review is for the chain in general.
freq 2
text列有点意思,它是用户撰写的评价。理论上,我们认为它和review_id列一样是不重复的文本,因为如果两个不同的人撰写的评价完全一致会非常诡异。
但是,数据集中恰恰有两条评价完全一样!下面让我们花点时间学习一下DataFrame的数据筛选功能,然后再研究这一奇怪现象。
Pandas中的筛选
我们先从筛选的机制说起。在Pandas中,基于特定条件对行进行筛选非常简单。对于DataFrame对象,如果想依据某些筛选条件对行进行过滤,只需一行一行检查该行是否满足特定条件即可,同时Pandas将判断结果(真或假)存在一个Series对象中。
真和假的判断依据如下。
● 真:该行满足条件;
● 假:该行不满足条件。
所以,我们首先需要设定一个条件。下面从数据集中提取出现两次的文本:
duplicate_text = yelp_raw_data['text'].describe()['top']
以下是重复的文本:
"This review is for the chain in general.
The location we went to isnew so it isn't in Yelp yet.
Once it is I will put this review thereas well……."
我们马上发现这可能是同一个人给隶属于同一家连锁餐馆的两家店撰写的两条完全相同的评价。但是,在没有进一步证据之前,这仅仅是猜测。
我们已经找出了重复文本,下面来创建判断真或假的Series对象。
text_is_the_duplicate = yelp_raw_data['text'] == duplicate_text
上面的代码将数据集中的text列和重复文本duplicate_text进行比较。这看起来有点不可思议,因为将含有10 000个元素的列表和1条文本做比较,对比结果应该是假,不是吗?
事实上,这是Series对象一个非常有意思的功能。当我们将Series对象和另一个对象做比较时,相当于将Series中每个元素和该对象做比较,返回的结果是一个和Series对象长度相同的新Series对象。非常便捷!
type(text_is_the_duplicate) # it is a Series of Trues and Falses
text_is_the_duplicate.head() # shows a few Falses out of the Series
在Python中,我们可以像对1和0一样,对真和假进行相加或相减。比如,真+假-真+假+真==1。所以,我们可以通过将Series对象的值相加来验证其是否正确。由于只有两行文本重复,所以Series对象合计值应为2,如下所示:
sum(text_is_the_duplicate) # == 2
现在,我们已经有了布尔型Series对象,我们可以用括号将它传入DataFrame数据集中,得到筛选后的结果,如图3.2所示。
filtered_dataframe = yelp_raw_data[text_is_the_duplicate]
# the filtered Dataframe
filtered_dataframe
图3.2 筛选后的结果
看起来我们之前的猜测是对的:某人在同一天,给同一连锁品牌的两家餐馆,撰写了相同的评语。我们接着分析其他列:
yelp_raw_data['type'].describe()
count 10000
unique 1
top review
freq 10000
还记得这一列吗?统计显示该列的列值只有一个:review。
yelp_raw_data['user_id'].describe()
count 10000
unique 6403
top fczQCSmaWF78toLEmb0Zsw
freq 38
和business_id类似,数据集由6 403个用户的评价组成,其中评价次数最多的用户评价了38次!
在本例中,我们无须进行数据转换。
这是我们第一次按照数据科学的5个步骤进行数据探索,不用担心,这肯定不是最后一次。从现在起,每当我们遇到一个新的数据集,都将使用以上数据探索步骤对数据进行转换、分解和标准化。尽管本文介绍的步骤仅仅是一个指引,但为每个数据科学家建立了工作中可遵循的实践标准。这些步骤适用于任何数据集。
《深入浅出数据科学》
[美] 斯楠·奥兹德米尔(Sinan Ozdemir) 著
本书可以帮助读者把数学、编程和商业分析联系起来。通过学习这本书,读者有信心探究和解答复杂的数据科学问题,从抽象的原始的统计,发掘出切实可行的观点和想法。本书适合缺乏数学知识的编程人员,或者是拥有数学技能、想投身数据科学领域的人士阅读使用。
长按二维码,可以关注我们哟
每天与你分享IT好文。
在“异步图书”后台回复“关注”,即可免费获得2000门在线视频课程
异步图书福利送不停
邀请10名好友关注10天直接获取异步图书一本(点击文字获取活动详情哦)
点击阅读原文,购买《深入浅出数据科学》