UCSD-COGS108-数据科学实战中文笔记-全-

UCSD COGS108 数据科学实战中文笔记(全)

原文:COGS108/Tutorials

译者:飞龙

协议:CC BY-NC-SA 4.0

零、数据科学实战

原文:Data Science in Practice

译者:飞龙

协议:CC BY-NC-SA 4.0

欢迎来到阅读数据科学实战课程的实践材料。

本笔记本将指导你获取使用这些教程和作业所需的工具。

对于这些教程你需要什么?

软件

  • python 3.6,以及 anaconda 发行版(datahub满足此要求)
  • Jupyter 笔记本(datahub 满足这个要求)
  • git/GitHub

预备条件

本课程以及本系列教程假定你已具备一些编程基础知识。

特别是它假定了 Python 的一些知识,涵盖了标准库。

如果你对 Python 有些不熟悉,可以按照 Python 笔记本中的链接来补上。

计算资源

这些教程和作业中的示例在计算上并不重要。

你应该能够在你有权访问的任何计算机上运行所有这些材料,假设它将运行上述工具。

工具

以下是此类所需的一系列工具

Jupyter 笔记本是混合代码的,输出和纯文本的一种方法。它们在 Web 浏览器中运行,并连接到内核以便能够执行代码。

官方的 Jupyter 网站在这里

请注意,你不需要单独下载 Jupyter,因为它与 anaconda 一起打包,如下所述。

笔记本可以在网页上展示,并与他人共享。NBViewer 是一个托管和展示笔记本的工具。

NBViewer 在这里提供。

请注意,NBViewer 不是你需要下载的工具,或者根本不需要使用它,它只是一个在线查看笔记本的有用工具。

Anaconda 是 Python 的开源发行版,专为科学计算,数据科学和机器学习而设计。

anaconda 网站是这里,下载页面在这里

Anaconda 本身就是一个发行版,即一系列包装,这些包被一起策划和维护,并且功能强大。

Anaconda 还附带了 conda,它是一个包管理器,允许你下载,安装和管理其他包。

anaconda 发行版包括这些教程所需的所有软件包。

注解

  • 如果你使用的是 Mac,则可以使用本机安装的 python。本机安装的 Python 可能较旧,不包括此类所需的额外软件包,最好保持不变。
    • 下载 anaconda 将安装一个单独的,独立的 Python,保持原生安装不受影响。
  • Windows 本身不需要 Python,因此通常不会预先安装。
  • 如果你需要本地副本(这是一个好主意!),请按照本教程逐步进行操作。或者,你可以将 datahub 用于本课程的所有内容。
# 你可以检查你正在使用哪个 python,以及它是什么版本。
#  一旦安装了 anaconda,你应该会看到你在 anaconda 文件夹中使用 Python
#  确保你拥有的版本是 3.6(或至少 3.X)
#  注意:这些命令行函数可能无法在 Windows 上运行
!which python
!python --version

'''
/anaconda3/bin/python
Python 3.6.8 :: Anaconda, Inc.
'''

Git 是一个用于版本控制的工具,一个软件包。Github 是一个可以与 git 一起使用的在线托管服务,并提供使用 git 的在线工具。

如果你还没有,请安装 git,并在 Github 上创建一个帐户。

Git 和 GitHub 不是一回事,但在实践中,它们通常一起使用,git 用作一个工具,对代码版本控制,管理存储在计算机上的多个副本,以及存储在 Github 上的远程存储库。

请注意,虽然 GitHub 是一家私营公司,但 git 是一个开源工具,可以独立于 GitHub 使用。

# 检查你是否安装了 git(哪个版本并不重要)
!git --version

# git version 2.14.3 (Apple Git-98)

SourceTree 是一个免费的图形用户界面(GUI),用于使用 git 和 Github 管理存储库。

SourceTree 可以在这里获得。你需要在 Atlassian 上创建一个 SourceTree 的帐户,但这是免费的。

如果你知道,或者想学习从命令行使用 git,则无需使用 SourceTree(或任何其他 GUI)。

环境

环境是独立的,编程语言和包组的独立安装,它们不会相互干扰。

Anaconda 有使用环境的详细说明,在这里

你不需要使用环境,但是如果你想要或需要维护多个不同版本的 Python,你可能会发现它很有用。

如果要使用环境,并且已经有 conda,则可以从命令行运行此命令:

$ conda create --name *envname* python=3.6 anaconda

用名称替换*envname*来调用此环境。这将使用 Python 3.6 和 anaconda 发行版安装新环境。

然后,你需要(每次)激活此环境来使用它。为了激活你的环境:

$ source activate *envname*

为了关闭你的环境:

$ source deactivate *envname*

一、Jupyter 笔记本

原文:Jupyter Notebooks

译者:飞龙

协议:CC BY-NC-SA 4.0

这是 Jupyter 笔记本的快速介绍。

Jupyter 笔记本是一种将可执行代码,代码输出和文本组合到一个连接文件中的方法。

项目 Jupyter 的官方文档在这里,他们也有一些示例笔记本在这里

菜单选项和快捷方式

要快速浏览 Jupyter 用户界面,请单击“帮助”菜单,然后单击“用户界面浏览”。

还有大量有用的键盘快捷键。单击“帮助”菜单,然后单击“键盘快捷键”来查看列表。

单元格

笔记本的主要组织结构是“单元格”。

单元格,可以是 markdown(文本),就像这一个或代码单元格(我们会看到他们)。

Markdown 单元格

Markdown 单元格用于传达有关我们笔记本的信息。

它们执行基本的文本格式化,包括斜体,粗体,标题,链接和图像。

双击本节中的任何单元格以查看纯文本的外观。运行单元格,然后查看格式化的 Markdown 文本的外观。

# 这是标题

## 这是较小的标题

### 这是更小的标题

我们可以将我的文本斜体化,像*这样*_这样_

我们可以像**这样**或像__这样__加粗我的文本。

这是一个无序的项目列表:

* 这是一个项目
* 这是一个项目
* 这是一个项目

这是一个有序的项目列表:

1. 这是我的第一个项目
2. 这是我的第二个项目
3. 这是我的第三个项目

我们可以使用缩进来获得嵌套列表:

* 这是一个项目
* 这是一个项目
	* 这是一个项目
	* 这是一个项目
* 这是一个项目

我们还可以组合有序和无序列表:

1. 这是我的第一个项目
2. 这是我的第二个项目
	* 这是一个项目
	* 这是一个项目
3. 这是我的第三个项目

我们可以这样链接到这个[有用的 markdown 速查表](https://www.markdownguide.org/cheat-sheet/)

如果我们不对链接使用 markdown 语法,它只会将链接本身显示为链接文本:https://www.markdownguide.org/cheat-sheet/

LaTeX 格式文本

$$ P(A \mid B) = \frac{P(B \mid A) \, P(A)}{P(B)} $$

代码单元格

# 代码单元格中可以输入注释。
a = 1
b = 2


# 单元格也可以有输出,打印输出到单元格下方。
print(a + b)

# 3


my_string = 'hello world'


print(my_string)

# hello world


# TAB 补全,print(my_string.upper())
my_string.upper()

# 'HELLO WORLD'


my_list = ['a','b','c']


print(my_list)

# ['a', 'b', 'c']

访问文档

Jupyter 有很多有用的快捷方式。在函数或类之后添加一个 '?' 获取带有文档的窗口,或者两个 '??' 来拉出源代码。

# 为示例导入 NumPy
import numpy as np


# 检查 NumPy 数组的文档
np.array?


# 检查 numpy append 函数的完整源代码
np.append??


# 获取你创建的变量的信息
my_string?

自动补全

Jupyter还具有 tab 补全功能,可以自动不全你输入的内容,和/或用于探索可用的代码。

# 移动光标到点号之后,按 Tab 键
# 将出现一个下拉菜单,显示所有可能的补全
np.


# 自动填充不一定在点号处。移至 'ra' 的末尾并按 Tab 键查看补全选项。
ra


# 如果只有一个选项,tab 补全将自动补全你输入的内容。
ran

内核和命名空间

你不需要按顺序运行单元格!这对于灵活地测试和开发代码很有用。

单元格左侧方括号中的数字表示哪个单元格已运行以及按什么顺序运行。

但是,它也很容易丢失已经声明/导入的内容,导致运行单元格时的意外行为。

内核是将笔记本连接到计算机后台来执行代码的东西。

清除并重新启动内核非常有用。你可以从顶部的“内核”下拉菜单执行此操作,也可以选择清除所有输出。

魔术命令

“魔术命令”是 IPython / Jupyter 中一种特殊的(命令行)语法,用于运行特殊功能。它们可以在某行和/或整个单元上运行。

iPython 文档提供了魔术命令的更多信息。

魔术命令旨在简洁地解决标准数据分析中的各种常见问题。魔术命令有两种形式:行魔术,由单个%前缀表示并在单行输入上操作,以及单元魔术,由双%%前缀表示,并在多行输入上操作。

# 访问快速参考清单
%quickref


# 你可以查看可用的魔术命令列表
%lsmagic

'''
Available line magics:
%alias  %alias_magic  %autocall  %automagic  %autosave  %bookmark  %cat  %cd  %clear  %colors  %config  %connect_info  %cp  %debug  %dhist  %dirs  %doctest_mode  %ed  %edit  %env  %gui  %hist  %history  %killbgscripts  %ldir  %less  %lf  %lk  %ll  %load  %load_ext  %loadpy  %logoff  %logon  %logstart  %logstate  %logstop  %ls  %lsmagic  %lx  %macro  %magic  %man  %matplotlib  %mkdir  %more  %mv  %notebook  %page  %pastebin  %pdb  %pdef  %pdoc  %pfile  %pinfo  %pinfo2  %popd  %pprint  %precision  %profile  %prun  %psearch  %psource  %pushd  %pwd  %pycat  %pylab  %qtconsole  %quickref  %recall  %rehashx  %reload_ext  %rep  %rerun  %reset  %reset_selective  %rm  %rmdir  %run  %save  %sc  %set_env  %store  %sx  %system  %tb  %time  %timeit  %unalias  %unload_ext  %who  %who_ls  %whos  %xdel  %xmode

Available cell magics:
%%!  %%HTML  %%SVG  %%bash  %%capture  %%debug  %%file  %%html  %%javascript  %%js  %%latex  %%markdown  %%perl  %%prun  %%pypy  %%python  %%python2  %%python3  %%ruby  %%script  %%sh  %%svg  %%sx  %%system  %%time  %%timeit  %%writefile

Automagic is ON, % prefix IS NOT needed for line magics.
'''


# 查看当前工作目录
%pwd

# '/Users/shannonellis/Desktop/Teaching/COGS108/Tutorials'


# 所有变量
%who

# a	 b	 my_list	 my_string	 np	 


# 所有变量;更多信息
%whos

'''
Variable    Type      Data/Info
-------------------------------
a           int       1
b           int       2
my_list     list      n=3
my_string   str       hello world
np          module    <module 'numpy' from '/an<...>kages/numpy/__init__.py'>
'''


# 历史
%hist

'''
    ### Markdown 单元
    # 历史
    %hist
    # 指定你正在编写 HTML
    %%HTML
    <p>This is a paragraph</p>
    %%bash
    # 等价地,(对于 bash)使用 %% bash cell 魔术,将单元格作为 bash 运行(命令行)
    pwd
    # 在代码单元格中,可以键入注释
    a = 1
    b = 2
    # 单元格也可以有输出,打印输出到单元格下方。
    print(a + b)
    my_string = 'hello world'
    print(my_string)
    # Tab 补全,print(my_string.upper())
    my_string.upper()
    my_list = ['a','b','c']
    print(my_list)
    # 为示例导入 NumPy
    import numpy as np
    # 检查 NumPy 数组的文档
    np.array?
    # 检查 NumPy append 函数的完全源代码
    np.append??
    # 获取你创建的变量的信息
    my_string?
    # 移动光标到点号之后,按 Tab 键
    # 将出现一个下拉菜单,显示所有可能的补全
    np.
    # 在代码单元格中,可以键入注释
    a = 1
    b = 2
    # 单元格也可以有输出,打印输出到单元格下方。
    print(a + b)
    my_string = 'hello world'
    print(my_string)
    # tab 补全,print(my_string.upper())
    my_string.upper()
    my_list = ['a','b','c']
    print(my_list)
    # 为示例导入 NumPy 
    import numpy as np
    # 检查 NumPy 数组的文档
    np.array?
    # 检查 NumPy append 函数的完全源代码
    np.append??
    # 获取你创建的变量的信息
    my_string?
    # 移动光标到点号之后,按 Tab 键
    # 将出现一个下拉菜单,显示所有可能的补全
    np.
    # 访问快速参考清单
    %quickref
    #  你可以检查可用魔术命令的列表
    %lsmagic
    # 查看当前工作目录
    %pwd
    # 所有变量
    %who
    # 所有变量;更多信息
    %whos
    # 历史
    %hist
    # 例如,我们可以计算创建大型列表所需的时间
    %timeit list(range(100000))
    %%timeit
    # 例如,我们可以为整个单元格计时
    a = list(range(100000))
    b = [n + 1 for n in a]
    # 你可以通过在行的开头添加 '!' 来运行终端命令
    !pwd
    # 注意,在这种情况下,'!pwd' 等同于魔术 '%pwd'。
    # '!' 语法更通用,允许你通过命令行运行任何你想要的东西
    %%bash
    # 等价地,(对于 bash)使用 %% bash cell 魔术,将单元格作为 bash 运行(命令行)
    pwd
    # 列出目录中的文件
    !ls
    # 修改当前目录
    !cd .
    # 历史
    %hist
'''

行魔术

行魔术使用单个 '%',并应用于单行。

# 例如,我们可以计算创建大型列表所需的时间
%timeit list(range(100000))

# 1.6 ms ± 26.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

单元魔术

单元魔术使用双“%%”,并应用至整个单元。

%%timeit
# 例如,我们可以为整个单元格计时
a = list(range(100000))
b = [n + 1 for n in a]

# 6.59 ms ± 97.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

运行终端命令

笔记本的另一个好处是能够运行终端命令。

# 你可以通过在行的开头添加 '!' 来运行终端命令
!pwd

# 注意,在这种情况下,'!pwd' 等同于魔术 '%pwd'。
# '!' 语法更通用,允许你通过命令行运行任何你想要的东西

# /Users/shannonellis/Desktop/Teaching/COGS108/Tutorials
%%bash
# 等价地,(对于 bash)使用 %% bash cell 魔术将单元格作为 bash 运行(命令行)
pwd

# /Users/shannonellis/Desktop/Teaching/COGS108/Tutorials
# 列出目录中的文件
!ls

'''
00-Introduction.ipynb              13-OrdinaryLeastSquares.ipynb

01-JupyterNotebooks.ipynb          14-LinearModels.ipynb

02-DataAnalysis.ipynb              15-Clustering.ipynb

03-Python.ipynb                    16-DimensionalityReduction.ipynb

04-DataSciencePython.ipynb         17-Classification.ipynb

05-DataGathering.ipynb             18-NaturalLanguageProcessing.ipynb

06-DataWrangling.ipynb             A1-PythonPackages.ipynb

07-DataCleaning.ipynb              A2-Git.ipynb

08-DataPrivacy&Anonymization.ipynb LICENSE

09-DataVisualization.ipynb         README.md

10-Distributions.ipynb             [34mfiles[m[m

11-TestingDistributions.ipynb      [34mimg[m[m
'''


# 修改当前目录
!cd .

有关更多有用信息,请查看 Jupyter 笔记本提示与技巧,以及有关笔记本如何工作的更多信息。

二、数据分析

原文:Data Analysis

译者:飞龙

协议:CC BY-NC-SA 4.0

这本笔记本讲解了一些,我们可能想要使用数据科学方法做的事情的最小例子。

特别是,为了以下目的,它简要介绍了数据分析:

  • 预测:分析可用数据,以便能够对未来数据进行预测
  • 分类:以有意义的方式对数据进行分组
  • 知识发现:寻求发现数据及其所代表现象的新知识

这些示例将开始使用 python 数据科学工具包中的包,以及一些简单的算法来说明示例案例。

这里的目标是,在代码中看到,数据科学有兴趣做的事情的概况。

这些工具和算法将在未来的笔记本中得到更全面的描述和正确介绍。

%matplotlib inline

# 为一些简单示例导入 matplotlib 和 numpy
import matplotlib.pyplot as plt
import numpy as np

预测

预测是使用当前(训练)数据来预测未来的观测。

示例问题

让我们假设我们想从狗的长度预测体重。

也许,例如,使用卷尺比将狗放到秤上更容易,所以如果我们可以从它们的长度推断它们的重量,我们可以节省很多时间。

# 我们以一些数据开始
lengths = [75, 50, 90, 115]    # 单位 cm
weights = [17.5, 10, 18, 20]   # 单位 kg


# 绘制数据:始终展示你的数据
f, ax = plt.subplots()
ax.plot(lengths, weights , '.')
plt.xlabel('Length (cm)'); plt.xlim([30, 125]);
plt.ylabel('Weight (kg)'); plt.ylim([5, 25]);

png

# Polyfit (degree=1) 会将直线拟合到数据,形式为 y = ax + b
#  一旦我们将这个简单模型拟合到数据
# 我们就可以使用它来对新数据点做预测
a, b = np.polyfit(lengths, weights, 1)


# 所以现在我们可以预测一个新观测(一只新的狗)的重量
new_length = 62
pred_weight = a * new_length + b 
print('Predicted weight for a new data point, weight  is', pred_weight)

# Predicted weight for a new data point, weight  is 13.3460674157


# 我们可以检查我们的预测如何与我们观察到的数据相符
ax.plot(new_length, pred_weight, '.r')
f

png

# 如果我们碰巧知道测试数据的真实重量
# 我们可以检查我们的预测有多好
actual_weight = 14.7
error = actual_weight - pred_weight

print('The (absolute) error of our prediction is', str(error), 'kg\'s.')

# The (absolute) error of our prediction is 1.35393258427 kg's.

我们如何进行预测将变得更加复杂,因为我们处理大量杂乱的数据以及各种“形状”的更多变量。

从根本上说,它归结为同一个过程:我们可以从一组数据中学到什么,这样,给定一个新的数据,我们可以对它进行预测(并使用答案已知的测试数据,来评估我们的预测模型有多好)。

分类

分类(或聚类)是尝试发现数据的系统组织的过程。

问题

我们当地的动物学家正在调查一群松鼠。

她想知道总体中有多少种不同的物种,但只有基本数据可供使用。

我们可以尝试对我们拥有的数据进行聚类,并寻找(看起来像是)有意义的分组。

# 我们观察到一堆松鼠的“身高(cm),体重(g)”对
dat = np.array([[10., 600.], [16., 1200], [6., 800], [12., 700.], [17., 1400.],
               [8., 500.], [20., 1500.], [21., 1300.], [11., 800.], [18., 1100.]])


# 展示数据!
f, ax = plt.subplots()
ax.plot(dat[:, 0], dat[:, 1], '.')
plt.xlabel('Height (cm)'); plt.xlim([0, 25]);
plt.ylabel('Weight (kg)'); plt.ylim([300, 1700]);

png

# 让我们尝试一个聚类算法
# 如果你对 KMeans 不熟悉,我们将在稍后回顾它的工作原理
from sklearn.cluster import KMeans
kmeans = KMeans(2).fit(dat)


# 这为我们提供了每个数据点的标签,以及它所属的簇
kmeans.labels_

# array([0, 1, 0, 0, 1, 0, 1, 1, 0, 1], dtype=int32)


# 我们可以使用它们将我们的数据集拆分为假定的分组
cl_1 = dat[kmeans.labels_ == 0]
cl_2 = dat[kmeans.labels_ == 1]


# 并可视化分类
f, ax = plt.subplots()
ax.plot(cl_1[:, 0], cl_1[:, 1], '.b')
ax.plot(cl_2[:, 0], cl_2[:, 1], '.r')
plt.xlabel('Height (cm)'); plt.xlim([0, 25]);
plt.ylabel('Weight (kg)'); plt.ylim([300, 1700]);

png

评估分类,特别是在这样的无监督的情况下(当我们不知道答案时)是非常重要的。很难知道这里是否真的有两个组 - 或者更多或更少。我们将回到这些分析如何实际运作,以及如何评估你从中获得的结果。

知识发现

知识发现是从数据中学习世界的新事物的尝试。

知识发现不一定在方法上与预测和分类不同,因为寻求新知识可能包括侧重于分类和预测的分析。

三、Python

原文:Python

译者:飞龙

协议:CC BY-NC-SA 4.0

title

Python 是开源高级通用解释性编程语言,是数据科学应用程序中最受欢迎的应用之一。

Python 的官方网站是 这里

为什么是 Python

  • 作为通用语言,Python 支持大量任务。
    • 或者说另一种方式:'Python 不是最好的,但它在所有方面都是第二好的'
    • 这很有用。数据科学项目可能包括从网上抓取数据,分析混合或文本和数字数据,计算函数,训练模型,创建高质量图表,然后托管包含结果的网站。
  • Python 是设计明确的,用户友好的。
  • Python 还拥有庞大的用户社区,他们贡献了大量高质量,维护良好的开源工具。
    • 项目的最佳语言是拥有你需要的东西的那个。
  • 部分由于上面列出的原因,Python 在业界中被大量使用。

学习 Python 的教程

  • Codecademy 非常适合初学者。
  • 也有官方的初学者指南
  • 笨办法学 Python 是一个很好的教程,拥有更深入的概述。
    • 它实际上并不特别难,并且在第四版中兼容了 Python3。
  • Python 的旋风之旅 是一个免费的 Jupyter 笔记本集合,带你浏览 Python。
    • 如果你有一些其他语言的编程经验,并希望快速浏览 Python 的细节,那么本书特别适合(并为其专门设计)。

Python 实践

  • Python 挑战是一个(有时令人愤怒的)编程挑战的好地方。
  • LeetCode是一个更强的技术编码问题和挑战的地方(面向业界面试)。

摆脱困境

在某些时候,你会陷入困境,它发生了。互联网是你的朋友。

如果你得到错误或不确定如何继续,请使用【你最喜欢的搜索引擎】以及与你要执行的操作相关的特定搜索字词。有时这只是意味着搜索你得到的错误。

你可能会在 StackOverflow 上找到回复 - 这基本上是编程问题的论坛,也是寻找答案的好地方。

Python2 vs Python3

这个课程将使用 Python3 - 它是当前开发的 Python 版本。特别是 3.6 是 2016 年发布的最新版本。

Python3 是 Python2 的一个突破,因为有一些更大的变化打破了向后兼容性

Python2 仍然很受欢迎,而且经常被使用,部分原因是,主要新版本需要一段时间才能使所有东西变得可用,并且更新他们。现在,Python3 几乎拥有所有可用的东西,并且是 Python 的未来。

在实践中,Python 2 和 3 非常相似 - 学习一个就相当于获知另一个,并且代码通常可以通过最小的更改兼容两者。

官方 Python 文档包括 Py2 与 Py3 的讨论,包括使用指南。

包基本上只是代码集合。anaconda 发行版附带了本课程所需的所有核心软件包。为获得其他包,anaconda 自带conda包管理器,支持下载和安装其他包。

四、Python 中的数据科学

原文:Data Science in Python

译者:飞龙

协议:CC BY-NC-SA 4.0

Python 有大量可用于数据科学的工具。

Python 中的数据科学核心围绕着一些核心模块,通常包括【scipy,numpy,pandas,matplotlib 和 scikit-learn】。

在这里,我们将探讨这些模块的基础知识以及它们的作用。

Scipy是一个“生态系统”,包括一系列用于 Python 中科学计算的开源软件包。

scipy 组织的网站在这里,包括生态系统的描述入门,以及广泛的教程

# 你可以导入完整的 scipy 包,通常缩写为 'sp'
import scipy as sp

# 但是,导入特定子模块可能更常见
# 例如,让我们导入 stats 子模块
import scipy.stats as sts

Scipy 具有广泛的功能。

对于一个简单/随机的例子,让我们使用它的统计模块来模拟用伯努利分布翻转硬币,这是一个可以模拟随机变量的分布,随机变量要么是 0(称之为反面),要么是 1(称之为正面)。

# 让我们模拟一个均匀的硬币 -  0.5 的概率是正面
sts.bernoulli.rvs(0.5)

# 0


# 让我们翻转一堆硬币吧!
coin_flips = [sts.bernoulli.rvs(0.5) for i in range(100)]
print('The first ten coin flips are: ', coin_flips[:10])
print('The percent of heads from this sample is: ', sum(coin_flips) / len(coin_flips) * 100, '%')

'''
The first ten coin flips are:  [1, 1, 1, 1, 0, 1, 1, 0, 1, 1]
The percent of heads from this sample is:  60.0 %
'''

Numpy 包含一个数组对象(用于多维数据,通常是统一类型),以及线性代数和数组分析的操作。

numpy 网站是这里,包括他们的官方快速入门教程

注意:

数组是“相似对象的系统排列,通常在行和列中”(来自 Wikipedia 的定义)

# Numpy 标准导入为 'np'
import numpy as np


# Numpy 的专长是线性代数和(匀质)数据数组

# 定义一些数组
# 数组可以有不同的类型,但数组中的所有数据都需要是相同的类型
arr_1 = np.array([1, 2, 3])
arr_2 = np.array([4, 5, 6])
bool_arr = np.array([True, False, True])
str_arr = np.array(['a', 'b', 'c'])


# 请注意,如果你尝试创建混合数据类型数组,numpy 将不会失败
# 但它将(默默地)
arr = np.array([1, 'b', True])

# 检查数组元素的类型
print(type(arr[0]))
print(type(arr[2]))

'''
<class 'numpy.str_'>
<class 'numpy.str_'>
'''


# 因此,这些数组不会像你期望的那样表现
# 最后一项看起来像布尔值
print(arr[2])

# 但是,因为它实际上是一个字符串,所以它不会像布尔值一样进行求值
print(arr[2] == True)

'''
True
False
'''

有关 numpy 的更多练习,请查看集合 numpy 练习

pandas

Pandas 是一个用于在数据结构组织数据,并对其进行数据分析的软件包。

Pandas 官方网站在这里,包括[ 10 分钟入门]等材料(http://pandas.pydata.org/pandas-docs/version/0.17.0/10min.html)和[基本功能]教程(http://pandas.pydata.org/pandas-docs/version/0.17.0/basics.html)。

Pandas 主要数据对象是 DataFrame(数据帧),它是一个功能强大的数据对象,用于将混合数据类型与标签一起存储。

Pandas 数据帧还提供了大量可用于处理和分析数据的方法。

如果你熟悉 R,pandas 数据帧对象和方法与 R 非常相似。

# Pandas 标准导入为 pd
import pandas as pd


# 让我们从一组数据开始,但我们也为每个数据项放置一个标签
dat_1 = np.array(['London', 'Washington', 'London', 'Budapest'])
labels = ['Ada', 'Alonzo', 'Alan', 'John']


# Pandas 提供 'Series' 数据对象来存储带有轴标签的 1d 数据
pd.Series?


# 让我们制作一个没有数据的序列,并收好它
ser_1 = pd.Series(dat_1, labels)
ser_1.head()

'''
Ada           London
Alonzo    Washington
Alan          London
John        Budapest
dtype: object
'''


# 如果我们有一些不同的数据(标签相同),我们可以制作另一个序列
dat_2 = [36, 92, 41, 53]
ser_2 = pd.Series(dat_2, labels)

ser_2.head()

'''
Ada       36
Alonzo    92
Alan      41
John      53
dtype: int64
'''


# 然而,拥有一系列序列可能会很快变得非常混乱
# 因此,Pandas 提供了数据帧 - 一个强大的数据对象,用于存储带标签的混合类型数据
pd.DataFrame?


# 有几种方法可以初始化数据帧
# 在这里,我们提供了一个由我们的序列组成的字典
df = pd.DataFrame(data={'Col-A': ser_1, 'Col-B':ser_2}, index=labels)


# 对于类别数据,我们可以检查每个值的数量
df['Col-A'].value_counts()

'''
London        2
Washington    1
Budapest      1
Name: Col-A, dtype: int64
'''


# 请注意,数据帧实际上是Series的集合
# 当我们索引 df 时,如上所述,我们实际上是拉出一个序列
# 因此,'.value_counts()' 实际上是一个 Series 方法
type(df['Col-A'])

# pandas.core.series.Series


# Pandas 还为我们提供了一种直接探索和分析数据帧中数据的方法
# 例如,所有数字数据列的平均值
df.mean()

'''
Col-B    55.5
dtype: float64
'''

对于 Pandas 的更多练习,你可以尝试一些练习集,包括这个这个

matplotlib

Matplotlib 是一个用于绘图的库,特别是 2D 绘图。

Matplotlib 官方网站包括官方教程以及示例的画廊,你可以从中起步和修改。

# 这个魔术命令用于在笔记本中内联绘制所有图形
%matplotlib inline


# Matplotlib 标准导入为 plt
import matplotlib.pyplot as plt


# 绘制基本折线图
plt.plot([1, 2, 3], [4, 6, 8])

# [<matplotlib.lines.Line2D at 0x11c0c5128>]

png

matplotlib 还有许多外部材料,包括这个

sklearn

Scikit-Learn 是一个用于数据挖掘,数据分析和机器学习的软件包。

这是 scikit-learn 官方网站,包括他们的官方教程

# 导入 sklearn
import sklearn as skl


# 查看模块说明
skl?

我们将在稍后的教程中入门机器学习并使用 sklearn。

外部资源

有许多资源可供学习如何使用这些软件包。

上面的链接包括官方文档和教程,这是最好的起点。

你还可以在谷歌中搜索其他资源和练习。

涵盖所有这些工具的特别好(和免费)的资源是 Jake Vanderplas数据科学手册

五、数据收集

原文:Data Gathering

译者:飞龙

协议:CC BY-NC-SA 4.0

数据收集只是将数据收集在一起的过程。

本笔记本涵盖了可用于收集分析数据的策略。

如果你想继续进行数据分析(使用提供的数据),你可以转到下一个教程,稍后再回到本教程。

数据收集可以包括启动数据收集项目,网络抓取,从数据库中提取,批量下载数据等任何内容。

它甚至可能只是简单地打电话给某人询问你是否可以使用他们的一些数据。

在哪里获取数据

网络

网络上绝对是数据或获取数据的方式,可以通过托管数据仓库,从中下载数据,通过API,从特定应用程序请求特定数据,或作为数据本身,你可以使用网络爬虫直接从网站提取数据。

除了网络

并非所有数据都在网络上编入索引或可访问,至少不是公开的。

有时查找数据意味着在任何地方追逐数据。

如果你需要某些特定数据,你可以尝试找出可能拥有该数据的人,并与他们联系,看看它是否可用。

数据收集技巧

根据你的收集方法,你可能需要执行以下某些组合:

  • 从仓库下载数据文件
  • 将数据文件读入 python
  • 使用 API
  • 查询数据库
  • 打电话给某人,让他们给你发一个硬盘

数据仓库

数据仓库基本上只是存储数据的地方。出于我们的目的,它是一个可以从中下载数据的地方。

项目材料中包含了一个精选列表,他包含良好的数据源。

数据库

数据库是有组织的数据集合。 更正式地说,“数据库”是指一组相关数据及其组织方式。

结构化查询语言 - SQL

SQL(发音为“sequel”)是一种用于与数据库“通信”的语言,用于查询从中请求特定数据。

这里有一个 SQL 的实用介绍和教程,以及[这里](http://www.cheat-sheets.org/sites/sql.su/)和这里有一些有用的“备忘单”。

SQL 是与关系数据库交互的标准且最流行的方式。

注意:其余教程都没有假定或需要任何 SQL 知识。

如果需要,或者它是否与访问要分析的数据相关,可以查看它,但这组教程不需要它。

应用程序接口 (API)

API 基本上是软件与软件通信的一种方式 - 它是为软件设计的应用程序/网站/数据库的接口。

有关API的简单说明请参见这里;更广泛,更技术性的概述参见这里

API提供了许多功能 - 你可以向应用程序发送请求开执行各种操作。 事实上,任何设计用于以编程方式使用的接口都是 API,包括例如用于使用代码包的接口。

API 执行和提供的许多功能之一是,查询和访问特定应用/数据库中的数据的方法。使用 API 进行数据收集的好处是,它们通常以结构良好的格式返回数据,这些格式相对容易分析。

从 Python 启动 URL 请求

# 导入
# requests 允许你从 python 发出 http 请求
import requests
import pandas as pd

实际上,API 通常是返回原始数据(json 或 XML)的特殊 URL,而不是为人类读者呈现的网页(html)。查找特定 API 的文档,了解如何发送请求来访问所需数据。例如,让我们试试 Github API。

# 使用 Github API 从特定用户请求数据
page = requests.get('https://api.github.com/users/tomdonoghue')


# 在这种情况下,我们得到的内容是一个 json 文件
page.content

# b'{"login":"TomDonoghue","id":7727566,"avatar_url":"https://avatars0.githubusercontent.com/u/7727566?v=4","gravatar_id":"","url":"https://api.github.com/users/TomDonoghue","html_url":"https://github.com/TomDonoghue","followers_url":"https://api.github.com/users/TomDonoghue/followers","following_url":"https://api.github.com/users/TomDonoghue/following{/other_user}","gists_url":"https://api.github.com/users/TomDonoghue/gists{/gist_id}","starred_url":"https://api.github.com/users/TomDonoghue/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/TomDonoghue/subscriptions","organizations_url":"https://api.github.com/users/TomDonoghue/orgs","repos_url":"https://api.github.com/users/TomDonoghue/repos","events_url":"https://api.github.com/users/TomDonoghue/events{/privacy}","received_events_url":"https://api.github.com/users/TomDonoghue/received_events","type":"User","site_admin":false,"name":"Tom","company":"UC San Diego","blog":"tomdonoghue.github.io","location":"San Diego","email":null,"hireable":null,"bio":"Cognitive Science Grad Student @ UCSD. \\r\\nOn Twitter @TomDonoghue","public_repos":13,"public_gists":0,"followers":13,"following":35,"created_at":"2014-05-28T20:20:48Z","updated_at":"2018-01-09T04:15:59Z"}'


# 我们可以用 pandas 读取 json 数据
pd.read_json(page.content, typ='series')

'''
avatar_url             https://avatars0.githubusercontent.com/u/77275...
bio                    Cognitive Science Grad Student @ UCSD. \r\nOn ...
blog                                               tomdonoghue.github.io
company                                                     UC San Diego
created_at                                          2014-05-28T20:20:48Z
email                                                               None
events_url             https://api.github.com/users/TomDonoghue/event...
followers                                                             13
followers_url          https://api.github.com/users/TomDonoghue/follo...
following                                                             35
following_url          https://api.github.com/users/TomDonoghue/follo...
gists_url              https://api.github.com/users/TomDonoghue/gists...
gravatar_id                                                             
hireable                                                            None
html_url                                  https://github.com/TomDonoghue
id                                                               7727566
location                                                       San Diego
login                                                        TomDonoghue
name                                                                 Tom
organizations_url          https://api.github.com/users/TomDonoghue/orgs
public_gists                                                           0
public_repos                                                          13
received_events_url    https://api.github.com/users/TomDonoghue/recei...
repos_url                 https://api.github.com/users/TomDonoghue/repos
site_admin                                                         False
starred_url            https://api.github.com/users/TomDonoghue/starr...
subscriptions_url      https://api.github.com/users/TomDonoghue/subsc...
type                                                                User
updated_at                                          2018-01-09T04:15:59Z
url                             https://api.github.com/users/TomDonoghue
dtype: object
'''

这个列表包含常用和可用 API 的集合。

网络抓取

网络抓取是指你(以编程方式)从网站提取数据。Wikipedia 有一个关于网页抓取的有用页面。

请注意,以下部分使用BeautifulSoup模块,该模块不是标准 anaconda 发行版的一部分。

如果你没有BeautifulSoup,并希望让它运行此部分,你可以取消注释下面的单元格并运行它,来当前的 Python 环境中安装BeautifulSoup。 你只需要这样做一次。

# 导入 sys
# !conda install --yes --prefix {sys.prefix} beautifulsoup4


# 导入 BeautifulSoup
from bs4 import BeautifulSoup


# 设置我们希望抓取的页面的 URL
site_url = 'https://en.wikipedia.org/wiki/Data_science'

# 启动 URL 请求,来获取页面
page = requests.get(site_url)


# 打印出已爬取网页的前 1000 个字符
page.content[0:1000]

# b'<!DOCTYPE html>\n<html class="client-nojs" lang="en" dir="ltr">\n<head>\n<meta charset="UTF-8"/>\n<title>Data science - Wikipedia</title>\n<script>document.documentElement.className = document.documentElement.className.replace( /(^|\\s)client-nojs(\\s|$)/, "$1client-js$2" );</script>\n<script>(window.RLQ=window.RLQ||[]).push(function(){mw.config.set({"wgCanonicalNamespace":"","wgCanonicalSpecialPageName":false,"wgNamespaceNumber":0,"wgPageName":"Data_science","wgTitle":"Data science","wgCurRevisionId":822535327,"wgRevisionId":822535327,"wgArticleId":35458904,"wgIsArticle":true,"wgIsRedirect":false,"wgAction":"view","wgUserName":null,"wgUserGroups":["*"],"wgCategories":["Use dmy dates from December 2012","Information science","Computer occupations","Computational fields of study","Data analysis"],"wgBreakFrames":false,"wgPageContentLanguage":"en","wgPageContentModel":"wikitext","wgSeparatorTransformTable":["",""],"wgDigitTransformTable":["",""],"wgDefaultDateFormat":"dmy","wgMonthNames":["","Ja'

请注意,抓取的网页的来源是一堆杂乱的 HTML。

那里有很多信息,但没有明确的组织。虽然页面中有一些结构,由 HTML 标签等描述,但我们只需要使用它们来解析数据。 我们可以使用 BeautifulSoup 来做到这一点,它接收这样的杂乱文档,并根据指定的格式解析它们。

# 使用 Beautiful Soup 和 html 解析器解析网页
soup = BeautifulSoup(page.content, 'html.parser')


# 有了解析的 soup 对象,我们可以选择网页的特定片段

# 打印页面标题
print('TITLE: \n')
print(soup.title)

# 打印第一个 p 标签
print('\nP-TAG:\n')
print(soup.find('p'))

'''
TITLE: 

<title>Data science - Wikipedia</title>

P-TAG:

<p><b>Data science</b>, also known as <b>data-driven science</b>, is an interdisciplinary field of scientific methods, processes, and systems to extract [knowledge](/wiki/Knowledge) or insights from [data](/wiki/Data) in various forms, either structured or unstructured,<sup class="reference" id="cite_ref-:0_1-0">[[1]](#cite_note-:0-1)</sup><sup class="reference" id="cite_ref-2">[[2]](#cite_note-2)</sup> similar to [data mining](/wiki/Data_mining).</p>
'''

从 soup 对象中,你可以更有条理地探索页面,并以这种方式提取你感兴趣的特定成分。

请注意,在其他方面它仍然是“混乱的”,因为可能会或可能不会有关于页面布局的系统结构,并且仍然可能需要大量工作才能从中提取你想要的特定信息。

API vs 网络抓取

网络抓取与使用 API 不同,即使可以通过互联网访问许多 API。网络抓取的不同之处在于,你(以编程方式)访问互联网,并提取感兴趣的数据。

注意:

请注意,从网站上抓取数据本身(不使用 API)通常可能是一个复杂的项目 - 网站抓取可能需要进行大量调整才能获得所需的数据。

请注意,网站上显示的数据可能结构不合理,或者采用有组织的格式,便于分析。

如果你尝试抓取网站,还要确保你可以抓取数据,并遵循网站服务条款。

六、数据整理

原文:Data Wrangling

译者:飞龙

协议:CC BY-NC-SA 4.0

“数据整理”通常是指将原始数据,转换为可用于你感兴趣的分析的可用形式,包括加载,聚合和格式化。

注意:在整个笔记本中,我们将使用 '!' 运行 shell 命令cat,来打印出示例数据文件的内容。

Python I/O

Python 有一些基本的 I / O (输入/输出)工具。

这是 I / O 的官方 Python 文档

# 查看示例数据文件
!cat files/dat.txt

'''
First line of data

Second line of data
'''


# 首先,显式打开文件对象进行读取
f_obj = open('files/dat.txt', 'r')

# 然后,你可以遍历文件对象,抓取每行数据
for line in f_obj:
    # 请注意,我正在删除每行末尾的新行标记('\n')
    print(line.strip('\n'))

# 完成后,必须关闭文件对象
f_obj.close()

'''
First line of data
Second line of data
'''


# 由于打开和关闭文件基本上总是在一起,因此有一个快捷方式来完成它们
# 使用 'with' 关键字打开文件,文件对象将在代码块的末尾自动关闭
with open('files/dat.txt', 'r') as f_obj:
    for line in f_obj:
        print(line.strip('\n'))
        
'''
First line of data
Second line of data
'''

Python 的 I / O是一种非常“低级”的读取数据文件的方法,并且通常需要大量工作来整理读取文件的细节 - 例如,在上面的示例中,明确地处理新行字符。

只要你有合理的结构化数据文件,使用标准化的文件类型,你就可以使用更高级的函数来处理很多这些细节 - 例如,将数据直接加载到 pandas 数据对象中。

Pandas I/O

Pandas 有一系列函数,可以将标准文件类型的整个文件自动读取到 pandas 对象中。

这是 I / O 的官方 Pandas 文档

import pandas as pd


# Tab 补全来检查所有可用的读取函数
pd.read_

文件类型

存在许多不同的标准化(和非标准化)文件类型,其中可以存储数据。在这里,我们将从检查 CSV 和 JSON 文件开始。

CSV 文件

“逗号分隔值”文件存储数据,以逗号分隔。把它们想象成列表。

这是维基百科中 CSV 文件的更多信息。

# 我们来看一下 csv 文件(以纯文本打印)
!cat files/dat.csv

'''
1, 2, 3, 4

5, 6, 7, 8

9, 10, 11, 12
'''

Python 中的 CSV 文件

# Python 有一个专门用于处理 csv 的模块
import csv


# 我们可以使用 csv 模块读取我们的文件
with open('files/dat.csv') as csvfile:
    csv_reader = csv.reader(csvfile, delimiter=',')
    for row in csv_reader:
        print(', '.join(row))
        
'''
1,  2,  3,  4
5,  6,  7,  8
9,  10,  11,  12
'''

Pandas 中的 CSV 文件

# Pandas 也具有直接加载 csv 数据的函数
pd.read_csv?


# 让我们读入我们的 csv 文件
pd.read_csv(open('files/dat.csv'), header=None)
0 1 2 3
0 1 2 3 4
1 5 6 7 8
2 9 10 11 12

JSON 文件

JavaScript 对象标记文件可以存储层次化键/值对。把它们想象成字典。

这是来自 wikipedia 的 JSON 文件的更多信息。

# 我们来看一下 json 文件(以纯文本打印)
!cat files/dat.json

'''
{

  "firstName": "John",

  "age": 53

}
'''


# 将 json 看做与字典相似
d = {'firstName': 'John', 'age': '53'}
print(d)

# {'firstName': 'John', 'age': '53'}

Python 中的 JSON 文件

# Python 还有一个用于处理 json 的模块
import json


# 加载 json 文件
with open('files/dat.json') as dat_file:    
    dat = json.load(dat_file)


# 检查加载的数据类型
print(type(dat))

# <class 'dict'>

Pandas 中的 JSON 文件

# Pandas 还支持读取 json 文件
pd.read_json?


# 你可以使用 pandas 读取 json 格式的字符串
# 请注意,这里我指定将其作为 pd.Series 读取,因为只有一行数据
pd.read_json('{ "first": "Alan", "place": "Manchester"}', typ='series')

'''
first          Alan
place    Manchester
dtype: object
'''


# 用 pandas 读入我们的 json 文件
pd.read_json(open('files/dat.json'), typ='series')

'''
age            53
firstName    John
dtype: object
'''

七、数据清理

原文:Data Cleaning

译者:飞龙

协议:CC BY-NC-SA 4.0

“数据清理”是查找并删除或修复“错误数据”的过程,其中“错误数据”通常指的是损坏和/或不准确的数据点。

# 导入
import numpy as np
import pandas as pd

缺失值

缺失值只是缺少的数据点。可以通过多种方式指示缺失值。

值可以是字面上的空值,或编码为特殊值,例如 Python NoneNaN,一个 numpy 对象(“非数字”的缩写)。

有时缺失值由任意选择的值指示,例如由某些不可能的值指示,例如-999

缺失值通常需要在进行任何分析之前进行处理。

Python - None 类型

# Python 具有特殊值“None”,可以编码缺失值或 null 值
dat_none = None


#  None 实际上是它自己的类型
print(type(None))

# <class 'NoneType'>


# 请注意,“None”的作用类似于 null 类型(就好像变量不存在一样)
assert dat_none

'''
---------------------------------------------------------------------------

AssertionError                            Traceback (most recent call last)

<ipython-input-4-95ad9e3fb11e> in <module>()
      1 # Note that 'None' acts like a null type (as if the variable doesn't exist)
----> 2 assert dat_none


AssertionError: 
'''


# 由于 None 是 null 类型,因此当数据中包含 None 时,基本操作将失败
dat_lst = [1, 2, 3, None]
sum(dat_lst) / len(dat_lst)

'''
    ---------------------------------------------------------------------------

    TypeError                                 Traceback (most recent call last)

    <ipython-input-5-bc3aab645ea1> in <module>()
          1 # Since None is a null type, basic operations will fail when None is in the data
          2 dat_lst = [1, 2, 3, None]
    ----> 3 sum(dat_lst) / len(dat_lst)
    

    TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
'''

Numpy - NaN

# Numpy也有“非数字”的特殊值 -- NaN
dat_nan = np.nan


# 它实际上是一个特殊的浮点值
type(dat_nan)

# float


# 它不会求值为 null(与 None 不同)
assert dat_nan


# Numpy 实际上有多个版本的 NaN  - 但它们实际上都是一样的。
np.nan is np.NaN is np.NAN

# True


# NaN 值不会失败(与 None 不同)但它们将返回未定义(NaN)的答案
dat_a = np.array([1, 2, 3, np.nan])
print(np.mean(dat_a))

# nan


# 你可以告诉 numpy 进行计算,忽略 NaN 值,但你必须明确告诉它这样做
np.nanmean(np.array([1, 2, 3, np.nan]))

# 2.0

数据清理的“艺术”

处理缺失数据是一个决策点:你需要做什么?

  • 你丢弃了观测吗?
    • 如果这需要放弃大量观测怎么办?
  • 你保留它,但在任何计算中忽略它?
    • 如果你在不同的计算中得到不同的 N,怎么办?
  • 你重新编码那个数据点吗?
    • 你把它重新编码为什么?

不可能的值

数据清理包括检查和处理不可能的值。由于编码或数据输入错误,可能会出现不可能的值。

请注意,数据集还可能将缺失的数据编码为特殊值 - 例如,使用-999表示缺少的年龄。

这些都必须处理,否则会扭曲你的结果。

Pandas 中的数据清理

示例问题:我们有两个单独的文件,它们共同拥有一组人的 id 号,年龄,体重和身高。

让我们假设最终,我们对年龄与身高的关系感兴趣(老年人萎缩真的是真的吗??)

数据文件:

  • messy_dat.json,有 id 和身高信息
  • messy_dat.csv,有 id,年龄和体重信息
# 加载 json 文件
df1 = pd.read_json('files/messy_dat.json')

# 由于JSON文件按字母顺序读取列,因此重新排列列
df1 = df1[['id', 'height']]


# 查看数据。 我们有 NaN 值!
df1
id height
0 1 168.0
1 2 155.0
2 3 NaN
3 4 173.0
# 让我们用 pandas 来丢弃 NaN 值
# 注意 inplace 参数:这将操作我们调用的数据帧
# 而不是返回并将数据帧重新保存到新变量
df1.dropna(inplace=True)


# 丢弃 NaN 后检查数据
df1
id height
0 1 168.0
1 2 155.0
3 4 173.0
# 读入 csv 数据文件
df2 = pd.read_csv('files/messy_dat.csv')


# 检查数据
df2
id age weight
0 1 20 11.0
1 2 27 NaN
2 3 25 14.0
3 4 -999 12.0

请注意,我们有另一个 NaN 值! 但是,它位于体重列中,我们实际上并不计划将其用于当前分析。 如果我们从这个数据框中删除 NaN,我们实际上拒绝了好的数据 - 因为我们将放弃记录 1,他实际上确实有我们需要的年龄和身高信息。

# 因此,既然我们不需要它,那么让我们丢弃重量列
df2.drop('weight', axis=1, inplace=True)


# 让我们检查年龄列中是否有任何 NaN 值(我们确实需要)
# isnull() 为每个数据点返回布尔值,指示它是否为 NaN
# 我们可以对布尔数组求和,看看我们有多少个 NaN 值
sum(df2['age'].isnull())

# 0

我们需要的数据列中没有任何 NaN 值! 我们继续吧!

# 现在让我们将数据合并在一起
# 请注意,这里我们指定使用 'id' 列来合并数据
# 这意味着数据点将基于具有相同 ID 的数据点来合并。
df = pd.merge(df1, df2, on='id')


# 检查合并后的数据帧
df
id height age
0 1 168.0 20
1 2 155.0 27
2 4 173.0 -999
# 查看基本的描述性统计量,看看事情是否合理
df.describe()
id height age
count 3.000000 3.000000 3.000000
mean 2.333333 165.333333 -317.333333
std 1.527525 9.291573 590.351026
min 1.000000 155.000000 -999.000000
25% 1.500000 161.500000 -489.500000
50% 2.000000 168.000000 20.000000
75% 3.000000 170.500000 23.500000
max 4.000000 173.000000 27.000000

所以,看起来我们的平均年龄约是 300....

这似乎不对。在数据收集的某些时刻,缺失的年龄值似乎已编码为-999。我们需要处理这些数据。

# 丢弃所有带有不可能年龄的行
df = df[df['age'] > 0]


# 那么实际的平均年龄是多少?
df['age'].mean()

# 23.5


# 查看清理过的数据帧!它现在准备好进行真正的分析了!
df
id height age
0 1 168.0 20
1 2 155.0 27

数据清理注解

这实际上只是数据清理的开始 - 将数据转换为适合分析的形状,可以包括任何东西

提示:

  • 阅读你拥有的数据集的任何文档
    • 像缺失值这样的东西可能是任意编码的,但应该(希望)记录在某处
  • 检查数据类型是否符合预期。如果你正在阅读混合类型数据,请确保最终得到正确的编码
  • 可视化你的数据!看看分布是否似乎合理
  • 检查基本统计量。df.describe()可以让你感觉到,某些东西是否真的偏斜了
  • 请记住你的数据收集方式。
    • 如果任何东西来自将信息输入表格的人类,这可能需要大量清洁
      • 修复数据输入错误(错别字)
      • 使用不同的单位/格式/惯例处理输入
  • 清理这类数据可能需要更多的手工工作(因为错误很可能是特殊的)

请注意,在许多实际情况中,可视地扫描数据表来查找丢失或错误的数据,可能是难以处理的,和/或非常低效。查看你的数据可能需要查看分布和描述性统计量,而不是原始数据。

Quartz 有一个有用的错误数据指南,Pandas 教程有很多相关资料,包括数据清理的章节 (#7)。

八、数据隐私和匿名化

原文:Data Privacy & Anonymization

译者:飞龙

协议:CC BY-NC-SA 4.0

许多数据,可能是数据科学中通常使用的绝大多数数据,直接或间接地与人有关。

个人拥有某些隐私权,关于谁可以知道或分享有关特定身份个人的信息。 对于某些类别的敏感信息(例如,与健康相关的信息具有特殊保护)尤其如此,但也适用于所有其他数据。

信息隐私

信息(或数据)隐私是指收集,使用和发布数据的法律,道德和实际问题,其中包含数据集中包含的人员的可识别信息。 它还涉及何时以及如何处理数据隐私问题,以及如何保护用户的隐私。

Wikipedia拥有信息隐私的概述。

匿名化

数据匿名化是一种信息清理 - 即删除敏感信息 - 用于隐私保护。这是一个修改数据集的过程,使其反映的个体是匿名的。 大多数情况下,这通常意味着从数据集删除个人身份信息,使得数据集中包含的个人的身份是匿名的。

Wikipedia 也拥有数据匿名化的概述。

数据保护和匿名化是数据科学和数据实践的跨学科组成部分,包括从数据使用的伦理和合法性考虑,到数据保护和匿名的实际和技术挑战。

匿名数据通常归结为从数据集中删除任何个人可识别数据,或者,如果必须保留此信息,则将可识别数据与敏感信息分开。

数据匿名化的部分困难在于,虽然我们可以证明给定数据集是匿名的,但这取决于特定的假设 - 最值得注意的是,在没有额外的外部信息用于尝试解密的假设下,数据集才可证明是匿名的。

在实践中,通常可以通过组合多个数据集来完成对数据的去匿名化 - 使用来自一个或多个可用信息源的信息来解码包含在一些其他数据集中的个体。

规定

有许多关于数据隐私和用户身份保护的官方指南,规则和标准,尽管其中大部分都是针对具体案例的。

至少,在数据保护方面,除其他外,法律要求的内容依赖于:

  • 数据是什么/包含什么,以及关于谁,
    • 某些数据类型和/或群体可能具有特殊保护,例如与健康相关的信息。
  • 谁拥有数据以及他们以何种身份行事(公司,大学等)
    • 科学研究的规定与公司的规定不同
  • 收集数据时的用户协议/同意程序。
    • 个人有权根据其数据使用的内容进行自我决定。数据仅应用于其使用条款/收集/同意程序所涵盖的内容。
  • 数据用于什么。
    • 根据拥有和使用数据的目标,通常是什么和谁的组合,可能有具体规定,关于你必须如何处理,以及你可以做什么。
  • 收集数据的位置,存储位置以及关于谁。
    • 不同地区(国家等)通常有不同的规定。

这些法规中的大部分更直接地应用于数据集的收集,存储和发布,但是方面也适用于数据集的使用,包括公开可用的数据集。可用数据集通常具有使用数据的用户协议,特别是,尝试从数据集中识别个体可能至少打破用户协议,和/或是非法的(取决于数据的性质),基于消费者和研究主体保护法。

研究标准

为研究目的收集和使用的数据,有自己的一套指导方针和要求,关于人类主体治疗以及数据收集,储存,使用和传播。除其他外,这些法规的重点是人类主体的自决权,同意收集哪些数据,以及如何使用这些数据。为研究目的而收集的数据必须遵循基于这些同意程序的限制。

研究根据赫尔辛基宣言进行保护。

HIPAA - 保护健康相关信息

健康保险流通与责任法案(HIPAA)是美国联邦政府的一项法规,规范和保护了个人医疗记录和健康相关数据。它包括如何存储数据,以及如何使用和共享数据的条款。

美国联邦政府官方 HIPAA 信息指南包含 HIPAA 的概述。

安全港方法

安全港是如何处理具有个人数据的数据集的官方协议,特别是从数据集中删除哪些信息,来对其进行匿名化的具体指导。它是在许多环境和国家之间共享的一组数据保护要求。

安全港的官方文档包含如何匿名数据的指南。

安全港方法要求删除个人或亲属,雇主或家庭成员的以下标识符:

  • 姓名
  • 小于州的地理细分
  • 日期(如出生日期等),以及所有年龄超过 90 岁的人
  • 电话号码
  • 车辆识别号码
  • 传真号码
  • 设备标识符和序列号
  • 电子邮件地址
  • Web 统一资源定位器(URL)
  • 社会安全号码
  • 互联网协议(IP)地址
  • 医疗记录编号
  • 生物标识符,包括手指和声纹
  • 健康计划受益人数量
  • 全脸照片和任何类似的图像
  • 帐号
  • 证书/许可证号码
  • 任何其他唯一标识号,特征或代码

**邮政编码的前三个数字可以保留,前提是超过 20,000 人居住在所有邮政编码覆盖的区域,这些邮政编码共享相同的初始三位数(相同的地理细分)。

唯一标识符

逻辑安全港(和/或一般数据匿名化)是删除可用于识别你的任何唯一信息。

对于像名字这样的事情来说,这可能是最明显的,但是一些看似不那么明显的安全港规范,也与这个想法有关,将指定信息留在数据集中,具有识别数据集中包含的个体的风险。

例如,虽然谈论住在洛杉矶的 37 岁男性可能是无害的(因为有许多候选人,没有透露特定的个人),但谈到约有一名 37 岁的男性居住在加利福尼亚州的波特雷罗,这个小镇约有 700 人,可能真的很明显。 这与 90 岁以上的人被移除的原因相同 - 即使在相当大的地区,假设圣地亚哥,一位 98 岁的女性参与者可能是相当明显的。

基本上 - 任何让你脱颖而出的信息都有可能识别你,所以匿名试图从数据中删除这些特质,这样个人就不会以某种方式让人知道他们是谁。

这也是在面对多个数据源时保护数据的难度基线,因为收集观测结果使得更容易更加独特地挑选个体 - 因此从洛杉矶识别出 37 岁的男性,可能仍然相对容易,如果你也碰巧知道(或弄清楚)他有一只 5 英尺 6 英寸的狮子狗,在加州大学洛杉矶分校工作,并于 4 月 15 日星期六在格里菲斯公园,通过组合公开可用的或易于获得的数据,所有这些都可能相对容易来弄清楚。

九、使用 Python 进行数据可视化

原文:Data Visualization with Python

译者:飞龙

协议:CC BY-NC-SA 4.0

数据可视化可能意味着不同的东西。

在这里,我们将使用 Matplotlib 来处理基本的 2D 绘图,Matplotlib 是一个 Python 绘图库。

Matplotlib 非常支持一些示例,你可以用来弄清楚它是如何工作的。

在这里,我们将浏览 matplotlib 的快速介绍,其中的示例改编自官方资料。

数据可视化是一种“查看”数据,用于数据探索和数据通信的方法。

查看 matplotlibs 官方网站,包括他们的介绍教程,以及示例列表。

Pyplot vs Pylab

请注意,matplotlib 是一个旧的,非常庞大的模块,实际上有几种不同的方式来使用它。

简短版本:导入matplotlib.pyplot,就像我们在这里做的,或许是最常见的,并且会起作用!

长版本:请按照以下链接了解可以使用 matplotlib 的不同方式(pyplot,pylab 等)。

最终,它都调用相同的底层代码来访问所有内容,只是语法不同。

与 matplotlib 交互的不同方法的描述,在这里

# 导入 matplotlib - 主要的 Python 绘图模块
import matplotlib.pyplot as plt

# 导入 numpy 函数来为绘图生成测试数据
import numpy as np
from numpy.random import rand

# 这个魔术命令直接在笔记本中绘制图形
%matplotlib inline
# 这为图形设置了更高的分辨率
%config InlineBackend.figure_format = 'retina'

折线图

# 让我们创建一些假数据来绘制
x = np.arange(0, 11)
y = x**2

# 在 matplotlib 中,我们可以制作一个图形,然后绘制它
# 生成图形
f = plt.figure()
# 要绘图,只需将 x 和 y 数据传递给绘图函数即可
plt.plot(x, y)

# [<matplotlib.lines.Line2D at 0x119df8710>]

png

没有任何其他信息,默认情况下 matplotlib 将添加许多绘图属性。

例如,默认情况下,我们获得了图表周围的线条,刻度线以及轴编号标签。

我们可以自定义所有这些内容,并为绘图添加更多内容。

散点图

让我们尝试创建一个散点图。让我们想象两组数据,我们想要在散点图上一起绘制来进行比较。

# 创建一些数据
n = 50                   # n 是数据点的数量
x = rand(n)              # 随机创建 x 数据点
y1 = rand(n)             # 随机创建 y 数据点的第一组
y2 = rand(n)             # 随机创建 y 数据点的第二组

创建散点图

scatter命令与plot命令的工作方式大致相同,但是会生成散点图而不是直线。

在这里,我们添加另一个参数c,它指定了点的颜色

我们可以向plotscatter添加许多可选参数

# 绘制第一组数据
plt.scatter(x, y1, c='blue')
# 我们现在想在同一个图上绘制第二组数据。
# 'hold' 命令告诉 Python 保持当前图形并向其添加下一个数据。
plt.hold
# 绘制第二组数据
plt.scatter(x, y2, c='red')

# <matplotlib.collections.PathCollection at 0x11aac7d68>

png

我们现在有一个散点图!

但是,它看起来不太好。 让我们看看我们是否可以改进它。让我们尝试添加大量的自定义函数来制作更好的图形。

# 创建新的图形
fig = plt.figure()
# 向图形添加轴域
ax = plt.axes()

# 再次绘制数据
ax.scatter(x, y1, c='blue', alpha=0.6, label='Group 1', s=50)
plt.hold
ax.scatter(x, y2, c='red', alpha=0.6, label='Group 2', s=50)
# 这里我们添加了一些可选参数。
# alpha - 设置数据点的透明度
# label - 为我们绘制的数据制作标签,可以在图例中使用
# s - 大小。 改变我们绘制的点的大小

# 向我们的图形添加标题
plt.title('My Awesome Scatter Plot', fontsize=18, fontweight='bold')

# 添加数据标签
plt.xlabel('X Data Label', fontsize=16, fontweight='bold')
plt.ylabel('Y Data Label', fontsize=16, fontweight='bold')

# 设置范围来绘制 x 和 y 变量
plt.xlim([-0.1, 1.1])
plt.ylim([-0.1, 1.1])

# 设置刻度标签
ax.set_xticks(np.array([0.0, 0.2, 0.4, 0.6, 0.8, 1.0]))
ax.set_yticks(np.array([0.0, 0.2, 0.4, 0.6, 0.8, 1.0]))

# 关闭顶部和右侧边线
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)

# 将刻度线设置为仅位于底部和左侧。
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')

# 设置剩余刻度的线宽
ax.spines['left'].set_linewidth(2)
ax.spines['bottom'].set_linewidth(2)

# 添加图例。这将使用你在设置数据时定义的标签。
plt.legend(loc='upper left', scatterpoints=1, frameon=False)
# 图例不需要任何参数。
# 在这里,我们可以选择指定图例的位置('loc'),
# 图例中使用的点数('scatterpoints'),
# 以及图例周围是否有一个框('frameon')。

# <matplotlib.legend.Legend at 0x11a655cf8>

png

数字和轴域

请注意,有时我们在ax上调用这些函数,有时我们用plt调用

我们还创造了一个叫做fig的东西 这一切是什么?

  • plt只是 matplotlib 模块的昵称
    • 在这里,当我们使用plt时,我们在当前图中隐式地从 matplotlib 调用一个函数
  • fig只是我们分配给图形对象的任意变量名。
    • 我们可以在创建它之后使用fig(或我们称之为图形)来更新它
  • ax也只是当前轴域的任意变量名。
    • 我们可以使用ax(或者我们称之为轴域),在我们创建它之后更新特定的轴域
# 'fig'是我们正在制作的图形的标签。
# gcf() 是找到当前图形的方式
print(type(fig))             # Figure 是 matplotlib 中的一个对象
print(fig)                   # 这是我们之前制作的图形的句柄 'fig'
print(plt.gcf(), '\n')       # gcf 引用了当前的图形。在这种情况下,当前图形与 'fig' 相同

'''
<class 'matplotlib.figure.Figure'>
Figure(432x288)
Figure(432x288) 

<matplotlib.figure.Figure at 0x117779588>
'''


# 'ax' 是当前轴域的名称。一个图形可以有很多个轴域(图形可以有子图)
print(type(ax))              # Axes 是 matplotlib 中的一个类
print(ax)                    # 这是我们之前制作的轴域的句柄 'ax'
#print(plt.gca(), '\n')      # gca 引用了当前轴域。

# 在这种情况下,当前轴是'ax'。在绘制轴时关闭。
# 请注意,这里 gca 绘制一个空轴。

'''
<class 'matplotlib.axes._subplots.AxesSubplot'>
Axes(0.125,0.125;0.775x0.755)
'''

跟踪图形和轴域,并知道调用什么,最初可能有点混乱。

请注意,很多内容都是在幕后进行管理的 - 你没有明确创建新的图形或轴域。Matplotlib 将在需要时创建新的数字和轴域,而无需明确告知。

如果你想知道为什么我们会纠结于使用figax

  • 我们通常不需要,但是在需要的时候,让标签引用我们的图形(并操纵它)会非常有用。

例如,我们可以通过访问它的名称来获取我们的图形。

# 用 'fig' 变量名称重绘图
fig

png

除官方文档外,还有另一个有用的教程在这里

十、分布

原文:Distributions

译者:飞龙

协议:CC BY-NC-SA 4.0

概率分布反映了函数/数据源的可能结果的发生概率。

这是维基百科上的概率分布。如果你想要更全面地了解概率/分布,请查看此文章

%matplotlib inline

import numpy as np
import matplotlib.pyplot as plt

概率分布

通常,给定数据源,我们想要考虑并检查我们的数据样本似乎遵循什么样的概率分布。更具体地说,我们试图推断出数据生成器遵循的概率分布,提出一个问题:它可以用什么函数代替?

检查数据的分布很重要,因为我们通常希望对我们的数据应用统计测试,并且许多统计测试都带有关于它们所应用的数据分布的基本假设。 确保我们应用适当的统计方法,需要考虑并检查数据的分布。

非正式地,我们可以从可视化我们的数据开始,看看它的形状是什么,以及它看起来遵循哪种分布。更正式地说,我们可以统计测试数据样本是否遵循特定分布。

在这里,我们将开始可视化一些最常见的分布。 Scipy(scipy.stats)有一系列代码和函数,用于处理和生成不同的分布 - 所有这些都具有一致的 API。我们将从不同的基础分布生成合成数据,并快速查看它们的外观,绘制生成数据的直方图。

你可以使用此笔记本来探索不同的参数,来了解这些分布。为进一步探索,绘制每个分布的概率密度函数。

均匀分布

均匀分布是一种分布,其中每个可能的值是同等可能的。

这是维基百科上的均匀分布。

from scipy.stats import uniform


dat = uniform.rvs(size=10000)


plt.hist(dat);

png

正态分布

正态(也称为高斯或“钟形曲线”)分布是由其均值和标准差定义的分布。

维基百科 上的正态分布。

from scipy.stats import norm


dat = norm.rvs(size=10000)


plt.hist(dat, bins=20);

png

伯努利分布

伯努利分布是二元分布 - 它只需要两个值(0 或 1),概率为p

维基百科上的伯努利分布.

from scipy.stats import bernoulli


r = bernoulli.rvs(0.5, size=1000)


plt.hist(r);

png

Gamma 分布

Gamma 分布是由两个参数定义的连续概率分布。

维基百科上的 Gamma 分布。

给定不同的参数,伽玛分布可能看起来非常不同。探索不同的参数。

指数分布在技术上是 Gamma 分布的一个特例,但也在 scipy 中单独实现为expon

from scipy.stats import gamma


dat = gamma.rvs(a=1, size=100000)


plt.hist(dat, 50);

png

Beta 分布

Beta 分布是在区间[0,1]上定义的分布,由两个形状参数定义。

维基百科上的 Beta 分布。

from scipy.stats import beta


dat = beta.rvs(1, 1, size=1000)


plt.hist(dat, 50);

png

泊松分布

在给定已知平均速率(和独立出现)的情况下,泊松分布建模了固定时间间隔的事件。

维基百科上的泊松分布。

from scipy.stats import poisson


dat = poisson.rvs(mu=1, size=100000)


plt.hist(dat);

png

十一、检验分布

原文:Testing Distributions

译者:飞龙

协议:CC BY-NC-SA 4.0

有时,正式检验你观察到的某些数据是否遵循特定分布,可能是有用的(或必要的)。

也许最常见的是,如果你使用假定数据具有特定分布的统计检验,则需要测试是否确实如此。

# 导入
%matplotlib inline

import numpy as np
import matplotlib.pyplot as plt

import scipy.stats as stats
from scipy.stats import normaltest


# 设置一个辅助函数,用于在 alpha 水平上检查 p 值和打印结果
def check_p_val(p_val, alpha):

    if p_val < alpha:
        print('We have evidence to reject the null hypothesis.')
    else:
        print('We do not have evidence to reject the null hypothesis.')

在这里,我们将关注最常见的情况:测试数据集是否正态分布。

# 创建正态分布的数据集
d1 = stats.norm.rvs(size=100000)


# 绘制观测数据的直方图
# 如果数据是正态分布的,则包括预期分布,具有相同的数据均值和标准。
xs = np.arange(d1.min(), d1.max(), 0.1)
fit = stats.norm.pdf(xs, np.mean(d1), np.std(d1))
plt.plot(xs, fit, label='Normal Dist.', lw=3)
plt.hist(d1, 50, normed=True, label='Actual Data');
plt.legend();

png

# 在 scipy 中,“normaltest” 函数测试样本是否与正态分布不同
# 零假设是数据是正态分布的。
# 我们可以使用 normaltest 来检查这个原假设  - 我们是否必须拒绝原假设(断定数据不是正态)。
# 它使用观察数据的偏斜和峰度的组合统计量,与正态分布下的预期相比。
normaltest?


# 在数据集上执行正态测试
stat, p_val = normaltest(d1)


# 检查 normaltest 的 p 值
print('\nNormaltest p value is: {:1.2e} \n'.format(p_val))

# 当 alpha 值为 0.05 时,我们应该如何处理
check_p_val(p_val, alpha=0.05)

'''
Normaltest p value is: 1.34e-01 

We do not have evidence to reject the null hypothesis.
'''

不同分布

视觉检查数据集可以让你快速了解它们是否正态分布。

然而,视觉检查是不够的,并且可能会产生误导,因为非正态数据可能“看起来正态”。

除了在看起来很正态时查看检查数据,执行其他检查也很重要。

例如,在一些参数下,Beta 分布的数据看起来通常是正态的。

# 从 beta 分布生成一些数据
d2 = stats.beta.rvs(7, 10, size=100000)


# 绘制观测数据的直方图
plt.hist(d2, 50, normed=True, label='Actual Data');
plt.legend();

png

如上所示,我们可能认为这些数据看起来非常正态,基于可视化。

但是,我们可以做更具体的检查。

# 在它是正态分布的假设下,用预期分布绘制数据。
# 如果数据是正态的,蓝线是预期的数据密度,具有相同的平均值和标准差。
xs = np.arange(d2.min(), d2.max(), 0.01)
fit = stats.norm.pdf(xs, np.mean(d2), np.std(d2))
plt.plot(xs, fit, label='Normal Dist.', lw=3)
plt.hist(d2, 50, normed=True, label='Actual Data');
plt.legend();

# 请注意,在绘制 PDF 时,我们可以看到某些差异
# 但是,如果你关闭 PDF 图,我们可能会猜测这些数据看起来是正态的

png

# 在数据集上执行正态测试
stat, p_val = normaltest(d2)


# 检查 normaltest 的 p 值
print('\nNormaltest p value is: {:1.2e} \n'.format(p_val))

# 当 alpha 值为 0.05 时,我们应该如何处理
check_p_val(p_val, alpha=0.05)

'''
Normaltest p value is: 2.17e-184 

We have evidence to reject the null hypothesis.
'''

非正态数据

在这个例子中,图形是不确定的,但“正态测试”表明这些数据实际上不太可能来自正态分布。

在这种情况下,我们碰巧知道这确实是正确的,因为数据的“基本事实”是它们是从 beta 分布生成的。

因此,在期望正态分布输入的统计测试中使用此数据是无效的,因为我们违反了这些测试所基于的假设。我们将不得不使用不同的方法来对这些数据进行统计比较。

检验其它分布

更一般地,你可以使用 Kolmogorov-Smirnov 测试,来检查一组数据是否具有(你指定的)其他分布。

此测试在 scipy 中实现,你可以使用它进行探索。

from scipy.stats import kstest


# 检查 kstest 的文档
kstest?

kstest形式与normaltest类似,在这种情况下,我们将数据样本与指定的分布进行比较。

零假设是数据来自指定的分布。

如果我们拒绝零假设,并使用一些预设的 alpha 值,我们可以得出结论,数据不符合所检验的分布。

# 让我们继续使用上面的数据,来自 beta 分布。
# 我们可以确认 kstest 认为它不是正态分布的
stat, p_val = kstest(d2, 'norm')
print('Statistic: \t{:1.2f} \nP-Value: \t{:1.2e}\n'.format(stat, p_val))
check_p_val(p_val, alpha=0.05)

'''
Statistic: 	0.56 
P-Value: 	0.00e+00

We have evidence to reject the null hypothesis.
'''


# 现在将数据与 beta 分布进行比较。
# 请注意,在这种情况下,我们必须为我们正在测试的 beta 分布指定一些参数
stat, p_val = kstest(d2, 'beta', [7, 10])
print('Statistic: \t{:1.2f} \nP-Value: \t{:1.2e}\n'.format(stat, p_val))
check_p_val(p_val, alpha=0.05)

'''
Statistic: 	0.00 
P-Value: 	1.69e-01

We do not have evidence to reject the null hypothesis.
'''

十三、普通最小二乘

原文:Ordinary Least Squares

译者:飞龙

协议:CC BY-NC-SA 4.0

普通最小二乘法(OLS)意味着最小化模型做出的预测与观测数据之间的平方和的误差。

维基百科上查找有关 OLS 的更多信息,请查看这个很酷的互动工具和/或查看在 Python 中执行 OLS 的教程

普通最小二乘

普通最小二乘可以被认为是一个误差函数 - 在给定数据的情况下,我们形式化计算模型的误差的方式。

通常,我们希望最小化此误差项。因此,例如线性模型的 OLS 解,是具有最小平方误差值的模型,其被计算为数据点的模型预测与数据点本身之间的差的平方。

在这里,我们将创建一个最小数据集,并使用 OLS 探索将简单线性模型拟合到他。

# 导入
%matplotlib inline

import random
import numpy as np
import matplotlib.pyplot as plt


# 创建一些数据
# x 是等间隔的整数数组
x = np.arange(0, 6)

# y 是一些数据,底层关系为 y = (theta) * x
# 对于这些示例,数据的真实关系为 y = 2x
true_rel = 2
y = true_rel * x

# 向 y 添加一些噪声
noise = np.random.normal(0, 0.5, len(x))
y = y + noise


# 绘制数据
f = plt.figure()
plt.plot(x, y, '.');

png

观察上面的数据,我们可以看到xy之间存在某种关系,但我们想要一种方法来衡量这种关系是什么。OLS 是这样做的过程:找到最小化每个观测数据点与模型预测之间的平方距离的模型(在本例中为直线)。

# 重塑数据来适配 NumPy
x = np.reshape(x, [len(x), 1])
y = np.reshape(y, [len(y), 1])

Numpy 为我们提供了计算 OLS 解的函数。 在这种情况下,我们拟合模型:

y = θ x

请注意,我们在这里没有拟合截距(没有b值,如果你想到y = ax + b)。 在这个简单的模型中,我们隐含地假设截距值为零。你可以使用 OLS 调整截距(以及具有更多参数的线性模型),你只需将它们添加到其中即可。

# 使用 numpy 拟合(普通)最小二乘最佳直线
# 这给了我们拟合值(theta)和残差(我们在这个拟合中有多少误差)
theta, residuals, _, _ = np.linalg.lstsq(x, y)

# 从数组中拉出 theta 值
theta = theta[0][0]


# 检查 OLS 产生的 θ 解什么:
print(theta)

# 1.98695402961


# 检查我们的 OLS 解有多好
print('The true relationship between y & x is: \t', true_rel)
print('OLS calculated relationship between y & x is: \t', theta)

'''
The true relationship between y & x is: 	 2
OLS calculated relationship between y & x is: 	 1.98695402961
'''


# 检查残差是什么
residuals[0]

# 1.3701226131131277


# 绘制原始数据,具有真实的基础关系,以及 OLS 拟合
fig, ax = plt.subplots(1)
ax.plot(x, y, 'x', markersize=10, label='Data')
ax.plot(x, 2*x, '--b', alpha=0.4, label='OLS Fit')
ax.plot(x, theta*x, label='True Fit')
ax.legend();

png

# 使用我们的模型,我们可以预测新的 'x' 数据点的值
new_x = 2.5
pred_y = theta * new_x
print('The prediction for a new x of {} is {:1.3f}'.format(new_x, pred_y))

# The prediction for a new x of 2.5 is 4.967


ax.plot(new_x, pred_y, 'or')
fig

png

# 我们还可以看到,我们观察到的所有点,模型预测了什么
preds = theta * x


# 残差是模型拟合与观测数据点之间的平方和
# Re-calculate the residuals 'by hand'
error = np.sum(np.subtract(preds, y) ** 2)


# 检查我们的残差计算是否与 scipy 实现相匹配
print('Error from :', residuals[0])
print('Error from :', error)

'''
Error from : 1.37012261311
Error from : 1.37012261311
'''

注意:在实践中,你不会将 numpy 用于 OLS。其他模块,如statsmodels,拥有更明确用于线性建模的 OLS 实现。

请参阅“LinearModels”笔记本和/或 StatsModels 中的 OLS

十四、线性模型

原文:Linear Models

译者:飞龙

协议:CC BY-NC-SA 4.0

线性(回归)建模是一种方法,将输出值预测为输入值的加权线性组合。

线性模型 - 概述

在最简单的情况下,我们试图拟合一条线,因此我们的模型具有以下形式:

y = ax + b

在上面的这个等式中,我们试图从一些其他数据变量x预测一些数据变量y,其中b是参数,我们需要通过拟合模型得出,并分别反映 模型(直线)的斜率和y`轴截距。

我们需要一些过程来寻找ab。 我们将使用 OLS 这样做 - 我们想要的ab的值是那些满足 OLS 解的值 - 也就是使模型预测与我们的数据之间距离最小的值。

请注意,你需要xy已知的数据,以便训练你的模型。

该方法也可以推广,包括例如使用更多特征来预测我们感兴趣的输出。

因此,我们将以一般形式重写我们的模型,如下所示:

y = a0 + a1 x1 + a2 x2 + ... + an xn + ε

在上面的等式中,a0是截距(与上面的b相同),a1an是我们正在尝试学习的n个参数,因为数据的权重为x1xn。我们的输出变量(我们试图预测的)仍然是y,我们引入了ε,这是误差,它基本上捕获了无法解释的变动。

线性模型实战

在下文中,我们将生成一些数据,其中两个特征D1D2是相关的。

鉴于相关性,我们可以尝试从D1预测D2的值,我们将创建一个线性模型来实现。

使用上面第二种表示法,模型将采用以下形式:

D2 = a0 + a1 * D1 
# 导入 
%matplotlib inline

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# Statmodels & patsy
import patsy
import statsmodels.api as sm


# 生成一些互相关数据

# 设置
corr = 0.75
covs = [[1, corr], [corr, 1]]
means = [0, 0]

# 生成数据
dat = np.random.multivariate_normal(means, covs, 1000)


# 查看我们生成的数据
plt.scatter(dat[:, 0], dat[:, 1], alpha=0.5);
#plt.scatter(dat[:, 0], dat[:, 1], alpha=0.5);

png

# 将数据放入 DataFrame
df = pd.DataFrame(dat, columns=['D1', 'D2'])


# 观察数据
df.head()
D1 D2
0 0.305994 0.521119
1 0.262456 0.562350
2 -0.289970 0.608496
3 0.025279 0.523315
4 -0.561126 -1.320507
# 检查 D1 和 D2 之间的相关性(它与合成的东西匹配)
df.corr()
D1 D2
D1 1.000000 0.747094
D2 0.747094 1.000000

Statsmodels & Patsy 的线性模型

Statsmodels 是 Python 中统计分析的模块。 Patsy 是一个有用的包,用于处理和描述统计模型。

这里是 statsmodelspatsy 的官方文档。

# Patsy 为我们提供了一种构建设计矩阵的简便方法
# 出于我们的目的,“设计矩阵”只是我们的预测变量和输出变量的有组织矩阵
outcome, predictors = patsy.dmatrices('D2 ~ D1', df)

如果检查“结果”和“预测变量”的类型,你会发现它们是DesignMatrix类型的自定义 patsy 对象。

如果你将它们打印出来,你会看到它们重置了 Pandas SeriesDataFrames

你可以将它们视为自定义的类数据帧对象,以便将其组织成用于建模的矩阵。

# 现在使用 statsmodels 初始化 OLS 线性模型
# 此步骤初始化模型,并提供数据(但实际上不计算模型)
mod = sm.OLS(outcome, predictors)

请注意,statsmodels,就像我们稍后会遇到的 scikit-learn 一样,使用面向对象的方法。

在这种方法中,你初始化将数据和方法存储在一起的复杂对象,为你提供有组织的方式来存储和检查数据和参数,拟合模型,然后甚至使用它们进行预测等等。

# 检查我们刚刚创建的模型对象的类型。
# 你还可以使用 tab 补全,来探索此对象的可用内容
type(mod)

# statsmodels.regression.linear_model.OLS


# 最后,拟合模型
res = mod.fit()


# 检查结果
print(res.summary())

'''
==============================================================================
Dep. Variable:                     D2   R-squared:                       0.558
Model:                            OLS   Adj. R-squared:                  0.558
Method:                 Least Squares   F-statistic:                     1261.
Date:                Tue, 06 Mar 2018   Prob (F-statistic):          3.32e-179
Time:                        00:18:34   Log-Likelihood:                -993.04
No. Observations:                1000   AIC:                             1990.
Df Residuals:                     998   BIC:                             2000.
Df Model:                           1                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
Intercept      0.0011      0.021      0.054      0.957      -0.039       0.042
D1             0.7546      0.021     35.506      0.000       0.713       0.796
==============================================================================
Omnibus:                        1.644   Durbin-Watson:                   1.970
Prob(Omnibus):                  0.440   Jarque-Bera (JB):                1.508
Skew:                          -0.068   Prob(JB):                        0.470
Kurtosis:                       3.133   Cond. No.                         1.05
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
'''

解释输出

Statsmodels 为我们提供了大量信息!

最上面的部分主要是元数据:它包括模型类型,运行它的时间和日期等内容。

它还包括 R 方,它是模型能够捕获的方差量的总体汇总。这个值在 0-1 之间,约为 0.5 ,我们在这里看到,是一个非常高的值,表明模型拟合良好。

中间一列是实际的模型结果。

每行反映一个参数,并给出它的值(coef),误差(std err),统计检验结果,关于该参数是否是输出变量的显着预测值(t,其中相关的 p 值为'P > | t |),以及参数值的置信区间([0.025 - 0.975]`)。

最后一个模型包括对数据运行的一些其他测试,可以帮助你检查输入数据的某些描述符,以及它们是否满足这种模型拟合的必要条件。

检查我们的模型

就模型本身而言,最有用的组件位于第二行,其中摘要给出了参数值,以及我们的预测变量的 p 值,在这种情况下是InterceptD2

从上面的结果中,我们可以获取参数的值,并获得以下模型:

D2 = -0.0284 + 0.7246 * D1

但是,我们还应该记住报告的统计测试,参数值是否显着(显着不同于零)的测试。使用 0.05 的 alpha 值,在这种情况下,D2参数值是显着的,但Intercept值不是。由于Intercept的参数值与零没有显着差异,我们可以决定不将它包含在我们的最终模型中。

因此,我们完成了模型:

D2 = 0.7246 * D1

有了这个模型,a1的值很可能为 0.7246,非常接近数据点的相关值,我们将其设置为 0.75!

## 绘制模型的拟合直线

# 绘制原始数据(像之前一样)
plt.scatter(df['D1'], df['D2'], alpha=0.3, label='Data');

# 生成和绘制模型的拟合直线
xs = np.arange(df['D1'].min(), df['D1'].max())
ys = 0.7246 * xs
plt.plot(xs, ys, '--k', linewidth=4, label='Model')

plt.xlabel('D1')
plt.xlabel('D2')
plt.legend();

png

使用多个预测值

上面的模型只使用了一个预测值,拟合了一条简单的直线,因此实际上模仿了我们用于拟合直线的先前方法。

我们还可以拟合多个预测变量,这就是 patsy 和 statsmodel 的强大功能,因为这些函数你和更复杂的模型,包括我们想要的许多参数,也处理相关特征的某些方面,等等。

在这里,我们将向数据帧添加一个新变量,并使用两个预测变量拟合 OLS 模型。

# 向 df 添加数据的新列
df['D3'] = pd.Series(np.random.randn(1000), index=df.index)
df.head()
D1 D2 D3
0 0.305994 0.521119 0.019043
1 0.262456 0.562350 -0.631288
2 -0.289970 0.608496 0.794971
3 0.025279 0.523315 0.447560
4 -0.561126 -1.320507 -1.560199
# 从 D2 和 D3 预测 D1
outcome, predictors = patsy.dmatrices('D1 ~ D2 + D3', df)
mod = sm.OLS(outcome, predictors)
res = mod.fit()


# 检查模型拟合摘要
print(res.summary())

'''
==============================================================================
Dep. Variable:                     D1   R-squared:                       0.558
Model:                            OLS   Adj. R-squared:                  0.557
Method:                 Least Squares   F-statistic:                     630.1
Date:                Tue, 06 Mar 2018   Prob (F-statistic):          1.25e-177
Time:                        00:18:34   Log-Likelihood:                -982.91
No. Observations:                1000   AIC:                             1972.
Df Residuals:                     997   BIC:                             1987.
Df Model:                           2                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
Intercept     -0.0177      0.020     -0.866      0.387      -0.058       0.022
D2             0.7395      0.021     35.479      0.000       0.699       0.780
D3            -0.0121      0.021     -0.587      0.557      -0.052       0.028
==============================================================================
Omnibus:                        0.273   Durbin-Watson:                   1.993
Prob(Omnibus):                  0.872   Jarque-Bera (JB):                0.357
Skew:                          -0.019   Prob(JB):                        0.836
Kurtosis:                       2.916   Cond. No.                         1.04
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
'''

请注意,如上所述,statsmodels 是一种功能强大的通用 OLS 模型方法。

你可以进一步研究如何包含其他功能,例如输入变量之间的交互,等等。

sklearn 线性回归

Scikit-learn 也具有线性回归模型的实现。

在这里,我们将使用 sklearn 而不是 statsmodels,快速演示运行与上述相同的线性 OLS 模型。

sklearn 中的线性回归。

# sklearn 的线性模型
from sklearn import linear_model


# 转换数据的形状,便于 sklearn 使用
d1 = np.reshape(df.D1.values, [len(df.D1), 1])
d2 = np.reshape(df.D2.values, [len(df.D2), 1])
d3 = np.reshape(df.D3.values, [len(df.D3), 1])


# 初始化线性回归模型
reg = linear_model.LinearRegression()


# 拟合线性回归模型
reg.fit(d2, d1) #d1 = a0 + a1*d2

# LinearRegression(copy_X=True, fit_intercept=True, n_jobs=1, normalize=False)


# 检查这个结果
# 如果将这些与我们上面使用的 statsmodel 进行比较,它们确实是相同的
print(reg.intercept_[0])
print(reg.coef_[0][0])

'''
-0.0179497213127
0.739686393719
'''

(在 sklearn 中)使用多个预测变量

# 初始化并拟合线性模型
# d1 = a1*d2 + a2*d3 + a0
reg = linear_model.LinearRegression()
reg.fit(np.hstack([d2, d3]), d1)

# LinearRegression(copy_X=True, fit_intercept=True, n_jobs=1, normalize=False)


np.hstack([d2, d3]).shape

# (1000, 2)


# 检查这个结果
# 如果将这些与我们上面使用的 statsmodel 进行比较,它们确实是相同的
print('Intercept: \t', reg.intercept_[0])
print('Theta D2 :\t', reg.coef_[0][0])
print('Theta D3 :\t', reg.coef_[0][1])

'''
Intercept: 	 -0.0177498825239
Theta D2 :	 0.739473377018
Theta D3 :	 -0.0120672090985
'''

十五、聚类

原文:Clustering

译者:飞龙

协议:CC BY-NC-SA 4.0

聚类是尝试在数据中查找结构(簇)的过程。

这是来自维基百科的文章聚类分析

# 导入
%matplotlib inline

import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.cluster import KMeans
from scipy.cluster.vq import whiten

Scikit-learn 有很多示例数据集。 在这里,我们将使用鸢尾花数据集:其中包含不同植物种类的数据。

# 导入鸢尾花数据
iris = datasets.load_iris()


# 检查可用特征
print('\n'.join(iris.feature_names))

'''
sepal length (cm)
sepal width (cm)
petal length (cm)
petal width (cm)
'''


# 检查物种 ('clusters')
print('\n'.join(iris.target_names))

'''
setosa
versicolor
virginica
'''


# 实际数据存储在 iris.data 中
# 我们来看看有多少数据
[n_samples, n_features] = np.shape(iris.data) 
print("There are ", n_samples , " samples of data, each with " , n_features, " features.")

# There are  150  samples of data, each with  4  features.


# 让我们设置一些索引,以便我们知道我们正在使用哪些数据
sl_ind = 0    # 萼片长度
sw_ind = 1    # 萼片宽度
pl_ind = 2    # 花瓣长度
pw_ind = 3    # 花瓣宽度


# 让我们开始看一些数据。
# 让我们从花瓣长度与花瓣宽度的散点图开始
fig = plt.figure(1)
plt.scatter(iris.data[:, pl_ind], iris.data[:, pw_ind])

# 添加标题和标签
plt.title('Iris Data: Petal Length vs. Width', fontsize=16, fontweight='bold')
plt.xlabel('Petal Length', fontsize=14);
plt.ylabel('Petal Width', fontsize=14);

png

# 绘制数据,颜色由物种编码
fig = plt.figure(1)
plt.scatter(iris.data[:, pl_ind][iris.target==0], iris.data[:, pw_ind][iris.target==0],
            c='green', label=iris.target_names[0])
plt.scatter(iris.data[:, pl_ind][iris.target==1], iris.data[:, pw_ind][iris.target==1],
            c='red', label=iris.target_names[1])
plt.scatter(iris.data[:, pl_ind][iris.target==2], iris.data[:, pw_ind][iris.target==2],
            c='blue', label=iris.target_names[2])

# 添加标题标签和图例
plt.title('Iris Data: Petal Length vs. Width', fontsize=16, fontweight='bold')
plt.xlabel('Petal Length', fontsize=14);
plt.ylabel('Petal Width', fontsize=14);
plt.legend(scatterpoints=1, loc='upper left');

# 请注意,拆分每组的绘图基本上是一个黑魔法,为了使图例正常,
# 以下命令可以很好地绘制数据,颜色由目标编码:
# plt.scatter(iris.data[:, petal_length_ind], iris.data[:, petal_width_ind], c=iris.target)
# 然而,当以这种方式绘制时,获得带标记的图例会很痛苦

png

任务

如果我们还不知道物种标签,我们可能会注意到似乎有不同的数据点分组。聚类是尝试在算法上找到这些组的方法。

在这里,我们将使用 KMeans 算法。有关 KMeans 及其工作原理的信息,请参阅维基百科。

# 拉出感兴趣的数据 - 花瓣长度和花瓣宽度
d1 = np.array(iris.data[:, pl_ind])
d2 = np.array(iris.data[:, pw_ind])

数据白化

如果你的不同维度使用不同的单位(或具有不同的差异),则这些差异会极大地影响聚类。

这是因为 KMeans 是各向同性的:它对待每个方向上的差异同等重要。 因此,如果单位或方差非常不同,这相当于将某些特征/维度加权,使其更重要或更不重要。

为了纠正这种情况,通常,有时需要“白化”数据:通过它各自的标准偏差来标准化每个维度。

# 检查 whiten 函数
whiten?


# 白化数据
d1w = whiten(d1)
d2w = whiten(d2)


# 组合数据成某个形状,便于 skl 使用
data = np.vstack([d1w, d2w]).T


# 初始化 KMeans 对象,设置为拟合 3 个簇
km = KMeans(n_clusters=3, random_state=13)


# 使用 KMeans 拟合数据
km.fit(data)

'''
KMeans(algorithm='auto', copy_x=True, init='k-means++', max_iter=300,
    n_clusters=3, n_init=10, n_jobs=1, precompute_distances='auto',
    random_state=13, tol=0.0001, verbose=0)
'''


# 让我们看看 KMeans 找到的簇
plt.scatter(d1, d2, c=km.labels_);
plt.xlabel('Year');
plt.ylabel('Age');

# 添加标题,标签和图例
plt.title('Iris Data: PL vs. PW Clustered', fontsize=16, fontweight='bold')
plt.xlabel('Petal Length', fontsize=14);
plt.ylabel('Petal Width', fontsize=14);

png

看起来它做得很好!除了杂色和维吉尼亚边界之间的一些差异之外,仅给出关于几个特征的信息的情况下,KMeans 能够使用算法重建物种标签。

十六、降维

原文:Dimensionality Reduction

译者:飞龙

协议:CC BY-NC-SA 4.0

降维是将数据集转换为较低维空间的过程。

有关降维的解释,以及实际数据中的示例,请访问这里

降维的概述

数据集可能非常大,不仅包含数百万个数据点,还包含有关每个数据点的大量特征。 我们可以将数据集的每个特征都视为“维度”。 对于高维数据,我们可能希望或需要尝试减少这些维度。

最简单的方法可能只是放弃一些维度,我们甚至可以选择放弃看起来可能最不实用的维度。这将是一种简单的降维方法。

但通常情况下,我们希望以保留最多信息的方式减少维度的数量。 一种方法可能是聚类 - 如果我们对高维数据进行聚类分析,我们可以重新编码数据,来通过它的簇标签存储每个点,从而可能在更少的维度中维护更多信息。

在这里,我们将探索另一种降维的常用方法 - 主成分分析(PCA)。

主成分分析(PCA)是将数据集转换为主成分的过程,按捕获了多少方差排序。

有关涵盖 PCA 完整教程的论文,请访问这里。更多技术概述和解释,请查看这个博文

主成分分析

要使用 PCA 进行降维,我们可以选择保留n个成分,其中n是一个低于数据集原始维数的数字。

通过使用 PCA 转换数据并保留n个成分,我们能够在较低维空间中保持原始数据的最大方差。

最广泛地说,PCA 试图利用变量的相关结构,并使用这种结构对数据进行编码。

例如,如果我们数据的特征x1x2是相关的,那么 PCA 会查找如何将数据重新组织成一些新的维度x_pc,它捕获了两者之间的大部分共享方差(相关结构)。

在这个笔记本中,我们将遵循一个简单的 PCA 示例,使用 PCA 将数据从 2D 转换为 1D。

实际上,从m D 转换为 n D 数据,PCA 最有用,其中m非常大,而n < m

# 导入
%matplotlib inline

import numpy as np
import matplotlib.pyplot as plt

from sklearn.decomposition import PCA


## 创建一些随机的互相关数据

# 设置
means = [50, 50]
covs = [[1, .75], [.75, 1]]
n = 1000

# 生成数据
dat = np.random.multivariate_normal(means, covs, n)


# 绘制我们的两个随机变量
f, ax = plt.subplots(1, 2)
ax[0].hist(dat[:, 0]);
ax[1].hist(dat[:, 1]);

png

# 查看数据如何相互关联
plt.scatter(dat[:, 0], dat[:, 1])

# <matplotlib.collections.PathCollection at 0x1117902b0>

png

任务

假设我们想要或需要数据的较低维度表示来进行进一步分析。

虽然降维不是简单地选择维度的子集,而是在较小数量的维度中尝试从原始空间捕获最多信息的过程。

注意:这里我们将从 2D -> 1D 开始,为了简化和方便。实际上,当你有一个难以处理的大量维度,比如说 20,000,并希望将数据转换为一个较低维度的空间(捕获尽可能多的信息)时,它是最有用的,但是或许包含接近 20 个维度,可能便于管理。

在这里,我们将使用主成分分析(PCA)来降维。

# 初始化PCA模型,此处指定 1 个成分
pca = PCA(n_components=1, whiten=True)


# 拟合 PCA 模型,并应用它来转换数据
out = pca.fit_transform(dat)


# 在新空间中查看转换后的数据
# 注意:由于新数据是 1D,因此这里的 x 轴只是索引号
plt.plot(out, '.')

# [<matplotlib.lines.Line2D at 0x1118b8ef0>]

png

有关使用 Python 执行 PCA 的更深入的教程,请访问这里,有关更多技术性教程,请访问这里

十七、分类

原文:Classification

译者:飞龙

协议:CC BY-NC-SA 4.0

分类是对数据进行分类的过程 - 将数据点分配给预定义的组(或簇)。

来自维基百科的分类文章。

支持向量机

支持向量机是一种监督分类算法。

文章提供了 SVM 算法的精彩概述。这也是来自 scikit-learn 的基于代码的解释。

%matplotlib inline

import numpy as np
import matplotlib.pyplot as plt


# 从 scikit-learn 导入
from sklearn.svm import SVC
from sklearn.metrics import classification_report

概述

在此示例中,我们将生成来自两个不同(已知)组的一些二维数据,并将 SVM 分类模型应用于此数据。

# 生成一些随机数据的设置
n_points = 50
label_prop = 0.5

# 初始化数据矩阵(为零)
dat = np.zeros(shape=[n_points, 2])

# 配置每类的数据点数量
n_dat_1 = int(n_points * label_prop)
n_dat_2 = n_points - n_dat_1

# 生成数据
dat[0:n_dat_1, 0] = np.abs(np.random.randn(n_dat_1))
dat[0:n_dat_1, 1] = np.abs(np.random.randn(n_dat_1))
dat[n_dat_2:, 0] = np.abs(np.random.randn(n_dat_1)) + 2
dat[n_dat_2:, 1] = np.abs(np.random.randn(n_dat_1)) + 2

# 创建标签向量
labels = np.array([0] * n_dat_1 + [1] * n_dat_2)


# 绘制出带标签数据
fig = plt.figure(figsize=[9, 7])
plt.plot(dat[0:n_dat_1, 0], dat[0:n_dat_1, 1], 'b.', ms=12, label="Label=0")
plt.plot(dat[n_dat_2:, 0], dat[n_dat_2:, 1], 'g.', ms=12, label="Label=1")
plt.legend();

png

Scikit-Learn 对象

如上所述,我们有两组完全不同的数据。现在我们想要学习一个数学过程,可以将这些数据标记为两组,我们希望它能够学习一个可以应用于新数据点的一般过程。

在这里,我们将使用典型的 scikit-learn 方法:

  • 为我们正在使用的模型对象初始化 sklearn 对象,设置所需的参数
  • 在我们带标记的训练数据上训练模型
  • 检查我们在带标记数据上的表现(通常是训练组和单独的带标记测试组)
  • 应用模型来预测新的数据点
# 初始化 SVM 分类器对象
classifier = SVC(kernel='linear')


# 将我们的分类模型拟合到我们的训练数据
classifier.fit(dat, labels)

'''
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
  decision_function_shape='ovr', degree=3, gamma='auto', kernel='linear',
  max_iter=-1, probability=False, random_state=None, shrinking=True,
  tol=0.001, verbose=False)
'''


# 计算模型对训练数据的预测
train_predictions = classifier.predict(dat)


# 打印出表现指标
print(classification_report(train_predictions, labels))

'''
             precision    recall  f1-score   support

          0       1.00      1.00      1.00        25
          1       1.00      1.00      1.00        25

avg / total       1.00      1.00      1.00        50
'''

预测新数据点

一旦我们有一个训练好的模型,我们就可以预测新数据点的标签 - 我们不知道答案的数据。

# 设置一个新点 - 来预测标签
new_point = np.array([[3, 3]])


# 向图形添加我们的新点(红色)
fig.gca().plot(new_point[0][0], new_point[0][1], '.r', ms=12);


# 重绘图形
fig

png

# 预测新点的类别
prediction = classifier.predict(new_point)
print('Predicted class of new data point is: ', prediction[0])

# Predicted class of new data point is:  1

支持向量

SVM的一个关键特性是它们使用“支持向量”,这意味着它们优先使用靠近决策边界的数据点的信息,并使用它们来尝试找到最宽的边距 - 两组之间的距离。在这里,我们可以简单探索我们的已训练模型的支持向量。

# 向绘图添加支持向量
# 支持向量将通过用黑色圆圈突出显示
for row in classifier.support_vectors_:
    fig.gca().plot(row[0], row[1], 'ok', ms=14,  mfc='none')


# 重绘图形
fig

png

绘制决策边界

现在让我们绘制决策边界 - 我们的学习模型认为标签在组之间切换的边界。

以下代码用于查找和可视化决策边界和边距,取自 sklearn 示例

# 获取当前图,找到轴的大小
ax = fig.gca()
xlim = ax.get_xlim()
ylim = ax.get_ylim()

# 创建数据网格来评估模型
xx = np.linspace(xlim[0], xlim[1], 30)
yy = np.linspace(ylim[0], ylim[1], 30)
YY, XX = np.meshgrid(yy, xx)
xy = np.vstack([XX.ravel(), YY.ravel()]).T
Z = classifier.decision_function(xy).reshape(XX.shape)

# 绘制决策边界和边距
ax.contour(XX, YY, Z, colors='k', levels=[-1, 0, 1], alpha=0.5,
           linestyles=['--', '-', '--']);


# 重绘图形
fig

png

探索

使用上面的代码,我们鼓励你探索 SVM。

在更改数据,更改内核和预测不同数据点时,调查会发生什么。

十八、自然语言处理

原文:Natural Language Processing

译者:飞龙

协议:CC BY-NC-SA 4.0

自然语言处理(NLP)是使用计算机分析文本数据的方法。

这是维基百科上的自然语言处理。

NTLK:自然语言工具包

NLTK 是用于文本分析的主要 Python 模块。

NLTK 组织网站在这里,他们有一整本教程在这里

NLTK

NLTK 为超过 50 种语料库和词汇资源(如 WordNet)提供了易于使用的界面,以及一套用于分类,分词,词干提取,标注,解析和语义推理的文本处理库,用于工业级 NLP 库的包装器,和活跃的讨论论坛。

# 导入 NLTK
import nltk

在这个笔记本中,我们将使用 NLTK 包中的一些有用功能来完成一些基本的文本分析。

要处理文本数据,通常需要使用语料库 - 文本数据集进行比较。 NLTK 有许多这样的数据集可用,但默认情况下不会安装它们(因为它们的完整集合会非常大)。下面我们将下载其中一些数据集。

# 如果你在下面的单元格中下载时,遇到了错误
# 请返回此单元格,取消注释,然后运行此代码。
# 这段代码赋予 python 写入磁盘的权限(如果它还没有这样做的权限)。
import ssl

try:
    _create_unverified_https_context = ssl._create_unverified_context
except AttributeError:
    pass
else:
    ssl._create_default_https_context = _create_unverified_https_context


# 从 NLTK 下载一些有用的数据文件
nltk.download('punkt')
nltk.download('stopwords')
nltk.download('averaged_perceptron_tagger')
nltk.download('maxent_ne_chunker')
nltk.download('words')
nltk.download('treebank')

'''
[nltk_data] Downloading package punkt to /Users/tom/nltk_data...
[nltk_data]   Package punkt is already up-to-date!
[nltk_data] Downloading package stopwords to /Users/tom/nltk_data...
[nltk_data]   Package stopwords is already up-to-date!
[nltk_data] Downloading package averaged_perceptron_tagger to
[nltk_data]     /Users/tom/nltk_data...
[nltk_data]   Package averaged_perceptron_tagger is already up-to-
[nltk_data]       date!
[nltk_data] Downloading package maxent_ne_chunker to
[nltk_data]     /Users/tom/nltk_data...
[nltk_data]   Package maxent_ne_chunker is already up-to-date!
[nltk_data] Downloading package words to /Users/tom/nltk_data...
[nltk_data]   Package words is already up-to-date!
[nltk_data] Downloading package treebank to /Users/tom/nltk_data...
[nltk_data]   Package treebank is already up-to-date!

True
'''


# 设置一些要测试的数据的测试句子
sentence = "UC San Diego is a great place to study cognitive science."

分词

分词是将文本数据拆分为“标记”的过程,这些标记是有意义的数据片段。

分词的更多信息在这里

词可以在不同的级别完成 - 例如,你可以将文本分词为句子,和/或分词为单词。

# 在单词级别对我们的句子进行分词
tokens = nltk.word_tokenize(sentence)


# 查看单词分词后的数据
print(tokens)

# ['UC', 'San', 'Diego', 'is', 'a', 'great', 'place', 'to', 'study', 'cognitive', 'science', '.']

词性(POS)标注

词性标注是根据单词的“类型”和与其他单词的关系对单词进行标记的过程。

这里是维基百科上的词性标注。

# 对我们的句子进行词性标注
tags = nltk.pos_tag(tokens)


# 检查我们的数据的 POS 标签
print(tags)

# [('UC', 'NNP'), ('San', 'NNP'), ('Diego', 'NNP'), ('is', 'VBZ'), ('a', 'DT'), ('great', 'JJ'), ('place', 'NN'), ('to', 'TO'), ('study', 'VB'), ('cognitive', 'JJ'), ('science', 'NN'), ('.', '.')]


# 查看描述所有缩写含义的文档
nltk.help.upenn_tagset()

'''
$: dollar
    $ -$ --$ A$ C$ HK$ M$ NZ$ S$ U.S.$ US$
'': closing quotation mark
    ' ''
(: opening parenthesis
    ( [ {
): closing parenthesis
    ) ] }
,: comma
    ,
--: dash
    --
.: sentence terminator
    . ! ?
:: colon or ellipsis
    : ; ...
CC: conjunction, coordinating
    & 'n and both but either et for less minus neither nor or plus so
    therefore times v. versus vs. whether yet
CD: numeral, cardinal
    mid-1890 nine-thirty forty-two one-tenth ten million 0.5 one forty-
    seven 1987 twenty '79 zero two 78-degrees eighty-four IX '60s .025
    fifteen 271,124 dozen quintillion DM2,000 ...
DT: determiner
    all an another any both del each either every half la many much nary
    neither no some such that the them these this those
EX: existential there
    there
FW: foreign word
    gemeinschaft hund ich jeux habeas Haementeria Herr K'ang-si vous
    lutihaw alai je jour objets salutaris fille quibusdam pas trop Monte
    terram fiche oui corporis ...
IN: preposition or conjunction, subordinating
    astride among uppon whether out inside pro despite on by throughout
    below within for towards near behind atop around if like until below
    next into if beside ...
JJ: adjective or numeral, ordinal
    third ill-mannered pre-war regrettable oiled calamitous first separable
    ectoplasmic battery-powered participatory fourth still-to-be-named
    multilingual multi-disciplinary ...
JJR: adjective, comparative
    bleaker braver breezier briefer brighter brisker broader bumper busier
    calmer cheaper choosier cleaner clearer closer colder commoner costlier
    cozier creamier crunchier cuter ...
JJS: adjective, superlative
    calmest cheapest choicest classiest cleanest clearest closest commonest
    corniest costliest crassest creepiest crudest cutest darkest deadliest
    dearest deepest densest dinkiest ...
LS: list item marker
    A A. B B. C C. D E F First G H I J K One SP-44001 SP-44002 SP-44005
    SP-44007 Second Third Three Two * a b c d first five four one six three
    two
MD: modal auxiliary
    can cannot could couldn't dare may might must need ought shall should
    shouldn't will would
NN: noun, common, singular or mass
    common-carrier cabbage knuckle-duster Casino afghan shed thermostat
    investment slide humour falloff slick wind hyena override subhumanity
    machinist ...
NNP: noun, proper, singular
    Motown Venneboerger Czestochwa Ranzer Conchita Trumplane Christos
    Oceanside Escobar Kreisler Sawyer Cougar Yvette Ervin ODI Darryl CTCA
    Shannon A.K.C. Meltex Liverpool ...
NNPS: noun, proper, plural
    Americans Americas Amharas Amityvilles Amusements Anarcho-Syndicalists
    Andalusians Andes Andruses Angels Animals Anthony Antilles Antiques
    Apache Apaches Apocrypha ...
NNS: noun, common, plural
    undergraduates scotches bric-a-brac products bodyguards facets coasts
    divestitures storehouses designs clubs fragrances averages
    subjectivists apprehensions muses factory-jobs ...
PDT: pre-determiner
    all both half many quite such sure this
POS: genitive marker
    ' 's
PRP: pronoun, personal
    hers herself him himself hisself it itself me myself one oneself ours
    ourselves ownself self she thee theirs them themselves they thou thy us
PRP$: pronoun, possessive
    her his mine my our ours their thy your
RB: adverb
    occasionally unabatingly maddeningly adventurously professedly
    stirringly prominently technologically magisterially predominately
    swiftly fiscally pitilessly ...
RBR: adverb, comparative
    further gloomier grander graver greater grimmer harder harsher
    healthier heavier higher however larger later leaner lengthier less-
    perfectly lesser lonelier longer louder lower more ...
RBS: adverb, superlative
    best biggest bluntest earliest farthest first furthest hardest
    heartiest highest largest least less most nearest second tightest worst
RP: particle
    aboard about across along apart around aside at away back before behind
    by crop down ever fast for forth from go high i.e. in into just later
    low more off on open out over per pie raising start teeth that through
    under unto up up-pp upon whole with you
SYM: symbol
    % & ' '' ''. ) ). * + ,. < = > @ A[fj] U.S U.S.S.R * ** ***
TO: "to" as preposition or infinitive marker
    to
UH: interjection
    Goodbye Goody Gosh Wow Jeepers Jee-sus Hubba Hey Kee-reist Oops amen
    huh howdy uh dammit whammo shucks heck anyways whodunnit honey golly
    man baby diddle hush sonuvabitch ...
VB: verb, base form
    ask assemble assess assign assume atone attention avoid bake balkanize
    bank begin behold believe bend benefit bevel beware bless boil bomb
    boost brace break bring broil brush build ...
VBD: verb, past tense
    dipped pleaded swiped regummed soaked tidied convened halted registered
    cushioned exacted snubbed strode aimed adopted belied figgered
    speculated wore appreciated contemplated ...
VBG: verb, present participle or gerund
    telegraphing stirring focusing angering judging stalling lactating
    hankerin' alleging veering capping approaching traveling besieging
    encrypting interrupting erasing wincing ...
VBN: verb, past participle
    multihulled dilapidated aerosolized chaired languished panelized used
    experimented flourished imitated reunifed factored condensed sheared
    unsettled primed dubbed desired ...
VBP: verb, present tense, not 3rd person singular
    predominate wrap resort sue twist spill cure lengthen brush terminate
    appear tend stray glisten obtain comprise detest tease attract
    emphasize mold postpone sever return wag ...
VBZ: verb, present tense, 3rd person singular
    bases reconstructs marks mixes displeases seals carps weaves snatches
    slumps stretches authorizes smolders pictures emerges stockpiles
    seduces fizzes uses bolsters slaps speaks pleads ...
WDT: WH-determiner
    that what whatever which whichever
WP: WH-pronoun
    that what whatever whatsoever which who whom whosoever
WP$: WH-pronoun, possessive
    whose
WRB: Wh-adverb
    how however whence whenever where whereby whereever wherein whereof why
``: opening quotation mark
'''

命名实体识别(NER)

命名实体识别旨在用与相关的实体类型标记单词。

这里是维基百科上的命名实体识别。

# 将命名实体识别应用于我们的 POS 标签
entities = nltk.chunk.ne_chunk(tags)


# 查看命名实体
print(entities)

'''
(S
  UC/NNP
  (PERSON San/NNP Diego/NNP)
  is/VBZ
  a/DT
  great/JJ
  place/NN
  to/TO
  study/VB
  cognitive/JJ
  science/NN
  ./.)
'''

停止词

“停止词”是一种语言中最常见的词语,我们经常希望在文本分析之前将其过滤掉。

这里是维基百科上的停止词。

# 查看英语中的停止词语料库
print(nltk.corpus.stopwords.words('english'))

# ['i', 'me', 'my', 'myself', 'we', 'our', 'ours', 'ourselves', 'you', "you're", "you've", "you'll", "you'd", 'your', 'yours', 'yourself', 'yourselves', 'he', 'him', 'his', 'himself', 'she', "she's", 'her', 'hers', 'herself', 'it', "it's", 'its', 'itself', 'they', 'them', 'their', 'theirs', 'themselves', 'what', 'which', 'who', 'whom', 'this', 'that', "that'll", 'these', 'those', 'am', 'is', 'are', 'was', 'were', 'be', 'been', 'being', 'have', 'has', 'had', 'having', 'do', 'does', 'did', 'doing', 'a', 'an', 'the', 'and', 'but', 'if', 'or', 'because', 'as', 'until', 'while', 'of', 'at', 'by', 'for', 'with', 'about', 'against', 'between', 'into', 'through', 'during', 'before', 'after', 'above', 'below', 'to', 'from', 'up', 'down', 'in', 'out', 'on', 'off', 'over', 'under', 'again', 'further', 'then', 'once', 'here', 'there', 'when', 'where', 'why', 'how', 'all', 'any', 'both', 'each', 'few', 'more', 'most', 'other', 'some', 'such', 'no', 'nor', 'not', 'only', 'own', 'same', 'so', 'than', 'too', 'very', 's', 't', 'can', 'will', 'just', 'don', "don't", 'should', "should've", 'now', 'd', 'll', 'm', 'o', 're', 've', 'y', 'ain', 'aren', "aren't", 'couldn', "couldn't", 'didn', "didn't", 'doesn', "doesn't", 'hadn', "hadn't", 'hasn', "hasn't", 'haven', "haven't", 'isn', "isn't", 'ma', 'mightn', "mightn't", 'mustn', "mustn't", 'needn', "needn't", 'shan', "shan't", 'shouldn', "shouldn't", 'wasn', "wasn't", 'weren', "weren't", 'won', "won't", 'wouldn', "wouldn't"]

文本编码

NLP的关键组件之一是决定如何编码文本数据。

常见的编码是:

  • 词袋(BoW)
    • 文本被编码为单词和频率的集合
  • 词频-逆向文件频率(TF-IDF)
    • TF-IDF是一种加权,用于存储单词和语料库中的共性关系。

我们将浏览 BoW 和 TF-IDF 文本编码的示例。

# 导入
%matplotlib inline

# 标准 Python 有一些有用的字符串工具
import string

# 集合是标准 Python 的一部分,包含一些有用的数据对象
from collections import Counter

import numpy as np
import matplotlib.pyplot as plt

# Scikit-learn 有一些有用的 NLP 工具,例如 TFIDF 向量化器
from sklearn.feature_extraction.text import TfidfVectorizer

我们将要查看的数据是 BookCorpus 数据集的一小部分。原始数据集可在此处找到:http://yknzhu.wixsite.com/mbweb

原始数据集是从超过 11,000 本书中收集的,并且已经在句子和单词级别上进行了分词。这里提供和使用的小子集包含前 10,000 个句子。

# 加载数据
with open('files/book10k.txt', 'r') as f:
    sents = f.readlines()


# 查看数据 - 打印出第一个和最后一个句子,作为示例
print(sents[0])
print(sents[-1])

'''
the half-ling book one in the fall of igneeria series kaylee soderburg copyright 2013 kaylee soderburg all rights reserved .

alejo was sure the fact that he was nervously repeating mass along with five wrinkly , age-encrusted spanish women meant that stalin was rethinking whether he was going to pay the price .
'''


# 预处理:从句子中删除所有额外的空格
sents = [sent.strip() for sent in sents]

我们首先看一下文档中的单词频率,然后打印出频率最高的前 10 个单词。

# 将所有句子分词为单词
# 这会将所有单词标记收集到一个大的列表中
tokens = []
for x in sents:
    tokens.extend(nltk.word_tokenize(x))


# 查看数据中有多少单词
print('Number of words in the data: \t', len(tokens))
print('Number of unique words: \t', len(set(tokens)))

'''
Number of words in the data: 	 140060
Number of unique words: 	 8221
'''


# 使用“计数器”对象计算每个单词出现的次数
counts = Counter(tokens)


# 查看计数对象
# 这基本上是这个语料库的“词袋”表示
# 我们失去了单词顺序和语法 - 它只是单词的一个集合
# 我们所拥有的是所有单词的列表,以及它们出现的频率
counts

如果你滚动上面的单词列表,你可能会注意到的一点是,它仍然包含标点符号。我们删除那些。

# 'string' 模块(标准库)有一个有用的标点符号列表
print(string.punctuation)

# !"#$%&'()*+,-./:;<=>?@[$$^_`{|}~


# 从计数对象中删除所有标点符号标记
for punc in string.punctuation:
    if punc in counts:
        counts.pop(punc)


# 获得前 10 个最常用的单词
top10 = counts.most_common(10)


# 提取顶部单词,并计数
top10_words = [it[0] for it in top10]
top10_counts = [it[1] for it in top10]


# 绘制文本中最常用单词的条形图
plt.barh(top10_words, top10_counts)
plt.title('Term Frequency');
plt.xlabel('Frequency');

png

正如我们所看到的,文档中出现了thewasa等等。

对于弄清楚这些文档的内容,或者作为使用和理解这些文本数据的方式,这些经常出现的单词并不是很有用。

# 丢弃所有停止词
for stop in nltk.corpus.stopwords.words('english'):
    if stop in counts:
        counts.pop(stop)


# 获取删除停止词的数据中,前 20 个最常用单词
top20 = counts.most_common(20)


# 绘制文本中最常用单词的条形图
plt.barh([it[0] for it in top20], [it[1] for it in top20])
plt.title('Term Frequency');
plt.xlabel('Frequency');

png

这看起来可能更相关/有用。我们可以继续探索这个 BoW 模型,但现在让我们转向,并使用 TFIDF 进行探索。

# 初始化 TFIDF 对象
tfidf = TfidfVectorizer(analyzer='word',
                        sublinear_tf=True,
                        max_features=5000,
                        tokenizer=nltk.word_tokenize)


# 将 TFIDF 转换应用于我们的数据
# 请注意,这会接受句子并对其进行分词,然后应用 TFIDF
tfidf_books = tfidf.fit_transform(sents).toarray()

TfidfVectorizer 将计算每个单词的逆文档频率(IDF)。

然后 TFIDF 计算为TF * IDF,用于降低频繁出现的单词的权重。该 TFIDF 存储在tfidf_books变量中,该变量是一个n_documents x n_words矩阵,用于以 TFIDF 表示来编码文档。

让我们首先为前 10 个最常出现的单词(来自第一次分析)中的每一个绘制 IDF。

# 获取前 10 个最常用单词的 IDF 权重
IDF_weights = [tfidf.idf_[tfidf.vocabulary_[token]] for token in top10_words]


# 绘制非常常见的单词的 IDF 得分
plt.barh(top10_words, IDF_weights)
plt.title('Inverse Document Frequency');
plt.xlabel('IDF Score');

png

我们将该绘图与以下绘图进行比较,该绘图显示 IDF 最高的前 10 个单词。

# 获得 IDF 得分最高的单词
inds = np.argsort(tfidf.idf_)[::-1][:10]
top_IDF_tokens = [list(tfidf.vocabulary_)[ind] for ind in inds]
top_IDF_scores = tfidf.idf_[inds]


# 绘制 IDF 得分最高的单词
plt.barh(top_IDF_tokens, top_IDF_scores)
plt.title('Inverse Document Frequency');
plt.xlabel('IDF Score');

png

正如我们所看到的,与更罕见的单词相比,文档中经常出现的单词获得的 IDF 分数非常低。

在 TF-IDF 之后,我们成功地减少了文档中频繁出现的单词的权重。这允许我们通过最独特的单词来表示文档,这可以是表示文本数据的更有用的方式。

附录一、有用的 Python 数据科学包

原文:Useful Python Packages for Data Science

译者:飞龙

协议:CC BY-NC-SA 4.0

以下是 Python 中可能对数据科学有用的包一般概述。

有关更广泛/更全面的 Python 生态系统列表,请查看 Awesome Python 列表。

数据科学模块

这些包都包含在 anaconda 发行版中。

核心包

  • scipy - 数学,科学和工程。
  • numpy - 数组和数组运算的数值计算。
  • pandas - 数据结构和数据分析。
  • scikit-learn - 机器学习和数据分析。

文本挖掘

  • nltk - 自然语言处理。
  • gensim - 主题建模。

数学和统计学

网络爬虫

可视化库

图论/网络

深度学习

  • theano - 多维数组的数学运算。
  • tensorflow - 使用数据流图进行数值计算。
  • keras - 高级神经网络库。

标准库的有用部分

标准库中的完整软件包列表在这里

基本工具

  • os - 杂项操作系统操作。
  • sys - 系统操作。
  • datetime - 日期时间操作。
  • glob - 搜索路径名称。

实用函数

  • math - 数学函数。
  • random - (伪)随机数生成器。
  • re - 正则表达式。

文件格式

  • json - 支持处理 JSON 文件。
  • csv - 支持处理 CSV 文件

数据对象

  • collections - 容器数据类型。
  • pickle - 序列化和反序列化(保存和加载复杂对象)。

附录二、git/Github 版本控制工具

原文:Version Control with git/Github

译者:飞龙

协议:CC BY-NC-SA 4.0

版本控制反映了一组与管理文件相关的实践,特别是管理不同版本的文件。

你可以在维基百科 git 文档上阅读版本控制的更多信息。

Git 是一个版本控制系统:一种在多个位置跟踪文件变化的工具。

点击访问 git。Git 是一个开源软件项目。

Github 是基于 Web 的 Git 版本,以及版本控制仓库或互联网托管服务。这是一个地方,放置使用 git 跟踪的代码。

点击 Github。注意 Github 是一家公司。

Git 图形用户界面(GUI)

有几种方法可以使用 git,包括:

  • 从命令行输入命令
  • 使用图形程序启动 git 命令
    • 这种程序被称为“图形用户界面”(GUI)。
    • 它基本上只是意味着,你可以单击按钮来执行操作,而不是写出命令

无论哪种方式,底层命令和执行的代码都是相同的。在幕后,这一切都归约为同样的事情。

你应该使用你最熟悉的方法。如果你已经了解了一些命令行编程,那么从命令行使用 git 会很有用,因为通常会有更多功能可供你使用,具有更具体的控制。如果你对命令行不是很熟悉,那么使用 GUI 要简单得多。

如果你打算使用 GUI,我们建议你使用 SourceTree。

SourceTree 教程文档可在此处获得。

本地 VS 远程

git 主要做的是保持同一个存储库的两个(或更多)版本一致。

存储库只是文件的集合,就像计算机上的文件夹。

我们将这些副本称为:

  • “本地”副本,它是计算机上存储库的副本(对你而言是“本地”副本)
  • “远程”副本,它是其他地方的存储库的副本,例如在 Github 上

通常有一个特定的代码副本称为master,这意味着它是相关存储库的主版本。最典型的情况是,这是 Github 上代码的副本 - 因此 Github 上有一个master代码副本,并且一个或多个人也有本地代码副本,并带有本地更新。当想要共享本地更新时,可以将它们发送给master,以便为每个人更新代码的主要版本。

在这里,我们将考虑上面描述的,具有两个存储库副本的情况。 这里描述的内容都可以扩展到代码的多个副本,包括存储库的多个不同远程副本。

作为版本控制系统,git 的主要功能是自动检查存储库的每个副本中的所有文件,跟踪发生的任何更改。然后,它提供了工具,在有变化时在不同副本之间进行同步。

从 Github 获取代码

最典型的是,Github 上有可用的代码,你希望获得本地副本,使用代码并可能更新代码,然后将更新发送回 Github。

首先,你需要获取代码的本地副本。Git 将生产存储库的副本称为clone

从命令行,要将 Github 存储库克隆到你的计算机,请使用带有存储库 URL 的clone命令。

  • $ git clone 'repo_url'

跟踪和传播更改

获得连接到远程存储库的本地副本后,更改可以分为两个方向:

  • 将你在本地进行的更改发送到远程
  • 使用远程更改更新本地副本

从本地 -> 远程跟踪和发送更改

处理本地文件时,git 有多个“级别”。这些多个级别可用于组织更改,放入组织良好的操作中。

典型的工作流程是:

  • 添加add:选择你希望 git 跟踪哪些文件的哪些更改
    • 你可以将多个文件一起添加,每个文件都有自己的更改
  • 提交commit:创建一个检查点,保存添加到一起的所有文件
    • 这些更改将与更改内容的消息(提交日志)一起“保存”
  • 推送push:将更改发送到遥控器

首先,在本地 git 存储库中,你对文件进行了一些更改。

你现在可以添加文件。这需要针对我们要记录的,每个你更改的文件进行:

  • $ git add 'f_name'

添加一个或多个文件后,使用提交commit保存这些文件的状态:

  • $ git commit -m 'Commit message'

-m标志是直接使用命令编写提交消息的选项。如果你不添加它,git 会把你送到一个文本编辑器,你可以在那里写提交消息。你应始终添加已更改/添加内容的信息性消息。

通过详细消息进行小的,增量的更改和提交,通常意味着你的 Github 日志可以作为项目的历史记录,跟踪你已完成的工作。

如果一切突然损坏,这也允许你回退到旧版本的代码。

提交的更改仍存储在本地副本中。要更新远程存储库,你必须推送:

  • $ git push

你不必在每次提交后推送,git push可以同时推送许多提交。

从远程获取更改 -> 本地

Git 使用pull(拉取)来指代,使用来自远程副本的更改更新本地副本。

在命令行上,如果远程分支上有更改,请使用git pull将这些更改复制到本地。

  • $ git pull

Git 速查表

最常见的 git 功能是:

  • git status
    • 检查 git 存储库的状态
  • git add 'file'
    • 将文件添加到暂存区域
  • git commit -m 'message'
    • 在暂存区域中记录所有更改的“保存点”。
  • git push
    • 将提交复制到远程
  • git diff 'file'
    • 检查自上次提交以来文件中的更改
  • git clone 'repo'
    • 创建 git 存储库的本地副本
  • git pull
    • 从远程更新 git 存储库的本地副本

高级 Git:分支和合并

Git 还有许多其他功能,包括分支合并,当你习惯使用 git 并着手更大的项目时,值得探索它。

外部资源和教程

有许多使用 Github 的教程,包括交互式教程Hello World,两者都是由 Github 制作的。还有其他一些有用的指南和教程,包括 LifeHackerAtlassianneuroplausible 上提供的这些指南和教程。

posted @ 2026-03-26 12:19  布客飞龙III  阅读(3)  评论(0)    收藏  举报