数据科学入门第25章:数据科学前瞻

IPython, 高效的工作环境,允许你创建将文本、Python 动态代码和可视化相结合的“日记本”(notebook),你可以将它们与别人共享,或仅仅保存为自己的日志 NumPy,即“Numeric Python”,对很多其他的库来说,NumPy 是个基础构件,这是它特别值得学习的原因。 pandas提供了处理Python 数据集的更多的数据结构。它主要的抽象概念是DataFrame,在内容上与我们在第23 章中构建的 NotQuiteABase table 类很相似,但是有更多的功能和更好的性能。如果你打算用Python 修改、分划、分组或操作数据集,pandas 是一个非常有用的工具。 scikit-learn可能是Python 中处理机器学习问题最常用的库。它包括我们用过的所有模型以及很多我们没用过的模型。在真实的问题上,你无需从零开始建立决策树,而是可以使用scikit-learn 来做繁重的工作。在真实的问题上,你也无需手动写出优化算法,而是可以依靠scikit-learn 使用已有的优秀算法。scikit-learn 的文档包括了许许多多案例来说明它可以做什么(或者,更一般地,说明机器学习可以做什么)。 我们创建过的matplotlib 图形很清晰而且功能强大,但它还不够美观(而且一点交互性也没有)。如果想深入了解数据可视化,你可以有多种选择。 第一种是深入学习matplotlib,因为我们涉及的内容只是它的一小部分。在它的网站上有许多关于它的功能的例子,还有一些更有趣的可视化的图库。如果你打算创建静态的可视化(比如想把它印在书里),这可能是你下一步最好的选择。你也应该试试seaborn,这是一个可 以使matplotlib 更有吸引力(还有其他很多优点)的库。 如果你想创建那种可以在网络上分享的交互式可视化,D3.js是首选,它 是一个可用于创建“数据驱动文档”(data driven documents,名称中的“3D”便由此得来) 的JavaScript 库。即使你不太懂JavaScript,通常也可以从D3 的图库中找到可以模仿的例子,并套用到你的数据上。(好的数据科学家从D3 的图库中复制例子,出色的数据科学家从D3 的图库中“偷”例子。)即使你对D3 一点兴趣也没有,仅仅浏览一下它的图库也能学到不少关于数据可视化的东西。 Bokeh是一个把D3 风格的功能整合到Python 中的项目。 可以作为起点的数据源: Data.gov是政府开放数据的门户网站。如果你想找任何和政府有关的数据(现在看这可能涉及方方面面的事情),它是个很好的开始。 reddit 上有r/datasets和r/data两个论坛,是一个可以请求数据和发现数据的地方。 Amazon.com 上有一些公用数据集,它希望你能使用它的产品来分析这些数据集(但你可以用任何你想用的产品来分析)。 Robb Seaton 的博客上有一个富有创意的专业数据集的列表。 Kaggle是一个举办数据科学竞赛的网站。 Hacker News是一个聚集并讨论与技术相关的新闻的网站。它收集了大量文章,但很多对作者来说并不有趣。因此,数年之前,作者着手建立了一个Hacker News 的内容分类器来预测作者是否喜欢某篇给定的文章。这项工作涉及对大量文章的手动标注(为了建立训练集),选择文章的特征(比如标题中的单词和链接的域),以及训练一个和之前我们做过的垃圾邮件检测类似的朴素贝叶斯分类器。 消防车:作者生活在西雅图市中心的一条主要街道上,这条街是从一个消防站去往城市里大多数火灾(或者看起来疑似火灾)的必经之地。由此,多年来作者产生了对西雅图消防部门的兴趣。幸运的是(从数据的观点),消防部门运行着一个实时的911 网站,上面列出了每一次火警状况和出动的消防车。所以,为了满足作者的兴趣,作者抓取了多年的火警数据并执行了关于消防车的社交网络分析,这就要求作者创造了一个特定的关于消防车的中心性的概念,作者称之为TruckRank。 T恤:作者有一个小女儿,她的童年有一件令作者感到十分沮丧的事情,就是“女孩的T 恤”大都很单调乏味,而“男孩的T 恤”却都充满趣味。尤其是,作者觉得出售给男童和女童的T 恤之间有很明显的区别。所以作者问自己能不能训练一个模型来识别这些区别。剧透:作者能。这项工作包括下载数百件T 恤的图案,把它们改成同样的尺寸,再把它们转换为像素颜色的向量,最后使用逻辑回归建立分类器。一种看起来较为简单的方法是针对每件T 恤的颜色分类;第二种方法是找到T 恤颜色向量的前10 个主成分,然后把每件T 恤投影到由10 个“特征T 恤”(eigenshirt)1 所组成的10维空间上进行分类. 作者联系方式:

数据科学入门第9章:获取数据

写作本书我用了三个月的时间;构思只用了三分钟;而收集书中的数据,则用了我的一生。 ——F. 斯科特· 菲兹杰拉德 To write it, it took three months; to conceive it, three minutes; to collect the data in it, all my life. —F. Scott Fitzgerald 为了成为一名数据科学家,你需要数据。事实上,作为数据科学家,你会花超大一部分时间来获取、清理和转换数据。必要时,你总可以自己输入数据(或者可以让你的助手来做),但通常这样做比较浪费时间。 stdin和stdout 如果在命令行运行Python 脚本,你可以用sys.stdin 和sys.stdout 以管道(pipe)方式传递数据。 先贴三个脚本的源代码: # -*- coding: utf-8 -*- """ Created on Sat Feb 15 11:51:07 2017 @author: dshowto.com # 文件 egrep.py 的源代码 # 实际上, unix系统里许多内置的命令行工具(比如egrep) """ # 以下脚本运行于命令行, 按行读入文本,然后划分出和一个正则表达式匹配的行 import sys, re # sys.argv是命令行参数的列表 # sys.argv[0]是程序自己的名字 # sys.

数据科学入门第8章:梯度下降

夸耀自己血统者,实际上夸耀的是他们对别人的亏欠。 ——塞内加 Those who boast of their descent, brag on what they owe to others. —Seneca 从事数据科学工作时,常常会面临这样的需要:为某种特定的情形寻找最佳模型。“最佳”常常会被解读为某种类似于“最小化模型残差”或者“最大化数据的可能性”。换句话说,它代表了优化某种问题的解决方案。 这意味着我们需要解决一连串的最优化问题。尤其是,我们需要从零开始解决问题。我们采用的方法是一种叫作梯度下降(gradient descent)的技术,适合从零开始逐步解决问题。 梯度下降的思想 假设我们拥有某个函数f,这个函数输入一个实数向量,输出一个实数。一个简单的例子如下: def sum_of_squares(v): # 计算向量 v 的各个元素的平方和 """computes the sum of squared elements in v""" return sum(v_i ** 2 for v_i in v) 我们常常需要最大化(或最小化)这个函数。这意味着我们需要找出能计算出最大(或最小)可能值的输入v, 即为了输出最大化(或者最小化)的目的,我们需要寻找对应的输入. 图:用梯度下降法计算最小点 对我们的函数来说,梯度(在微积分里,这表示偏导数向量)给出了输入值的方向,在这个方向上,函数增长(或者说变化?)得最快。 相应地,最大化函数的算法首先从一个随机初始点开始,计算梯度,在梯度方向(这是使函数增长最快的一个方向)上跨越一小步,再从一个新的初始点开始重复这个过程。同样,你也可以在相反方向上逐步最小化函数. 这种算法三种可能的结果: 1.如果一个函数有一个全局最小点,那么这个方法很可能会找到它。 2.如果这个函数有多个(局部)最小点,那么这种方法可能找不到这个点,但你可以通过多尝试一些初始点来重复运行这个方法。 3.如果一个函数没有最小点,也许计算会陷入死循环。 估算梯度 如果f 是单变量函数,那么它在x 点的导数衡量了当x 发生变化时,f(x) 变化了多少。导 数通过差商的极限来定义(其中h 趋近于0): def difference_quotient(f, x, h): return (f(x + h) - f(x)) / h 实际这就是在求单变量函数的导数, 很多函数对应的导数可以直接用手算求出对应的公式,也可以用程序近似求出.

数据科学入门第7章:假设与推断

深谙统计之道,方为人中之龙。 ——萧伯纳 It is the mark of a truly intelligent person to be moved by statistics. —George Bernard Shaw 数据科学的科学部分,乃是不断针对我们的数据和生成数据的机制建立假设和检验假设。 统计假设检验 作为数据科学家,我们常常需要检验某个假设是否成立。 有时,假设是诸如“这枚硬币是均匀的”,“数据科学家喜欢Python 胜过R”或“如果人们点开某个突然弹出的小广告,广告的关闭按钮又小又难找,那么大家更倾向于离开这个页面,压根不会阅读”等可以被翻译成统计数据的断言。 在各种各样的假设之下,这些统计数据可以理解为从某种已知分布中抽取的随机变量观测值,这可以让我们对这些假设是否成立做出论断。 典型的步骤是这样的,首先我们有一个零假设(H_0),它代表一个默认的立场,而替代假设(H_1) 代表我们希望与零假设对比的立场。我们通过统计来决定我们是否可以拒绝(H_0),即判断它是否错误。通过举例能更直观地说明这个过程。 案例:掷硬币 假设有一枚硬币,我们试图判断它是否均匀,即任何一面朝上的可能性是否相等。 首先,假设硬币落地后正面朝上的概率为p,所以我们的零假设为硬币均匀,即p=0.5。我们要对比替代假设p≠0.5 来检验这个假设。 具体来说,首先掷硬币n 次,将出现正面朝上的次数记为X。每次掷硬币都是一次伯努利 试验,意味着X 是二项式随机变量Binomial(n,p),(正如第6 章中所讲到的)可以用正态 分布来拟合. 本章源代码 # -*- coding: utf-8 -*- """ Created on Sat Feb 13 15:32:07 2017 @author: dshowto.com """ from matplotlib import pyplot as plt from collections import Counter import random import math # 上一章的两个函数 normal_cdf() 以及其逆运算 inverse_normal_cdf() #正态分布的累积分布函数计算 def normal_cdf(x, mu=0,sigma=1): return (1 + math.

数据科学入门第6章:概率

The laws of probability, so true in general, so fallacious in particular. —-Edward Gibbon 如果对概率论和相关的数学原理理解得不够多,从事数据科学工作就极其困难。概率理论无处不在。 我们可以把概率论视为对从事件空间中抽取的事件的不确定性进行量化的一种方式。空间是指所有可能的结果的集合。这些结果的任何一部分就是一个事件(event),比如,“骰子掷出的点数为1”,“骰子掷出的点数是偶数”等都是事件。 我们用P(E) 来标记“事件E 的概率”。 不独立和独立 泛泛地讲,如果E 发生意味着F 发生(或者F 发生意味着E 发生),我们就称事件E 与事件F 为不相互独立(dependent)。反之,E 与F 就相互独立(independent)。 从数学角度讲, 事件E 和事件 F 独立意味着两个事件同时发生的概率等于它们分别发生的概率的乘积: P(E, F)=P(E)P(F) 条件概率 如果事件E 与事件F 独立,那么定义式如下: P(E, F)=P(E)P(F) 如果两者不一定独立(并且F 的概率不为零),那么E 关于F 的条件概率式如下: P(E|F)=P(E, F)/P(F) 条件概率可以理解为,F 发生情况下,E 会发生的概率. 更常用的公式是上式的变形,实际这种变形也更容易理解: P(E, F)=P(E|F)P(F) E,F同时发生的概率 = F 发生的概率乘以 F发生情况下 E会发生的概率. 如果E 和F 独立,则上式应该表示为: P(E|F)=P(E) 这个数学公式意味着,F 是否发生并不会影响E 是否发生的概率。 关于一个有两个孩子(性别未知)的家庭的有趣例子 如果我们假设:

数据科学入门第5章:统计学

事实如磐石,统计似蒲草(中文版翻译) —- 马克吐温 Facts are stubborn, but statistics are more pliable.(事实是死的,统计是活的) —Mark Twain 统计学是我们赖以理解数据的数学和技术.这是一个庞大繁荣的领域,要用图书馆的一整个书架(甚至一整间屋子)的书来阐述. 对于任何数据, 描述数据的最简单方式是用数据本身来描述, 对于足够小的数据集来说,这可能是最好的方式,但对于庞大的数据集来讲, 需要用统计来提炼和表达数据的相关特征. num_friends = [100,49,……] 为了计算中位数,需要对数据排序, 并且随着数据的变化, 中位数有可能剧烈变化, 也可能不变,也可能变化很小. 相对于中位数, 均值的计算更简单,并且均值会随着数据的变化而平稳的变化. 均值对于异常值(过大或者过小的值)非常敏感,中位数对异常值不敏感. 如果异常值没有代表性或者为不良数据(质量差的数据), 那么计算出来的均值会误导我们. 所以均值和中位数一起使用来理解数据的中心位置情况相对更合理. 不排序而快速计算中位数的算法(本书认为不容易理解): https://en.wikipedia.org/wiki/Quickselect 离散度是数据的离散程度的一种度量, 相关的统计值越小,表示数据越聚集,离散程度越小. 计算样本方差为啥分母用 n-1 而不是 n,可参考: https://www.zhihu.com/question/20099757 极差和标准差都存在类似均值计算中对异常值敏感的问题. 对于极差,更加稳健的方案是计算75%分位数和25% 分位数之差来替代极差计算. 协方差(covariance)这个概念是和方差对应的:方差衡量的是单个变量对均值的偏离程度, 而协方差是衡量两个变量对均值的串联偏离程度,计算程序: # 协方差 # de_mean计算的是样本值和样本均值的差, 即偏差 deviations # dot() 是对应元素相乘后再求和 def covariance(x, y): n = len(x) return dot(de_mean(x), de_mean(y)) / (n - 1) 如果向量x 和 向量y 的对应元素同时大于或者同时小于他们各自序列的均值, 那么将为求和的结果贡献一个正值,否则贡献一个赋值.

数据科学入门第4章:线性代数

线性代数在数据科学家中应用很广. 网上部分线性代数学习资源 UC Davis 提供的线性代数学习资源 Linear Algebra, from UC Davis https://www.math.ucdavis.edu/~linear/ Linear Algebra, from Saint Michael’s College http://joshua.smcvt.edu/linearalgebra/ 进阶读物,可以挑战一下:Linear Algebra Done Wrong http://www.math.brown.edu/~treil/papers/LADW/LADW.html SciPy linear algebra module http://docs.scipy.org/doc/scipy/reference/tutorial/linalg.html 线性代数是数学的一个分支, 研究向量空间. 抽象的讲,向量是指可以加总(以生成新的向量),可以乘以标量(数字),也可以生成新的向量的对象. 具体的讲,向量是有限维空间的点. 即使平时我们没有把数据看做向量, 将数值数据表示为向量也是非常好的处理方式. 向量以分量方式(componentwise)做运算. 矩阵是一个二维数据集合,可以用列表的列表表示,每个内部列表的大小一样,表示矩阵的一行, A[i][j] 表示第i行第j列的元素.按照数学表达的惯例,通常用大写字母表示矩阵. 矩阵的重要性不言而喻, 如下列出了部分原因: 可以通过将每个向量看成矩阵的一行,来用矩阵表示一个包含多维向量的数据集 可以用一个 n * k 的矩阵表示一个线性函数,实现将一个k维的向量映射到一个n维的向量上.我们使用的很多技术和概念都隐含着这样的函数. 可以用矩阵表示二维关系. 如:用A[i][j] = 1 表示节点i 和节点j有关系,用A[i][j] = 0 表示节点i 和节点j没关系 本章源代码 # -*- coding: utf-8 -*- """ Created on Sat Feb 10 10:50:07 2017 @author: dshowto.

数据科学入门第3章:可视化数据

我相信可视化是实现个人目标的最有力的手段之一. —- 哈维麦凯 创建可视化很容易,创建优秀的可视化却很难. 数据可视化的两个主要用途: 探索数据 交流数据 除了matplotlib, 该章提到的其他几个可视化的库 Seaborn 基于matplotlib构建,可以更轻松的制作更漂亮也更复杂的可视化. Seaborn is a Python visualization library based on matplotlib. It provides a high-level interface for drawing attractive statistical graphics. http://seaborn.pydata.org/index.html D3.js 一个JavaScript 库, 可以制作精致的基于网络的交互可视化.虽然不是基于 Python 的, 但应用广泛,值得了解. D3.js is a JavaScript library for manipulating documents based on data. D3 helps you bring data to life using HTML, SVG, and CSS. D3’s emphasis on web standards gives you the full capabilities of modern browsers without tying yourself to a proprietary framework, combining powerful visualization components and a data-driven approach to DOM manipulation.

数据科学入门第2章:Python速成(进阶内容)

直接上进阶内容部分的源代码: # -*- coding: utf-8 -*- """ Created on Sat Feb 9 16:38:07 2017 @author: dshowto.com """ from collections import Counter import random from functools import partial from functools import reduce print('\n*********************') print('Python 速成(2):进阶内容 ') print('*********************\n') print('\n######################') print('列表排序 ') print('######################\n') # sort 与 sorted # sort 是列表的一个方法,会直接在原来的列表上排序,列表本身会改变 # sorted 是一个BIF 内置函数, 参数是原列表, 返回值是一个新列表, 原列表不变 # sort,sorted 默认顺序都是从小到大, reverse 默认值为 False, 可以指定为 True 从大小排序 x = [4,1,3,2] y = sorted(x) print("y",y) print("x",x) x.

数据科学入门第2章:Python速成(基础内容)

直接上基础内容部分的源代码: # -*- coding: utf-8 -*- """ Created on Sat Feb 4 21:55:07 2017 @author: dshowto.com """ from time import clock from collections import defaultdict from collections import Counter print('\n*********************') print('Python 速成(1):基础内容 ') print('*********************\n') print('\n######################') print('函数 ') print('######################\n') # python 中函数是第一类对象 # 函数名字是函数对象的引用,函数名可以赋值给变量,可以作为参数传递给函数,可以作为函数的返回值从函数中返回 def double(x): return x * 2 def apply_to_one(f): # 用 参数 1 对 函数 f 进行调用 return f(1) my_double = double # 变量名 my_double 指向之前定义的函数 double, 可以做类似如下注释的测试 ''' type(double) Out[29]: function type(my_double) Out[30]: function id(double) Out[31]: 209430728 id(my_double) Out[32]: 209430728 ''' x = apply_to_one(my_double) print('x = ', x) #2 # lambda函数也叫匿名函数,即,函数没有具体的名称,而用def创建的方法是有名称的 y = apply_to_one(lambda x:x + 4) print('y = ', y) #5 another_double = lambda x : 2 * x x = apply_to_one(another_double) print('x = ', x) #2 print('\n######################') print('字符串 ') print('######################\n') #用 r'string' 表示原始字符串 tab_string = '\t' not_tab_string = r'\t' print(len(tab_string)) print(len(not_tab_string)) print('\n######################') print('异常处理 ') print('######################\n') try: 0/0 except ZeroDivisionError: print('零不能作为除数') print('\n######################') print('列表 ') print('######################\n') # 列表是一个有序集合, 和其他语言中的数组概念类似,但列表对象增加了一组函数功能 # in 操作用来确认列表成员, 每次调用都会遍历列表, 如果列表很大, 会很费时间 # 下面测试可以看到查找列表开头和结尾确认列表成员消耗的时间相差很大 listToTest = list(range(10000)) def t1(theList): return 1 in theList def t2(theList): return 10000 in theList print('=== 列表的 in 操作性能测试 ===') start=clock() for i in range(1000):t1(listToTest) finish=clock() print ('t1',finish-start) start=clock() for i in range(1000):t2(listToTest) finish=clock() print ('t2',finish-start) print('\n######################') print('字典 ') print('######################\n') # 根据字典的 key,可以用[] 调用其 value, 如果 value 不存在, 会报错: print('=== 根据字典 key 调用 value 测试 ===') dictTest = {1:'hello',2:'world'} try: temp = dictTest[3] except KeyError: print('字典不存在该 key') # 可以用get方法, 并指定key 不存在时的返回值, 不指定的情况下返回值为 None temp = dictTest.