数据科学利用数学来分析数据、提炼信息并讲述故事。数据科学的成果可以是严格地证实一个假设,也可以是从数据中发现一些有用的属性。在数据科学中,你可以使用许多工具,从基础统计学到复杂的机器学习模型。即使是最常见的工具,也能在数据科学项目中发挥奇妙的作用。
在这个为期7天的速成课程中,您将通过示例学习如何进行数据科学项目。本迷你课程专注于数据科学的核心。假设您已经收集了数据并使其准备就绪。编写网络爬虫和验证您收集的数据可能是一个大话题;这不属于本课程的范畴。本迷你课程面向熟悉 Python 编程且愿意学习 pandas 和 matplotlib 等常用数据科学工具的实践者。您将看到这些工具如何提供帮助,但更重要的是,您将学习如何从现有数据中得出经过量化支持的陈述的过程。让我们开始吧。

数据科学入门指南(7天迷你课程)
照片来源:Eduardo Soares。部分权利保留。
本迷你课程适合谁?
在开始之前,请确保您处于正确的位置。下面的列表提供了一些关于本课程设计对象的通用指南。如果您不完全符合这些要点,请不要惊慌;您可能只需要复习一两个领域即可跟上。
- 了解如何编写少量代码的开发人员。这意味着您使用 Python 可以轻松完成任务,并且知道如何在您的工作站上设置生态系统(这是一个先决条件)。这并不意味着您是编程大师,但您不害怕安装软件包和编写脚本。
- 了解一些统计学知识的开发人员。这意味着您了解一些基本的统计工具,并且不害怕使用它们。这并不意味着您是统计学博士,但如果您遇到不熟悉的术语,可以查阅并学习。
- 了解一些数据科学工具的开发人员。使用 Jupyter notebook 在数据科学中很常见。如果您使用 pandas 库,在 Python 中处理数据会更容易。这个列表还在继续。您不需要成为任何库的专家,但只要能够舒适地调用不同的库并编写代码来处理数据就足够了。
本迷你课程并非数据科学教材。相反,它是一个项目指南,将您一步一步地从知识最少(最少)的开发人员转变为能够自信地展示数据科学项目如何完成的开发人员。
迷你课程概述
本迷你课程分为 7 个部分。
每节课的设计时间约为普通开发人员 30 分钟。有些您可能会更快完成,有些您可能会选择深入研究并花费更多时间。
您可以根据自己的喜好快慢完成每个部分。一个舒适的时间表可能是七天内每天完成一节课。强烈推荐。
您将在接下来的 7 节课中涵盖的主题如下:
- 第一课:获取数据
- 第二课:缺失值
- 第三课:描述性统计
- 第四课:数据探索
- 第五课:可视化相关性
- 第六课:假设检验
- 第七课:识别异常值
这将非常有趣。
不过,您需要付出一些努力:阅读、研究和编程。您想学会如何完成一个数据科学项目,对吧?
在评论中发布您的结果;我会为您加油!
坚持下去;不要放弃。
第一课:获取数据
本迷你课程将使用的数据集是 Kaggle 上提供的“All Countries Dataset”。
该数据集描述了几乎所有国家的人口、经济、地理、健康和政治数据。这方面最知名的就是 CIA World Fact Book。从 World Fact Book 抓取数据应该能为您提供更全面、更及时的信息。然而,使用这个 CSV 格式的数据集可以为您构建网络爬虫节省很多麻烦。
从 Kaggle 下载此数据集(您可能需要注册一个账户才能下载),您会找到 CSV 文件 All Countries.csv
。让我们用 pandas 来检查这个数据集。
1 2 3 4 |
import pandas as pd df = pd.read_csv("All Countries.csv") df.info() |
上面的代码将在屏幕上打印一个表格,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<class 'pandas.core.frame.DataFrame'> RangeIndex: 194 entries, 0 to 193 Data columns (total 64 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 country 194 non-null object 1 country_long 194 non-null object 2 currency 194 non-null object 3 capital_city 194 non-null object 4 region 194 non-null object 5 continent 194 non-null object 6 demonym 194 non-null object 7 latitude 194 non-null float64 8 longitude 194 non-null float64 9 agricultural_land 193 non-null float64 ... 62 political_leader 187 non-null object 63 title 187 non-null object dtypes: float64(48), int64(6), object(10) memory usage: 97.1+ KB |
在上面,您可以看到数据集的基本信息。例如,顶部显示此 CSV 文件中有 194 个条目(行)。表格显示有 64 列(索引从 0 到 63)。有些列是数字的,如 latitude(纬度),有些则不是,如 capital_city(首都)。pandas 中的“object”数据类型通常表示字符串类型。您还可以知道存在一些缺失值,例如在 agricultural_land
(农业用地)中,194 个条目中只有 193 个非空值,这意味着该列有一行包含缺失值。
让我们更详细地查看数据集,例如取前五行作为样本:
1 |
df.head(5) |
这将以表格形式显示数据集的前五行。
您的任务
这是数据集的基本探索。但使用 head()
函数并不总是合适的(例如,当输入数据已排序时)。也有用于类似目的的 tail()
函数。然而,运行 df.sample(5)
通常更有帮助,因为它会随机抽取 5 行。尝试使用此函数。此外,从上面的输出可以看出,列被截断到屏幕宽度。如何修改上面的代码以显示样本中的所有列?
提示:pandas 中有一个 to_string()
函数,您还可以调整通用打印选项 display.max_columns
。
在下一课中,您将学习如何检查数据中的缺失值。
第二课:缺失值
在分析任何数据之前,了解数据的外观很重要。在 pandas 中,浮点数类型的列可能将缺失值表示为 NaN
(“非数字”),而这些值的存在会破坏许多函数。
在 pandas 中,您可以使用 isnull()
或 notnull()
来查找缺失值。这些函数用于检查值是否为 null,包括 Python 的 None
和浮点数 NaN
。返回值是布尔值。如果将其应用于列,您将得到一个包含 True 或 False 的列。求和将是 True 值的计数。
在下面,您使用 isnull()
查找 null 值,然后对结果求和以计算它们的数量。您可以对结果进行排序,以查看哪些列具有最多和最少的缺失值。
1 |
print(df.isnull().sum().sort_values(ascending=False)) |
您将看到上面的打印输出:
1 2 3 4 5 6 7 8 9 10 11 12 |
internally_displaced_persons 121 central_government_debt_pct_gdp 74 hiv_incidence 61 energy_imports_pct 56 electricty_production_renewable_pct 56 ... land_area 0 urban_population_under_5m 0 rural_land 0 urban_land 0 country 0 Length: 64, dtype: int64 |
在上面,您可以看到一些列没有缺失值,例如国家的名称。缺失值最多的列是 internally_displaced_persons
(境内流离失所者),这是一个关于难民的人口统计数据。正如您可以想象的那样,这并不正常,而且大多数国家没有这样的人口是合理的。因此,在处理该数据时,您可以将缺失值替换为零。这是使用领域知识进行插补的一个例子。
要可视化缺失值,您可以使用 Python 包 missingno
。它有助于显示缺失值的分布情况。
1 2 3 4 5 |
import missingno as msno import matplotlib.pyplot as plt msno.matrix(df, sparkline=False, fontsize=12) plt.show() |
上面的图表显示,一些国家(行)和一些属性(列)存在大量缺失值。您可能可以猜出图表中的哪个列对应于 internally_displaced_persons
。具有许多缺失值的国家很可能是因为这些国家没有收集这些统计数据。
您的任务
并非所有缺失值都应替换为零。另一种策略是使用平均值替换缺失值。您能否在此数据集中找到另一个适合用平均值替换缺失值的属性?此外,如何替换 pandas DataFrame 中的缺失值?
在下一课中,您将学习如何使用基本统计量来探索数据。
第三课:描述性统计
给定一个 pandas DataFrame,查看描述性统计信息是一个重要的第一步。在代码中,您可以使用 DataFrame 的 describe()
函数。
1 |
print(df.describe()) |
这显示了每个数字属性的平均值、标准差、最小值、最大值和四分位数。非数字列不在此输出中报告。您可以通过打印列集进行比较来验证这一点。
1 2 |
print(df.columns) print(df.describe().columns) |
此数据集中有很多列。要查看特定列的描述性统计信息,您可以筛选其输出,因为它也是一个 DataFrame。
1 |
print(df.describe()["inflation"]) |
输出如下:
1 2 3 4 5 6 7 8 9 |
count 184.000000 mean 13.046591 std 25.746553 min -6.687320 25% 4.720087 50% 7.864485 75% 11.649325 max 254.949000 Name: inflation, dtype: float64 |
这与定义 df2=df.describe()
然后用 df2["inflation"]
提取相同。对于有缺失值的列,描述性统计是通过跳过所有缺失值来计算的。
您的任务
继续上一个例子,您可以通过检查 df["inflation"].isnull().sum()
是否不为零来判断 inflation
列中存在缺失值。平均值可以使用 df["inflation"].mean()
计算。您如何验证这个平均值确实跳过了所有缺失值?
在下一课中,您将学习如何进一步了解数据。
第四课:数据探索
数据科学的目标是从数据中讲述一个故事。这里让我们看一些例子。
数据集中有一列 life_expectancy
(预期寿命)。是什么影响了预期寿命?您可以做出一些假设并用数据进行验证。您可以检查预期寿命在世界不同地区是否存在差异。
1 |
print(df.groupby("region").mean(numeric_only=True)["life_expectancy"]) |
运行上面的代码并观察其输出。存在一些差异,但它们并不剧烈。应用于 DataFrame 的 groupby()
函数类似于 SQL 语句中的 GROUP BY
子句。但在 pandas 中,对 groupby 应用函数时需要注意列中不同的数据类型。如果像上面那样使用 mean()
,它是计算所有列的平均值(然后您选择 life_expectancy
),如果列不是数字,则会失败。因此,您需要添加一个参数来将操作限制在仅那些列。
从上面可以看出,预期寿命与您居住在世界的哪个部分无关。您也可以按大洲分组而不是按区域分组,但由于某些大洲(如亚洲)地域广阔且多样化,因此平均值可能没有信息量。
您可以应用类似的操作来查找人均 GDP,而不是预期寿命。这是国家 GDP 除以人口,是衡量一个国家富裕程度的指标之一。在代码中:
1 2 |
df["gdp_per_capita"] = df["gdp"] / df["population"] print(df.groupby("region").mean(numeric_only=True)["gdp_per_capita"]) |
这显示了不同地区之间巨大的差异。因此,与预期寿命不同,您居住的地方与您的富裕程度相关。
除了分组,另一个有用的探索和总结数据的方法是数据透视表。pandas DataFrame 中有一个用于此目的的函数。让我们看看不同类型的政府在不同地区是如何被偏好的。
1 |
print(df.pivot_table(index="region", columns="democracy_type", aggfunc="count")["country"]) |
上表显示了计数,因为它被指定为聚合函数。行(索引)是“region”,列是 democracy_type
的值。单元格中的数字计算了同一“region”中“democracy type”的实例。一些值是 NaN,表示该组合没有可“计数”的数据。由于这是计数,所以您知道它意味着零。
您的任务
数据透视表和分组是非常强大的工具,可以用来汇总数据和提炼信息。您如何使用上述数据透视表来查找不同地区的平均人均 GDP 和民主类型?您会看到缺失值。为了在不考虑地区的情况下找到不同民主类型的平均值,有什么合理的缺失值需要填补?
在下一课中,您将学习如何通过图表来分析数据。
第五课:可视化相关性
在上一课中,我们探讨了预期寿命和人均 GDP 列。它们相关吗?
有很多方法可以判断两个属性是否相关。散点图是一个很好的起点,因为它提供了视觉证据。要绘制人均 GDP(如第四课中通过 GDP 除以人口计算的)与预期寿命的散点图,您可以使用 Python 库 Seaborn 结合 Matplotlib。
1 2 3 |
import seaborn as sns sns.scatterplot(data=df, x="life_expectancy", y="gdp_per_capita", hue="continent") |
上面散点图函数中的 hue
参数是可选的。这会根据另一个属性的值来为点着色,因此可以用来判断,例如,非洲在预期寿命和人均 GDP 方面都处于较低水平。
然而,上面生成的图表存在一个问题:您看不到任何线性模式,并且很难判断两个属性之间的关系。在这种情况下,您必须转换数据来确定这种关系。让我们尝试使用半对数图,其中 y 轴以对数刻度表示。您可以使用 Matplotlib 来调整刻度。
1 2 |
sns.scatterplot(data=df, x="life_expectancy", y="gdp_per_capita", hue="continent") plt.yscale("log") # 将y轴设置为对数刻度 |
现在,预期寿命与人均 GDP 的对数呈线性关系似乎更加合理。
在数值上,您可以计算对数 GDP 与预期寿命之间的相关系数。相关系数接近 +1 或 -1 表示相关性很强。不相关的属性将显示接近零的相关系数。您可以使用 pandas 查找所有数字属性中最强的相关因素。
1 2 |
top_features = df.corr(numeric_only=True)["life_expectancy"].abs().sort_values(ascending=False).index[:6] print(top_features) |
上面的代码查找与预期寿命最相关的 6 个属性。它不区分正相关还是负相关,因为排序是基于绝对值。预期寿命本身由于与自身的相关性为 1,因此应位于列表的顶部。
您可以使用 Seaborn 创建相关图,以显示它们之间任何配对的散点图。
1 2 |
sns.pairplot(df, vars=list(top_features)) plt.show() |
相关图可以帮助您快速可视化哪些因素相关。例如,个体雇佣百分比与脆弱就业百分比密切相关。出生率与预期寿命呈负相关(也许是因为年龄越大,人生育的可能性越小)。对角线上的直方图显示了该属性的分布情况。
您的任务
散点图是一个强大的工具,特别是当您有计算机来帮助您制作一个时。上面,您通过视觉建立了两个属性之间的相关性,但相关性不等于因果关系。要建立因果关系,您需要更多证据。在统计学中,有九个著名的“布拉福德·希尔标准”,在流行病学中很有名。一个更简单、更弱的表述是格兰杰因果关系(Granger causality)的两个原则。查看您拥有的数据并与格兰杰因果关系原则进行比较,需要哪些额外数据才能证明预期寿命是由人均 GDP引起的?
在下一课中,您将使用统计检验来分析您的数据。
第六课:假设检验
由于数据科学旨在讲故事,因此在数据科学项目中,你如何支持自己的论点是工作的核心。
让我们再次关注预期寿命:城市化是提高预期寿命的关键,因为它也与先进的医学、卫生和免疫接种相关。你如何证明这一点?
一个简单的方法是显示预期寿命的两个直方图,分别对应于城市化程度更高的国家和未城市化的国家。我们将城市化国家定义为城市人口比例超过 50% 的国家。你可以使用 pandas 计算人口百分比,然后将数据集分成两部分
1 2 3 |
df["urban_pct"] = df["urban_population"]/(df["rural_population"] + df["urban_population"]) df_urban = df[df["urban_pct"] > 0.5] df_rural = df[df["urban_pct"] <= 0.5] |
然后,你可以创建一个重叠的直方图来显示预期寿命
1 2 3 4 5 6 7 |
plt.hist(df_urban["life_expectancy"], alpha=0.7, bins=15, color="blue", label="Urba") plt.hist(df_rural["life_expectancy"], alpha=0.7, bins=15, color="green", label="Rural") plt.xlabel("Life expectancy") plt.ylabel("Number of countries") plt.legend(loc="upper left") plt.tight_layout() plt.show() |
这证实了上述假设,即城市化国家具有更高的预期寿命。但是,图表并不是非常有力的证据。更好的方法是应用一些统计检验来量化我们主张的强度。你想比较两个独立组之间的平均预期寿命,因此 t 检验是合适的。你可以使用 SciPy 包运行 t 检验,如下所示
1 2 3 4 5 6 7 |
import scipy.stats as stats df_urban = df[(df["urban_pct"] > 0.5) & df["life_expectancy"].notnull()] df_rural = df[(df["urban_pct"] <= 0.5) & df["life_expectancy"].notnull()] t_stat, p_value = stats.ttest_ind(df_urban["life_expectancy"], df_rural["life_expectancy"], equal_var=False) print("t-Statistic:", t_stat) print("p-value", p_value) |
与 Matplotlib 会忽略缺失值不同,如果提供的任何数据中存在 NaN,SciPy 将不会计算统计量。因此,上面你清理了数据,删除了缺失值,并重新创建了 DataFrame `df_urban` 和 `df_rural`。t 检验提供的 p 值为 1.6×10-10,非常小。因此,零假设被拒绝,即拒绝两个组具有相同平均值的说法。但是,这个 t 检验并没有说明 `df_urban` 或 `df_rural` 的平均值更高。你可以稍后通过单独计算平均值来轻松了解这一点。
您的任务
与其重新创建 DataFrame `df_urban` 和 `df_rural`,不如通过用各自的平均值填充缺失值来让 SciPy 的 t 检验正常工作。 试试这样做。p 值如何改变?它是否改变了你的结论?
在下一课中,你将从数据中找出异常值。
第 7 课:识别异常值
异常值是一个与大多数样本差异很大的样本,因此很难将其视为更大群体的一部分。
识别异常值最著名的方法是正态分布的 68-95-99 规则,该规则指出,距离均值一个、两个和三个标准差分别涵盖 68%、95% 和 99% 的样本。通常,距离均值 2 个标准差的样本足以被认为是异常值。让我们看看是否有任何国家的预期寿命是异常值。
在使用 68-95-99 规则之前,你需要将数据转换为更接近正态分布。一种方法是使用 Box-Cox 变换。你可以通过比较变换前后的偏度来判断变换是否有效。完美的正态分布的偏度为零
1 2 3 |
boxcox_life, lmbda = stats.boxcox(df_rural["life_expectancy"]) boxcox_life = pd.Series(boxcox_life) print(df_rural["life_expectancy"].skew(), boxcox_life.skew()) |
经过 Box-Cox 变换后,偏度从 0.137 变为 -0.006,更接近于零。Box-Cox 变换计算出的 lambda 值稍后会很有用。顺便说一句,你可以验证变换后的数据大致是对称的
1 2 |
plt.hist(boxcox_life, bins=15) plt.show() |
假设 Box-Cox 变换后的数据服从正态分布,我们可以很容易地找到均值以下和以上 2 个标准差的值。但这只是在变换后的数据中。回想一下,Box-Cox 变换是将 y 变换为 w=(yλ – 1)/λ。因此,我们可以使用 (wλ + 1)1/λ 进行反变换
1 2 3 4 5 6 |
mean, stdev = boxcox_life.mean(), boxcox_life.std() plus2sd = mean + 2 * stdev minus2sd = mean - 2 * stdev upperthreshold = (plus2sd * lmbda + 1)**(1/lmbda) lowerthreshold = (minus2sd * lmbda + 1)**(1/lmbda) print(lowerthreshold, upperthreshold) |
这些是农村人口占比较高的国家中非异常值的下限和上限。让我们看看是否有任何国家超出了这个范围
1 2 |
print(df_rural[df_rural["life_expectancy"] <= lowerthreshold]) print(df_rural[df_rural["life_expectancy"] >= upperthreshold]) |
因此,列支敦士登是上限异常值,而乍得和莱索托是下限异常值。此测试仅向你指出这些异常值,而没有提供任何解释。你需要进一步查看数据以假设为什么会出现这种情况。但这是一种典型的数据科学工作流程。
您的任务
你可以在 `df_urban` 上重复此操作,以找出哪些城市国家是异常值。下限和上限的异常值数量是多少?
这是最后一课。
结束!(看看你已经走了多远)
您做到了。干得好!
花点时间回顾一下您已经走了多远。
- 你发现了 pandas、missingno、scipy、seaborn 和 matplotlib 等 Python 库,它们可以帮助你完成数据科学项目。
- 通过基础统计学,你可以探索数据集以获得洞察。你还可以从数据中确认你的假设。
- 你看到了如何使用散点图等可视化工具以及统计检验来探索数据。
- 你知道数据转换如何帮助你从数据中提取信息,例如查找异常值。
不要轻视这一点,你在很短的时间内取得了长足的进步。这仅仅是你数据科学之旅的开始。继续练习和发展你的技能。
总结
您对这个迷你课程的学习情况如何?
您喜欢这个速成课程吗?
您有任何问题吗?有没有遇到什么难点?
告诉我。在下面留言。
暂无评论。