带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

点击查看第一章
点击查看第三章

第2章 数据化运营的数据来源

“巧妇难为无米之炊”,对于数据工作者来说数据便是所有工作的基础。企业的数据化运营的数据来源复杂,从数据结构类型看,包括结构化和非结构化数据;从数据来源看,既有导出的数据文件、数据库等常见来源,又有流式数据、API等复杂系统接口和外部资源;从数据格式来看,有普通文本、视频格式、音频格式等。
本章将从数据类型和数据来源两个方面介绍数据化运营的数据来源,在第3部分我们还会简单介绍有关读取非结构化数据集的知识,包括网页抓取数据、文本、图像、视频、语音等,用来进行数据化的整体数据资源的整合。

2.1 数据化运营的数据来源类型

数据化运营的数据来源类型包括数据文件、数据库、API、流式数据、外部公开数据和其他来源等。

2.1.1 数据文件

数据文件就是存储数据的文件,广义上,任何文件中存储的信息都可以称为数据;狭义上,数据文件中是以数字或文本形式存储的结构化的数据记录,本节的范围指的是后者。
结构化数据文件大多来源于数据库,例如,从MySQL中导出2017年1月4日到2017年10月21日的订单明细数据并存储为csv文件;也有系统或工具的工作过程或返回结果,例如,Windows版本的Tesseract文字识别后的结果会存储到txt文本文件中。
数据文件常见的数据格式类型既包括txt、csv、tsv、xls、xlsx等常规格式,也包括xml、html、doc、sql等非常规数据格式。文件格式取决于数据处理需求,也受限于来源系统的导出格式。如图2-1所示为使用Navicat 9.0.10连接MySQL 5.7.21支持导出的数据格式。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

大多数情况下,txt(任意指定分隔符)、csv(以逗号分隔的数据文件)、tsv(以Tab制表符分隔的数据文件)是最常用的数据文件格式。不同的工具对于文件打开的性能支持有差异,在查看数据时,当数据文件大小在百兆级别以下时,可以使用Excel等工具打开;数据文件大小在百兆级别时,推荐使用Notepad打开;当数据文件大小在G级别时,推荐使用UltraEdit打开。

2.1.2 数据库

数据库(DataBase)是按照数据结构来组织、存储和管理数据的仓库。数据库广泛应用于CMS(内容管理系统)、CRM(客户关系管理系统)、OA(办公自动化)、ERP(企业资源计划)、财务系统、DSS(决策支持系统)、数据仓库和数据集市、进销存管理、生产管理、仓储管理等各类企业运营事务之中。
数据库的主要应用包括数据的定义、存储、增加、删除、更新、查询等事务型工作,数据传输、同步、抽取、转换、加载等数据清洗工作,数据计算、关联查询、OLAP等分析型工作,以及数据权限控制、数据质量维护、异构数据库和多系统通信交互等工作。
数据库按类型可分为关系型数据库和非关系型数据库(又称为NoSQL数据库)。关系型数据库在企业中非常常见,尤其在传统企业中更为流行,常见的关系型数据库包括DB2、Sybase、Oracle、PostgreSQL、SQL Server、MySQL等。非关系型数据库是随着企业经营场景的多样化以及大数据场景而出现的,根据应用场景和结构分为以下几类。

  • 面向高性能并发读写的键值(Key-Value)数据库:优点是具有极高的并发读写性能,查找速度快,典型代表是Redis、Tokyo Cabinet、Voldemort。
  • 面向海量文档的文档数据库:优点是对数据要求不严格,无须提前定义和维护表结构,典型代表为MongoDB、CouchDB。
  • 面向可扩展性的列式数据库:优点是查找速度快,可扩展性强,通过分布式扩展来适应数据量的增加以及数据结构的变化,典型代表是Cassandra、HBase、Riak。
  • 面向图结构的图形数据库(Graph Database):优点是利用图结构相关算法,满足特定的数据计算需求,例如最短路径搜寻、关系查询等,典型代表是Neo4J、InfoGrid、Infinite Graph。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

2.1.3 API

API(Application Programming Interface)是应用程序编程接口,在数据化运营中的API通常分为服务型API和数据型API。
服务型API可以基于预定义的规则,通过调用API实现特定功能。例如,通过调用百度地图JavaScript API可以在网站中构建功能丰富、交互性强的地图应用,这种API下输入的是地理位置数据,从API获得的输出是可视化地图(服务/功能)。
数据型API则通过特定的语法,通过向服务器发送数据请求,返回特定格式的数据(或数据文件)。例如,通过向Google Analytics的Analytics Reporting API V4发送请求来获得符合特定条件的数据记录。
API广泛应用于企业内部和外部多系统和平台交互。API返回的数据格式,大多数情况下是JSON、XML格式。
JSON是一种轻量级的数据交换格式,由流行的JavaScript编程语言创建,广泛应用于Web数据交互。JSON格式简洁、结构清晰,使用键值对(Key:Value)的格式存储数据对象。Key是数据对象的属性,Value是数据对象属性的对应值。例如,“性别”:“男”就是一个键值对结构的数据。JSON格式数据示例如下:

{
    "category": {
        "name": "电脑",
        "brands": {
            "brand": [
                "DELL",
                "THINKPAD"
            ]
        }
    }
}

XML是可扩展标记语言,提供了统一的方法来描述和交换独立于应用程序或供应商的结构化数据,这是一种非常成熟且强大的数据格式。像JSON一样,XML提供了非常好的扩展性,API的创建者可以使用它们创建自己的数据结构。XML格式数据示例如下:

<?xml version="1.0" encoding="utf-8"?>
<category>
    <name>电脑</name>
    <brands>
        <brand>DELL</brand>
        <brand>THINKPAD</brand>
    </brands>
</category>

2.1.4 流式数据

流式数据指的是实时或接近实时的时效性处理的大数据流。常见的流式数据处理使用Spark、Storm和Samza等框架,能在毫秒到秒之间完成作业,用于处理应用时效性较强的场景,例如在线个性化推荐系统、网站用户实时行为采集和分析、物联网机器日志实时分析、金融实时消费反欺诈、实时异常人员识别等,应用领域集中在实时性较强的互联网和移动互联网、物联网等。
按照数据对象来区别,流式数据可分为两类:
第1类是用户行为数据流。用户行为数据流是围绕“人”产生的数据流,包括用户在网站和App内部因浏览、搜索、评论、分享、交易以及在外部的微博、微信中操作而产生的数据流。用户行为数据流采集平台可分为Web站、移动站和App(包含iOS、Android、Windows等)应用。Web站及基于HTML5开发的移动应用都支持JS脚本采集,较早开发的不支持JS的Wap站(现在基本上很少)则采用NoScript方法,即一个像素的硬图片实现数据跟踪。SDK是针对App提供数据采集的特定方法和框架。这3种方法可以实现目前所有线上用户行为数据采集的需求。
第2类是机器数据流。机器数据流是围绕“物”产生的数据流,包括从机器的生产、制造、应用、监控和管理等过程中产生的所有数据,例如机器运行日志、传感器监控数据、音频采集器数据、监控图像和视频、GPS地理数据等。
机器数据流通常集中在工业4.0、智能工厂等工业的智能运营管理过程中,也出现在物联网、人工智能等人和物的监控、识别、联通、互动等智能化应用中。机器数据流扮演着实时采集目标对象属性、状态、行为、信号等数据的角色。

2.1.5 外部公开数据

外部公开数据指公开的任意第三方都能获取的数据。
数据化运营所需的外部公开数据来源渠道众多,常见的来源包括:

  • *和相关机构提供的公开数据,例如国家统计局提供的月度CPI数据。
  • 竞争对手主动公开的数据,例如通过新闻发布会、网络宣传等渠道发布的数据。
  • 行业协会或相关平台组织提供的统计、资讯数据,例如艾瑞提供的行业研究报告发布的数据。
  • 第三方的组织或个人披露的与企业运营相关的数据,例如有关竞争对手的供应商、客户等数据。

2.1.6 其他来源

在某些场景下,企业数据化运营所用数据还会有其他来源,例如通过调研问卷获得的有关产品、客户等方面的数据,从第三方平台直接购买的数据,通过与其他厂商合作所得的交互数据等。由于这些场景比较少,并且不是企业主流的数据获取来源,在此不过多阐述。

2.2 使用Python获取运营数据

使用Python获取数据,目前主要的应用方法集中在文本文件、Excel文件、关系型和非关系型数据库、API、网页等方面。本节就来介绍具体获取方法。

2.2.1 从文本文件读取运营数据

1.使用read、readline、readlines读取数据
Python可以读取任何格式的文本数据,使用Python读取文本数据的基本步骤如下。
(1)定义数据文件
定义数据文件即定义要读取的文件,该步骤不是必需的,可以跟“获取文件对象”整合。但为了后续操作的便捷性、全局数据对象的可维护性以及减少代码冗余,建议读者养成习惯,将数据文件预先赋值给一个对象。
定义文本数据文件的方法是:
file_name = [文件名称]
示例:
file_name = 'd:/python_data/data/text.txt'
文件名称中可以只写文件名,此时默认Python读取当前工作目录下的文件;也可以加入路径,默认使用斜杠,尤其是Windows下要注意用法。
(2)获取文件对象
获取文件对象的意义是基于数据文件产生对象,后续所有关于该数据文件的操作都基于该对象产生。
语法:
file object = open(name , mode)
参数如下。
name:要读取的文件名称,即上一个环节定义的file_name,必填。
mode:打开文件的模式,选填。在实际应用中,r、r+、w、w+、a、a+是使用最多的模式。完整文件打开模式如表2-1所示。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

buffering:文件所需的缓冲区大小,选填;0表示无缓冲,1表示线路缓冲。
返回:
通过open函数会创建一个文件对象(file object)。
示例:
file_name = 'text.txt'
file_object = open(file_name)
在“定义数据文件”部分提到,可以将前两个环节结合起来,定义的语法是:
file_object = open('text.txt')
(3)读取文件内容
Python基于文件对象的读取分为3种方法,如表2-2所示。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

示例,在“附件-chapter2”文件夹中有一个名为text.txt的数据文件,其中包含2个文本行,数据内容如图2-2所示。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

通过read方法读取该数据文件得到的数据结果如下:
'line1: This is line1nline2: This is line2'
通过readline方法读取该数据文件得到的数据结果如下:
'line1: This is line1n'
通过readlines方法读取该数据文件得到的数据结果如下:
['line1: This is line1n', 'line2: This is line2
在实际应用中,read方法和readlines方法比较常用,而且二者都能读取全部文件中的数据。二者的区别只是返回的数据类型不同,前者返回字符串,适用于所有行都是完整句子的文本文件,例如大段文字信息;后者返回列表,适用于每行是一个单独的数据记录的文件,例如日志信息。不同的读取方法会直接影响后续基于内容的处理应用。由于readline每次只读取一行数据,因此通常需要配合seek、next等指针操作,才能完整遍历读取所有数据记录。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源
带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

(4)关闭文件对象
每次使用完数据对象之后,需要关闭数据对象。方法是file_object.close()。这种应用方法略显冗余,这里介绍基于with的文件打开方法,该方式可以自动做上下文管理,而无须单独做close操作。
例如,上面的文件读取方式用with可以写成:
with open('text.txt') as fn:

content = fn.read()

如果同时要对多个文件对象操作,那么可以连续写open方法。例如,同时对file1.txt和file2.txt做读入可以这样写:
with open('file1.txt') as fn1, open('file2.txt') as fn2:

content1 = fn1.read()
content2 = fn2.read()

理论上,Python可以读取任意格式的文件,但在这里通常以读取格式化的文本数据文件为主,其中包括有扩展名的txt、csv、tsv等格式的文件,以及由固定分隔符分隔并以通用数据编码和字符集编码(例如utf8、ASCII、GB2312等)存放的无扩展名格式的数据文件。在2.3节中我们会介绍使用Python读取非结构化的数据的方法。
2.使用Numpy的loadtxt、load、fromfile读取数据
Numpy读取数据的方法包括loadtxt、load和fromfile 3种,概要描述如表2-3所示。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

(1)使用loadtxt方法读取数据文件
Numpy可以读取txt格式的数据文件,数据通常都是一维或二维的。
语法:
loadtxt(fname, dtype=, comments='#', delimiter=None, converters=None, skiprows=0, usecols=None, unpack=False, ndmin=0)
参数如下。

  • fname:文件或字符串,必填,这里指定要读取的文件名称或字符串,支持压缩的数据文件,包括gz和bz格式。
  • dtype:数据类型,选填,默认为float(64位双精度浮点数)。Numpy常用类型如表2-4所示。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

  • comments:字符串或字符串组成的列表,是表示注释字符集开始的标志,选填,默认为#。
  • delimiter:字符串,用来分隔多个列的分隔符,例如逗号、TAB符,选填,默认值为空格。
  • converters:字典,用来将特定列的数据转换为字典中对应的函数的浮点型数据,例如将空值转换为0,选填,默认为空。
  • skiprows:跳过特定行数据,用来跳过特定前N条记录,例如跳过前1行(可能是标题或注释),选填,默认为0。
  • usecols:元组,用来指定要读取数据的列,第1列为0,以此类推,例如(1,3,5),选填,默认为空。
  • unpack:布尔型,用来指定是否转置数组,如果为真则转置,选填,默认为False。
  • ndmin:整数型,用来指定返回的数组至少包含特定维度的数组,值域为0/1/2,选填,默认为0。

返回:
从文件中读取的数组。
示例:
在“附件-chapter2”文件夹中有一个名为numpy_data.txt的数据文件,数据为3行5列的矩阵,数据内容如图2-3所示。该示例通过loadtxt方法读取其中的数据。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

import numpy as np     # 导入Numpy库
file_name = 'numpy_data.txt'     # 定义数据文件
data = np.loadtxt(file_name, dtype='float32', delimiter=' ') # 获取数据
print(data)     # 打印数据
上述代码输出的结果如下:
[[ 0. 1. 2. 3. 4.]
[ 5. 6. 7. 8. 9.]
[ 10. 11. 12. 13. 14.]]
(2)使用load方法读取数据文件
使用Numpy的 load方法可以读取Numpy专用的二进制数据文件,从npy、npz或pickled文件加载数组或pickled对象,该文件通常基于Numpy的save或savez等方法产生。
语法:
load(file, mmap_mode=None, allow_pickle=True, fix_imports=True, encoding='ASCII')
参数如下。

  • file:类文件对象或字符串格式,要读取的文件或字符串,必填。类文件对象需要支持seek()和read()方法。
  • mmap_mode:内存映射模式,值域为:None、'r+'、'r'、'w+'、'c',选填。
  • allow_pickle:布尔型,决定是否允许加载存储在npy文件中的pickled对象数组,选填,默认值为True。
  • fix_imports:布尔型,如果为True,pickle将尝试将旧的Python 2名称映射到Python 3中并使用的新名称,仅在Python 2生成的pickled文件加载Python 3时才有用,选填,默认值为True。
  • encoding:字符串,决定读取Python 2字符串时使用何种编码,仅对Python 3读取Python 2产生的pickled文件时有用,选填。

返回:
从数据文件中读取的数组、元组、字典等。
示例:
我们将在这个示例中先定义一份数据,然后保存为.npy格式的数据文件(该文件也在“附件-chapter2”中,名为load_data.npy),接着使用Numpy的load方法读取并打印输出。代码如下:
import numpy as np # 导入Numpy库
write_data = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12]])# 定义要存储的数据
np.save('load_data', write_data) # 保存为npy数据文件
read_data = np.load('load_data.npy') #读取npy文件
print(read_data) # 输出读取的数据
上述代码输出的结果如下:
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]
(3)使用fromfile方法读取数据文件
使用Numpy的fromfile方法可以读取简单的文本文件数据以及二进制数据。通常情况下,该方法读取的数据来源于Numpy的tofile方法,即通过Numpy的tofile方法将特定数据保存为文件(默认为二进制数据文件,无论文件扩展名如何定义),然后通过fromfile方法读取该二进制文件。
语法:
fromfile(file, dtype=float, count=-1, sep='')
参数如下。

  • file:文件或字符串。
  • dtype:数据类型,具体参照表2-3。注意数据类型要与文件存储的类型一致。
  • count:整数型,读取数据的数量,-1意味着读取所有数据。
  • sep:字符串,如果file是一个文本文件,那么该值就是数据间的分隔符。如果为空("")则意味着file是一个二进制文件,多个空格将按照一个空格处理。

返回:
从文件中读取的数据。
示例:
我们仍然以“附件-chapter2”文件夹中numpy_data.txt数据文件为例,首先通过tofile方法创建1个二进制文件,然后对该文件进行读取。
import numpy as np    # 导入Numpy库
file_name = 'numpy_data.txt'    # 定义数据文件
data = np.loadtxt(file_name, dtype='float32', delimiter=' ') #获取数据
tofile_name = 'binary'    # 定义导出二进制文件名
data.tofile(tofile_name)    # 导出二进制文件
fromfile_data = np.fromfile(tofile_name, dtype='float32') # 读取二进制文件
print(fromfile_data)    # 打印数据
上述代码输出的结果如下:
[ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14.]

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

3.使用Pandas的read_csv、read_fwf、read_table读取数据
相对于Python默认函数以及Numpy读取文件的方法,Pandas读取数据的方法更加丰富。Pandas读取文本文件数据的常用方法如表2-5所示。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

(1)使用read_cvs方法读取数据
通过read_csv方法可以读取csv格式的数据文件。
语法:
read_csv(filepath_or_buffer, sep=',', delimiter=None, header='infer', names=None, index_col=None, usecols=None, **kwds)
参数(read_csv的参数众多,仅介绍最常用的几个如下。

  • filepath_or_buffer:字符串,要读取的文件对象,必填。
  • sep:字符串,分隔符号,选填,默认值为英文逗号','。特殊情况下,如果数据分隔符号含有多个,例如多列之间通过“|+|”(3个符号)分隔的,那么分隔符sep的值可以设置为“|+|”,这是Python正则表达式语法。
  • names:类数组,列名,选填,默认值为空。
  • engine:解析引擎,默认情况下设置为“python”,这样设置的好处是功能更全面;而如果设置为“c”则解析速度更快,在大文件解析时更好用。但是,并不是所有情况下都可以设置为“c”,例如在上面的sep解析规则中,如果设置为“|+|”则无法指定解析引擎为“c”。
  • skiprows:类字典或整数型,要跳过的行或行数,选填,默认为空。
  • nrows:整数型,要读取的前记录总数,选填,默认为空,常用来在大型数据集下做初步探索之用。
  • na_values:NA值的表现字符串,系统中已经默认支持将空格(‘’)、#N/A、#N/A N/A、 #NA、-1.#IND、-1.#QNAND、1.#QNAN、N/A、NA、NULL、NaN、nan识别为NA值,如果数据中有其他NA值的表现形式,可以在这里指定。例如,设置na_values=[' ','None'],将字符串空格和None识别为NA值。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

  • thousands:字符串,千位符符号,选填,默认为空。
  • decimal:字符串,小数点符号,选填,默认为点(.),在特定情况下应用。例如,欧洲的千位符和小数点与中国地区相反,欧洲的“4.321,1”对应中国的“4,321.1”。
  • encoding:文件编码,默认情况下是“utf-8”,但需要注意的是,从原始数据库中导出的数据可能有各种编码,例如gb2312、latin1等,因此这里要设置为与原始数据一致的编码格式。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

返回:
DataFrame或TextParser
示例:
我们以“附件-chapter2”文件夹中的csv_data.csv数据文件为例,直接读取文件并打印输出。数据内容如图2-4所示。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

import pandas as pd # 导入Pandas库
csv_data = pd.read_csv('csv_data.csv', names=['col1', 'col2', 'col3', 'col4', 'col5'])   # 读取csv数据
print(csv_data)     # 打印输出数据
上述代码输出的结果如下:

 col1  col2  col3  col4  col5

0 0 1 2 3 4
1 5 6 7 8 9
2 10 11 12 13 14
(2)使用read_fwf方法读取数据
通过read_fwf方法可以读取表格或固定宽度格式的文本行到数据框。
语法:
read_fwf(filepath_or_buffer, colspecs='infer', widths=None, **kwds)
read_fwf与read_csv一样都具有非常多的参数(只是在语法中前者通过**kwds省略了,查询完整语法请使用help(pd.read_fwf)),并且大多数参数的用法相同。除了read_csv中的常用参数外,以下介绍一个read_fwf特有且常用的参数。

  • widths:由整数组成的列表,选填,如果间隔是连续的,可以使用字段宽度列表而不是“colspecs”。

返回:
DataFrame或TextParser。
示例:
我们以“附件-chapter2”文件夹中的fwf_data数据文件为例,直接读取文件并打印输出。数据内容如图2-5所示。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

import pandas as pd   # 导入Pandas库
fwf_data = pd.read_fwf('fwf_data', widths=[5, 5, 5, 5], names=['col1', 'col2', 'col3', 'col4']) # 读取csv数据
print(fwf_data)    # 打印输出数据
上述代码输出的结果如下:
col1 col2 col3 col4
0 a2331 a9013 a3211 a9981
1 b4432 b3199 b9766 b2212
2 c3294 c1099 c7631 c4302
(3)使用read_table方法读取数据
通过read_table方法可以读取通用分隔符分隔的数据文件到数据框。
语法:
read_table(filepath_or_buffer, sep='t', delimiter=None, header='infer', names=None, index_col=None, usecols=None, **kwds)
对于read_table而言,参数与read_csv完全相同。其实read_csv本来就是read_table中分隔符是逗号的一个特例,表现在语法中是read_csv的sep=','(默认)。因此,具体参数请查阅read_csv的参数部分。
返回:
DataFrame或TextParser。
我们以“附件-chapter2”文件夹中的table_data.txt数据文件为例,直接读取文件并打印输出。数据内容如图2-6所示。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

import pandas as pd # 导入Pandas库
table_data = pd.read_table('table_data.txt', sep=';', names=['col1', 'col2', 'col3', 'col4', 'col5']) # 读取csv数据
print(table_data) # 打印输出数据
上述代码输出的结果如下:

 col1  col2  col3  col4  col5

0 0 1 2 3 4
1 5 6 7 8 9
2 10 11 12 13 14
数据分隔(或分列)常用思路分为两种:一种是基于固定宽度,一种是基于分隔符号。在表2-5所示的3种方法中,常用的是第2种和第3种,即read_fwf和read_table方法。
除了上述用于读取文本文件的方法外,Pandas还提供了非常丰富的用于其他场景的数据读取方法,限于篇幅,在此不做更多介绍,仅提供读取方法列表供有兴趣的读者参考,以及做知识延伸。具体如表2-6所示。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

4.如何选择最佳读取数据的方法
关于“最佳”方法其实没有固定定义,因此所谓的最佳方法往往与以下具体因素有关。

  • 数据源情况:数据源中不同的字段类型首先会制约读取方法的选择,文本、数值、二进制数据都有各自的适应方法约束。
  • 数据处理目标:读取数据往往是第1步,后续会涉及数据探索、预处理、统计分析等复杂过程,这些复杂过程需要用到哪些方法在一定程度上都会受数据源的读取影响,影响最多的包括格式转换、类型转换、异常值处理、分类汇总等。
  • 模型数据要求:不同的模型对于数据格式的要求是不同的,应用到实际中不同的工具对于数据的表示方法也有所差异。
  • “手感”最好的方法:很多时候,最佳方法往往是对哪个或哪些方法最熟悉,这些所谓的“手感”最好的方法便是最佳方法。

当然,即使使用了不是“最佳”的数据读取方法也不必过于担心,因为Python强大的功能提供了众多可以相互进行转换的方法。从Python存储数据的基本对象类型来看,无非是字符串、列表、字典、元组、数组、矩阵等(当然,不同的库对于这些对象的定义名称可能有所不同,但基本含义相同),不同对象的类型转换都非常容易。但本着少走弯路的原则,在这里笔者还是针对不同的场景提供了较为适合的数据读取方法。

  • 对于纯文本格式或非格式化、非结构化的数据,通常用于自然语言处理、非结构化文本解析、应用正则表达式等后续应用场景下,Python默认的3种方法更为适合。
  • 对于结构化的、纯数值型的数据,并且主要用于矩阵计算、数据建模的,使用Numpy的loadtxt方法更为方便,例如本书中使用的sklearn本身就依赖于Numpy。
  • 对于二进制的数据处理,使用Numpy的load和fromfile方法更为合适。
  • 对于结构化的、探索性的数据统计和分析场景,使用Pandas方法进行读取效果更佳,因为其提供了类似于R的数据框,可以实现“仿SQL”式的操作方式,对数据进行任意翻转、切片(块等)、关联等都非常方便。
  • 对于结构化的、数值型和文本型组合的数据统计分析场景,使用Pandas更为合适,因为每个数据框中几乎可以装载并处理任意格式的数据。

2.2.2 从Excel获取运营数据

现有的Excel分为两种格式:xls(Excel 97-2003)和xlsx(Excel 2007及以上)。
Python处理Excel文件主要是第三方模块库xlrd、xlwt、pyexcel-xls、xluntils和pyExcel-erator等,此外Pandas中也带有可以读取Excel文件的模块(read_excel)。
基于扩展知识的目的,我们使用xlrd模块读取Excel数据。
首先安装该库,本书推荐的Anaconda中已经默认安装了xlrd和xlwt模块,用于Excel的读写操作。如果读者系统环境中没有,可以在Jupyter输入命令!pip install xlrd安装。
然后我们以“附件-chapter2”文件夹中的demo.xlsx数据文件为例,介绍该库的具体应用。数据概览如图2-7所示。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

import xlrd # 导入库
# 打开文件
xlsx = xlrd.open_workbook('demo.xlsx')
# 查看所有sheet列表
print('All sheets: %s' % xlsx.sheet_names())
上述代码中,我们先读取一个Excel文件,输出文件的sheet名称列表。由于里面只有一张sheet,一次只有一个值。结果为:All sheets: ['Sheet1']。
查看sheet1的数据概况:
sheet1 = xlsx.sheets()[0] # 获得第1张sheet,索引从0开始
sheet1_name = sheet1.name # 获得名称
sheet1_cols = sheet1.ncols # 获得列数
sheet1_nrows = sheet1.nrows # 获得行数
print('Sheet1 Name: %snSheet1 cols: %snSheet1 rows: %s' % (sheet1_name, sheet1_cols, sheet1_nrows))
我们分别获取了第1张sheet(虽然里面只有一张,但在多sheet情况下可通过索引循环输出)的名称、列数量和行数据。结果如下:
Sheet1 Name: sheet1
Sheet1 cols: 4
Sheet1 rows: 10
查看sheet1的特定切片数据:
sheet1_nrows4 = sheet1.row_values(4) # 获得第4行数据
sheet1_cols2 = sheet1.col_values(2) # 获得第2列数据
cell23 = sheet1.row(2)[3].value # 查看第3行第4列数据
print('Row 4: %snCol 2: %snCell 1: %sn' % (sheet1_nrows4, sheet1_cols2, cell23))
通过查看特定行、列或行列组合的索引来输出,结果如下:
Row 4: ['431381197408191515', '有效', 42725.0, '深圳市']
Col 2: ['Create_Time', 42725.0, 42725.0, 42725.0, 42725.0, 42725.0, 42725.0, 42725.0, 42725.0, 42725.0]
Cell 1: 深圳市
查看sheet1的数据明细:
for i in range(sheet1_nrows): # 逐行打印sheet1数据

print(sheet1.row_values(i))

逐条输出结果,部分结果如下(为了节约篇幅,中间的数据内容以…代替):
['ID_number', 'Status', 'Create_Time', 'Business_City']
['431381198109106573', '有效', 42725.0, '深圳市']
['431381198809122734', '有效', 42725.0, '深圳市']

['431381198901176911', '有效', 42725.0, '深圳市']
['43138119870827275X', '有效', 42725.0, '深圳市']
上述操作只是将数据从Excel中读取出来,将读取的数据转换为数组便可以进行矩阵计算。由于矩阵计算大多是基于数值型数据实现的,因此上述数据将无法适用于大多数科学计算场景,这点需要注意。
总结:在企业实际场景中,由于Excel本身的限制和适用,其无法存储和计算过大(例如千万级的数据记录)的数据量,并且Excel本身也不是为了海量数据的应用而产生的,因此,Excel可以作为日常基本数据处理、补充数据来源或者汇总级别的数据进行读取,同时也可以作为数据结果展示的载体,这种应用下对于大量数值表格的应用效果非常好。

2.2.3 从关系型数据库MySQL读取运营数据

在1.2.4节中我们介绍了安装MySQL和Navicat的方法和关键步骤。这里我们介绍如何利用Python从MySQL中读取数据。
在“附件-chapter2”文件夹中有一个名为order.xlsx的数据文件,我们先把文件导入MySQL数据库,然后再基于数据库进行相关操作。
第一步,新建一个数据库用于存放要导入的目标数据。
1)打开Navicat,左侧导航栏中有我们已经建立好的数据库链接,在第1章中我们已经建立好了本地连接,名为“local”。
2)双击该数据库连接,会展示出所有当前连接(对应的用户权限)下可用的数据库,如图2-8所示。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

3)为了保持不同数据的独立性,我们新建一个数据库,单独存放特定主题的数据。在“local”名称上右击,在弹出的菜单中选择,然后设置各项并单击“确定”按钮,如图2-9所示。完成之后在左侧的“local”链接下会新增一个刚才新建的数据库“python_data”。
第二步,将Excel数据导入数据库。
双击刚才新建的名为“python_data”的数据库名称,激活数据库连接。此时右侧功能栏中的部分功能已经可用。单击“导入向导”,开始导出Excel数据,如图2-10所示。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源
带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

1)选择数据文件格式为Excel 2007文件。
2)选择数据源文件,如图2-11所示。
3)定义附加选项。由于数据文件中第1行是表头,因此数据从第2行开始。日期分隔符与数据文件一致,需要设置为“-”,其他都为默认值,如图2-12所示。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

4)设置目标数据表名。源表为“Sheet1”,目标表为“order”。
5)设置字段类型、长度、约束等信息。其中主要的设置是将order_data类型设置为date(日期型),长度为0(不做限制);order_tme类型设置为time(时间型),长度为0(不做限制);total_amount类型设置为float(浮点型),长度默认为255,如图2-13所示。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

6)设置导入模式。由于我们是新创建表,因此设置为:“添加记录到目标表”。
7)启动导入任务。单击“开始”按钮即可。
等待系统导入数据。导入成功后,会在窗口中显示一些信息,最终的信息中包含“success-fully”,如图2-14所示。单击“关闭”按钮即可。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

至此我们已经成功导入数据,在数据库python_data下新增了一个名为“order”的数据表。我们要初步验证导入的数据是否与原始数据一致。
双击打开该表。打开表之后,会弹出信息,提示该表没有主键。但这并不影响我们使用该表,单击“确定”按钮即可,如图2-15所示。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

在创建表时,我们完全可以指定主键,例如本案例中的order_id是唯一的,那么可指定该字段作为主键,更可以创建一个自增长ID作为主键。本节的主要内容是介绍如何导入外部数据到数据库,有关数据库建表还有很多话题,在此不做更多介绍。
打开order表之后,会显示表预览内容,如图2-16所示。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

一般情况下,MySQL以及数据都是存储在C盘的。当不断写入大数据量时可能导致C盘的空间急剧减少。由于很多应用程序(也包括MySQL)会在C盘占用很多临时空间,因此当C盘突然变小时,可能导致程序无法正常运行。此时可以检查是否是MySQL不断写库而导致的。
在当前窗口,单击“文件-查询表”或直接使用快捷键Ctrl+Q,打开SQL窗口,然后输入SELECT * FROM order LIMIT 5;点击“运行”或使用快捷键Ctrl+R,返回前5条结果,如图2-17所示。读者可以在此输入其他SQL,或直接浏览数据表来核对数据导入是否准确。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源
带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

导入Excel数据主要核对的信息点如下。

  • 数据记录数是否一致:使用SELECT COUNT(*) FROM order;或在导入成功提示窗口也可以看到)。
  • 数据字段数量是否一致,导入表中的字段不能多也不能少。
  • 查看数据内容是否一致,尤其是日期、时间等非字符串字段的数据,很多时候时间型的数据转换会出现0000-00-00,这通常是导入设置的日期分隔符问题。
  • 数据精准度是否一致,尤其是当原始数据是浮点型,要注意对应到数据库字段是否还是浮点型(注意小数位数),问题通常出现在字段类型和位数设置上。
  • 注意字段的最大长度,不同的数值型数据长度位数是不同,例如整数型tinyint、int,浮点型的单精度和双精度浮点等,这对于汇总级别的数据会产生极大影响(因为某些字段的汇总数据可能非常大)。

通过Python连接MySQL需要有Python库来建立连接,本节使用MySQL官方驱动连接程序,更多信息可在1.2.3节中找到。
以下是Python读取数据库数据的基本方法:

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源
带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

上述代码中,实现了通过Python连接MySQL查询所有的数据,并输出前2条数据的功能。执行结果如下:
('3897894579', datetime.date(2010, 3, 11), datetime.timedelta(0), 'PENDING_ORDER_CONFIRM', '1038166', 59.0)
('3897983041', datetime.date(2010, 3, 11), datetime.timedelta(0), 'REMOVED', '1041656', 19.9)
在应用MySQL中,除了查询所有数据外,更多时候我们还会应用更多SQL技巧来帮助我们快速找到目标数据并做初步处理。以下是常用SQL语法。
1)只查询前N条数据而非全部数据行记录。
示例:只查询前100条数据记录。
SELECT * FROM order LIMIT 100;
LIMIT为限制的数据记录数方法,语法为limit m, n,意思是从第m到m+n条数据。m可省略,默认值从0开始,如上述示例中是从0开始,取100条数据。例如,要从第11条开始取,取10条可以写为SELECT * FROM order LIMIT 11, 10;。
2)只查询特定列(而非全部列)数据。
示例:只查询total_amount和order_id两列数据。
SELECT total_amount, order_id from order;
选择特定列只需将列名写到表达式中即可,多个列名用英文逗号分隔。另外,还可以使用“表名.字段名”的写法,例如上述表达式可以写成SELECT order.total_amount, order.order_id from order;,这种写法会出现在表达式中有多个表的情况下,例如多表关联查询。
3)查询特定列去重后的数据。
示例:查询针对user_id去重后的数据。
SELECT DISTINCT user_id FROM order;
关键词DISTINCT用于返回唯一不同的值,后面接字段名即要去重的字段。如果后面接多个字段会默认对多个字段同时进行比较,只有多个字段完全相同时才会去重。DISTINCT常用来返回去重后的特定ID,或者与COUNT配合使用,查询特定数据记录的唯一数量。
4)查询带有1个条件的数据。
示例:查询total_amount<100的所有数据。
SELECT * FROM order WHERE total_amount < 100;
WHERE是条件关键字,后面接具体条件。本示例中,由于total_amount为浮点型,因此可直接与数值型比较;如果是字符串型,则比较值需要加引号用来表示一致的字段类型。
5)查询带有多个条件(同时满足)的数据。
示例:查询total_amount<100且status为REMOVED的所有数据。
SELECT * FROM order WHERE total_amount < 100 and status = 'REMOVED';
多个条件使用and表示且的关系,多个条件必须同时满足。MySQL中字段不区分大小写。由于status也是关键字,因此也需要使用status
6)查询带有多个条件(满足任意一个)的数据。
示例:查询total_amount<100或status为REMOVED的所有数据。
SELECT * FROM order WHERE total_amount < 100 or status = 'REMOVED';
多个条件使用or表示或的关系,多个条件满足任意一个条件即可。
7)查询特定条件值在某个值域范围内的数据。
示例:查询status的值为REMOVED或NO_PENDING_ACTION或PENDING_ORDER_CONFIRM。
SELECT * FROM order WHERE status in ('REMOVED','NO_PENDING_ACTION','PENDING_ORDER_CONFIRM');
对于特定字段采用穷举法列出值域的方法,也可以使用or方法连接多个条件,但使用列表的穷举法会使得表达式更简单。
8)使用正则表达式查询具有复杂条件的数据。
示例:查询user_id以“103”开头且order_id包含“04”的所有订单数据。
SELECT * FROM order WHERE user_id LIKE '103%' and order_id LIKE '%04%';
正则表达式通常用在复杂条件中,通过使用关键字LIKE来连接不同的正则语法,LIKE后面接具体的匹配模式。常用的匹配模式如下。
以特定字符开头:'字符串%',例如'ABD%'表示以ABD开头的所有匹配。
以特定字符结尾:'%字符串',例如'% ABD'表示以ABD结尾的所有匹配。
包含特定字符:'%字符串%',例如'%ABD%'表示包含ABD的所有匹配。
正则表达式还有更多强大的语法规则,限于篇幅不再展开介绍。
9)将查询到的数据倒序排列。
示例:将total_amount金额在10~100之间的所有数据,按照订单ID倒序排序。
SELECT * FROM order WHERE 10 < total_amount < 100 ORDER BY order_id DESC;
在查询表达式ORDER BY的结尾,通过使用DESC来表示倒序(逆序)排序;省略是默认使用ASC正序(顺序)排序。
10)查询指定列中不包含空值的所有数据。
示例:查询order_id不为空的所有数据。
SELECT * FROM order WHERE order_id IS NOT NULL;
在MySQL中,IS NULL表示为空,IS NOT NULL表示非空。需要注意的是,NULL不代表空字符串或者空格,而是真正意义上的没有任何数据,类似于Python中的None。
上述案例只是展示了如何取数,更多情况下,我们会配合特定函数和方法做数据计算、整合和探索性分析。例如:

  • 使用MySQL聚合函数求算术平均值、计数、求最大/最小值、做分类汇总等。
  • 使用MySQL数学函数,用来求绝对值,进行对数计算、求平方根等。
  • 使用MySQL字符串函数进行字符串分割、组合、截取、匹配、处理等。
  • 使用MySQL的日期函数进行日期获取、转换、处理等。
  • 使用MySQL将多个表(2个或2个以上)数据进行关联、匹配和整合。

在Python工作者看来,Python本身能胜任MySQL的很多工作,为什么还要耗费时间和精力学习如何在MySQL中完成这些数据工作呢?直接用Python读取数据然后基于Python的相关库进行数据运算岂不更好?
Python的工作强项并不是数据计算,而是其灵活、高效、简易和集成多方的工作方式、效率和效果。MySQL(以及其他关系型数据库)作为成熟的数据存储和集成解决方案,在(关系型)数据本身方面更具优势,尤其是对于数据结构定义(实体、属性、关系)、关系操作(选择、连接、聚合等)、关系完整性约束(主外键、唯一性等)等方面具有成熟且稳定的应用价值,这对于数据处理至关重要。因此,可以说MySQL在结构化数据存储和初步处理工作上比Python更专业。
还有一个更加关键的原因是,如果所有数据工作都由Python完成,那么Python的事务处理在某些情况下一定会面临资源瓶颈、工作效率等问题,届时可能会导致程序崩溃和报错,这将大大降低程序的可靠性以及结果输出的效率,对于海量数据工作更是如此。
因此,很多时候不是Python不能做,而是在合适的时机选择最合适的工具来完成才是最好的选择。

2.2.4 从非关系型数据库MongoDB读取运营数据

由于MongoDB一般都是企业级数据存储,因此这里我们使用在第1章已经安装过的SSH远程客户端SecureCRT。如果读者有自己在虚拟机或本地安装MongoDB,也可以使用,操作方法类似。
双击SecureCRT打开程序,单击顶部的快速连接按钮,新建连接,如图2-18所示。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

然后根据服务器具体配置情况,配置如图2-19所示信息。其中主机名和用户名需要单独配置,其他则应根据实际情况询问IT或运维管理人员(本案例中都是默认值)。可勾选带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源用于以后启动该程序时直接显示快捷入口。
单击“连接”按钮之后,会弹出密码输入窗口,输入密码,可勾选带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源用于以后无须重复输入密码,具体视公司安全规定执行,如图2-20所示。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

如果服务器配置信息填写正确,连接服务器成功会显示如图2-21所示信息。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

要想通过Python调用MongoDB,需要先安装PyMongoDB,本书使用的Anaconda默认没有安装该库,可在Jupyter中直接使用!pip install pymongo安装。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源
带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

使用Python连接MongoDB之前,需要服务器上的MongoDB处于启动状态。查看是否成功启动的方法是找一个可以直接连接或访问服务器的浏览器,直接输入IP:端口,如果出现“It looks like you are trying to access MongoDB over HTTP on the native driver port.”字样的提示,则说明已经正常启动和运行。例如:笔者的服务器上已经启动了该服务,在浏览器中输入http://10.66.202.134:27017/ 后提示如图2-23所示信息。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

要在服务器上进入Python环境,直接在终端窗口输入命令python。在Python命令行窗口中,通过如下方法调用MongoDB数据。
from pymongo import MongoClient # 导入库
client = MongoClient('10.0.0.54', 27017) # 输出实际的服务器IP地址以及端口,建立连接,并初始化环境变量
db = client.python_data # 选择python_data库
orders = db.ordersets # 选择orders集合
terms = [{"user": "tony", "id": "31020", "age": "30", "products": ["215120", "245101", "128410"], "date": "2017-04-06"},

      {"user": "lucy", "id": "32210", "age": "29", "products": ["541001", "340740", "450111"], "date": "2017-04-06"}]  # 定义一条数据集合用于插入

orders.insert_many(terms) # 插入数据
print(orders.find_one()) # 获取一条文档数据
在上述代码中,我们连接到MongoDB后选择了test_py库下的ordersets集合,然后插入2条数据到集合中,打印其中一条数据如下:
{'_id': ObjectId('5bf51b668b0b3f20dcc04638'), 'user': 'tony', 'id': '31020', 'age': '30', 'products': ['215120', '245101', '128410'], 'date': '2017-04-06'}
再输出所有集合数据。
for i in orders.find(): # 获取所有文档数据并展示

print(i)

以下是代码执行后打印输出的结果:
{'age': '30', 'products': ['215120', '245101', '128410'], 'user': 'tony', 'date': '2017-04-06', '_id': ObjectId('58eb1f0b2f76bf26108b4898'), 'id': '31020'}
{'age': '29', 'products': ['541001', '340740', '450111'], 'user': 'lucy', 'date': '2017-04-06', '_id': ObjectId('58eb1f0b2f76bf26108b4899'), 'id': '32210'}
除了上述基本查询语句外,PyMongo也提供了类似于MySQL的条件过滤语句。
1)查询特定文档数据。
示例:只查询第2条数据。
orders.find()[1] # 查询特定索引的数据记录
通过增加索引值可以指定查询特定索引的文档数据。注意索引值从0开始,0代表第1条是数据。
2)查询特定范围内的文档数据。
示例:只查询第1~2条数据。
orders.find()[0:2] # 查询特定范围内的数据记录
通过增加索引值可以指定查询特定索引范围的文档数据(切片)。注意,索引值为空则默认从0开始,0代表第1条是数据。上述表达式可以写成orders.find()[:2]。索引结束值默认不包含,例如,上述语法中的0:2的实际索引只有0和1。
3)增加查询条件。
示例:只查询user为lucy的文档数据。
orders.find({"user": "lucy"}) # 所有数据,注意使用迭代方法查看数据
orders.find_one({"user": "lucy"}) # 单条数据
作为Key-Value形式的代表应用之一,MongoDB几乎所有的用法都以Key-Vaule的形式存在。过滤条件也不例外,只需在find函数中,以Key-Value的形式设置过滤条件即可,其中Key为过滤维度,Value为对应值。
4)排序。
示例:针对user排序并输出。
orders.find({"user": "lucy"}).sort("user") # 所有数据,注意使用迭代方法查看数据
通过使用Sort方法设置排序维度。默认是正序,也可以指定为倒序排列,同时也可以指定多个字段排序规则,例如collection.find().sort([ ('field1', pymongo.ASCENDING), ('field2', pymongo.DESCENDING)])。从MongoDB 2.6开始,还提
供了按照文本相关性的排序方法,例如collection.find({'score': {'$meta': 'text-Score'}}).sort([('score', {'$meta': 'textScore'})])。
除了上述基本查询和过滤条件外,PyMongo也提供了用于数据统计、分析和探索的基本方法,更多信息具体查阅http://api.mongodb.com/python/current/
在企业实际应用中,非关系型数据库往往基于“大数据”的场景产生,伴随着海量、实时、多类型等特征而来。这些数据库舍弃了关系型数据库的某些特征和约束,在特定方面进行增强,因此才能满足特定应用需求。非关系型数据库由于约束性、规范性、一致性和数据准确性低于关系型数据库,因此常用于实时海量数据读写、非结构化和半结构化信息读写、海量集群扩展、特殊场景应用等。所以在金融、保险、财务、银行等领域内,这种应用比较少;而在互联网、移动应用等新兴产业和行业领域则应用较多。

2.2.5 从API获取运营数据

为了更好地让所有读者了解从API获取数据的具体过程,本节使用百度免费API作为实际数据来源。百度API提供了众多地图类功能,可用于基本地图、位置搜索、周边搜索、公交驾车导航、定位服务、地理编码及逆地理编码等。本节使用的是百度Web服务API中的Geocoding API。
Geocoding API用于提供从地址到经纬度坐标或者从经纬度坐标到地址的转换服务,用户可以发送请求且接收JSON、XML的返回数据。该应用可用于对运营数据中的地址相关信息进行解析,从而获得相关经纬度信息,这些信息可用于进一步的基于地理位置的解析、展示和分析等应用。
要获得该API,读者需要拥有百度相关账户和AK信息。
1)获得百度账户,没有账户的读者可在https://passport.baidu.com/v2/?reg 免费注册获取。
2)注册成为百度开放平台开发者,读者可进入http://lbsyun.baidu.com/apiconsole/key?appl-ication=key 完成相关注册。该过程非常简单,遵循引导即可,整个过程在5分钟以内完成,如图2-24所示。
3)注册完成之后,会有一封名为“百度地图开放平台”的开发者激活邮件发送验证链接到用户指定(注册时邮箱)邮箱,单击链接进行验证。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

4)单击“申请秘钥”进入创建应用界面,如图2-25所示。在该应用创建中,我们主要使用Geocoding API v2,其他应用服务根据实际需求勾选,如图2-26所示。如果不做限制,IP白名单区域设置为“0.0.0.0/0”。设置完成后,单击“提交”按钮。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

5)获得AK秘钥。完成上述步骤之后,会默认跳转到应用列表界面,界面中的“访问应用(AK)”中便是该应用的秘钥,如图2-27所示。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

1.获取并解析JSON数据
我们先通过Python请求该API来获得JSON格式的数据。本示例的目标是给百度API发送一条地理位置数据,返回其经纬度信息。
本节会用到Python第三方库requests,默认通过Anaconda已经安装。如果读者系统环境中没有该库,可以先通过!pip install requests安装。完整代码如下:
import requests # 导入库
add = '北京市中关村软件园' # 定义地址
ak = 'DdOyOKo0VZBgdDFQnyhINKYDGkzBkuQr' # 创建访问应用时获得的AK
url = 'http://api.map.baidu.com/geocoder/v2/?address=%s&output=json&ak=%s' # 请求URL
res = requests.get(url % (add, ak)) # 获得返回请求
add_info = res.text # 返回文本信息
print(add_info) # 打印输出
在上述代码中,先导入一个requests库,该库用来发送网络请求,支持多种发送模式,可以用来做网页内容抓取、自动化网页测试、网页内容采集等。
第2行定义了一个地址,该地址通常是运营中的地址类信息,例如:通信地址、注册地址、收货地址、联系地址等。
第3行ak是创建访问应用时获得的AK,注意百度有每天有6000次的限制,读者可填写自行申请的AK。
第4行定义了一个通过get方法发送的URL请求地址,地址中的address和ak的具体值使用占位符代替,在后面用到时具体赋值,这种方法经常用于地址、ak有变化的场景中。例如:我们通常会创建多个应用(基于每个账户有限制,以及分开治理应用的考虑),然后从数据库中读取一系列地址用于解析。此时的地址和AK都需要能动态赋值。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

第5行通过get方法发送请求到上面定义的URL中,并具体赋值。
第6行将返回对象的文本信息赋值到add_info,返回对象中还包括非常多的相关属性信息,例如状态码、cookie、reason、headers、编码等,这些信息可用于判断是否正确返回、问题原因、状态等信息。
最后一行打印输出返回的文本信息。
以下是代码执行后打印输出的结果:
{"status":0,"result":{"location":{"lng":116.29381532521775,"lat":40.05299113952319},"precise":0,"confidence":40,"comprehension":100,"level":"工业园区"}}
返回结果包括以下字段。

  • status:返回结果状态值,成功则返回0。
  • location:经纬度坐标,其中lat是纬度值,lng是经度值。
  • precise:位置的附加信息,决定是否精确查找。1为精确查找,即准确打点;0为不精确查找,即模糊打点。
  • confidence:可信度,描述打点准确度。
  • level:百度定义的地址类型。

该结果可以通过JSON进行格式化处理。
import json # 导入库
add_json = json.loads(add_info) # 加载JSON字符串对象
lat_lng = add_json'result' # 获得经纬度信息
print(lat_lng) # 打印输出
代码中,我们导入Python自带的JSON库。该库支持Python其他对象和JSON对象之间的相互转换。
先将获得的地址信息格式化为JSON字符串(字典类型),然后通过读取字典的Key来获得其Value。由于返回的地址信息中包含字典嵌套,因此这里需要依次读出第1层和第2层信息。读者可通过add_json.items()来更加直观地观察2层嵌套。
上述代码执行后返回结果如下:
{'lng': 116.29381532521775, 'lat': 40.05299113952319}
2.获取并解析XML数据
Geocoding API也提供XML格式的返回数据。下面以获得XML格式的数据为例介绍代码过程。
import requests # 导入库
add = '北京市中关村软件园' # 定义地址
ak = 'DdOyOKo0VZBgdDFQnyhINKYDGkzBkuQr' # 创建访问应用时获得的AK
url = 'http://api.map.baidu.com/geocoder/v2/?address=%s&output=xml&ak=%s' # 请求URL
res = requests.get(url % (add, ak)) # 获得返回请求
add_info = res.text # 返回文本信息
print(add_info) # 打印输出
上述所有代码与JSON格式的代码完全相同,只在第4行定义url时,将output的返回值类型设置为xml。执行后返回结果如下:

<?xml version="1.0" encoding="utf-8"?>
<GeocoderSearchResponse>
    <status>0</status>
    <result>
        <location>
            <lng>116.299337657</lng>
            <lat>40.0539973025</lat>
        </location>
        <precise>0</precise>
        <confidence>40</confidence>
        <level>工业园区</level>
    </result>
</GeocoderSearchResponse>

接着我们通过引入一个XML格式化处理库来从中提取经纬度信息。关于XML文件的解析,Python默认和第三方的常用库包括xml、libxml2、lxml、xpath等,我们使用Python自带的XML进行处理。
import xml.etree.ElementTree as Etree # 导入XML中的ElementTree方法
root = Etree.fromstring(add_info) # 获得XML的根节点
lng = root1[0].text # 获得lng数据
lat = root1[1].text # 获得lat数据
print('lng: %s' % lng) # 格式化打印输出经度值
print('lat: %s' % lat) # 格式化打印输出纬度值
上述代码中,前4行实现了一个功能,将代码的字符编码设置为utf-8,否则系统会默认为ASCII,对返回的带有中文字符串无法识别而报错。
代码第5行导入XML自带的ElementTree方法,该方法可以实现对XML内容的查询、新建、修改等操作,是XML中比较简单容易上手的方法(XML除了ElementTree外,还提供了DOM和SAX方法)。
代码第6行获得从API得到的XML对象并获得根节点。
代码第7、第8行分别通过嵌套读取从根节点开始向下的第3层经纬度数据。
代码最后两行格式化打印输出经纬度。
上述代码执行后返回结果如下:
lng: 116.293815325
lat: 40.0529911395
有关百度API的更多信息,具体查阅http://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-geocoding
在API应用中,中文的编码处理因细节太多而常常让人头疼。因此,如果可以则应尽量减少直接在API的数据中出现中文字符。在实际企业应用中,会出现多种API形式,但无论哪种形式,其基本实现思路都是一致的:导入库→定义请求变量→发送请求→获得返回数据→格式化并获得目标数据,因此需要掌握JSON和XML的数据与其他数据的转换方法。

2.3 内容延伸:读取非结构化网页、文本、图像、视频、语音

在前面的章节中,我们介绍的内容是企业常见的数据来源和获取方式。本节将拓展数据来源方式和格式的获取,主要集中在非结构化的网页、文本、图像、视频和语音。

2.3.1 从网页中获取运营数据

要从网页中获取数据,可使用Python内置标准库或第三方库,例如urllib、urllib2、httplib、httplib2、requests等。本节使用requests方法获取网页数据。
import requests  # 导入库
url = 'http://www.dataivy.cn/blog/dbscan/' # 定义要获取的网页地址
res = requests.get(url)  # 获得返回请求
html = res.text  # 返回文本信息
print(html)  # 打印输出网页源代码
在代码中,先导入用到的网络请求处理库requests,然后定义一个用来获取的url,通过requests的get方法获取url的返回请求,并通过返回请求的text方法获取内容(源代码),最终打印输出网页信息。部分结果如下:
带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

从网页中读取的信息其实是网页的源代码,源代码经过浏览器解析后才是我们看到的不同的页面内容和效果。因此,在获取网页中包含了内容的源代码后,下面要做的是针对源代码的解析。有关该内容会在3.10.1节中具体说明。

2.3.2 读取非结构化文本数据

非结构化的文本数据指的是文本数据中没有结构化的格式,需要定制化解析才能获取数据,并且每条记录的字段也可能存在差异,这意味着传统的结构化读取方式将很难工作。非结构化的日志就是一个典型示例,服务器的日志可由运维工程师自行定义,因此不同公司的日志格式会有所不同。另外在网站日志中还可能包含通过页面“埋码”的方式采集到的用户的行为数据,这些都会使日志面临非结构化的解析问题。
在“附件-chapter2”文件夹中有一个名为traffic_log_for_dataivy的日志文件,里面存放了www.dataivy.cn 网站一段时间的日志数据。本节示例代码的目的是将日志读取出来。
file = 'traffic_log_for_dataivy'
fn = open(file, 'r') # 打开要读取的日志文件对象
content = fn.readlines() # 以列表形式读取日志数据
print(content[:2])
fn.close() # 关闭文件对象
上述代码中先定义了一个要读取的非结构化文本文件,通过Python标准库open方法以只读模式打开文件,然后通过readlines方法将文件内容以行为单位读取为数据列表,打印输出前2条数据,最后关闭文件对象。执行后返回如下结果:
['120.26.227.125 - - [28/Feb/2017:20:06:51 +0800] "GET / HTTP/1.1" 200 10902 "-" "curl"n', '139.129.132.110 - - [28/Feb/2017:20:06:51 +0800] "GET / HTTP/1.1" 200 10903 "-" "curl"n']
其实日志文件只是普通文本文件的一种类型而已,其他的非结构化数据文件都可以以类似的方法读取,即使文件没有任何扩展名也可以。
总结:对于非结构化的文本处理,通常更多侧重于特定场景,通用性较差,原因就在于非结构化的形式本身变化多样。自然语言理解、文本处理和挖掘、用户日志和机器日志解析等都是围绕该领域的主要工作主题。

2.3.3 读取图像数据

在Python 3中,读取图像通常使用Pillow和OpenCV两个库,相对而言,笔者使用后者的情况更多。本节以“附件-chapter2”文件夹中cat.jpg为例进行说明。
1.使用Pillow读取图像
有关Pillow与PIL的渊源,我们已经在1.2.3节中介绍过,这里直接介绍Pillow的用法。
Pillow中包含很多库,常用的是Image,通过使用其中的open方法来读取图像。用法如下:
from PIL import Image # 导入库
file = 'cat.jpg' # 定义图片地址
img = Image.open(file, mode="r") # 读取文件内容
img.show() # 展示图像内容
其中关键的方法是open,其参数包括以下两个。

  • file:文件对象名称,可以是文件名,也可以是图像文件字符串。
  • mode:打开模式,默认只能是r模式,否则会报错。当file是图像字符串时,会调用系统的rb模式读取。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

通过open读取之后会返回一个图像文件对象,后续所有的图像处理都基于该对象进行。上述代码执行后,通过img.show()会调用系统默认的图像浏览器打开图像进行查看,如图2-28所示。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

该对象包含了很多方法,这些方法可以用来打印输出文件的属性,例如尺寸、格式、色彩模式等。
print('img format: ', img.format) # 打印图像格式
print('img size: ', img.size) # 打印图像尺寸
print('img mode: ', img.mode) # 打印图像色彩模式
上述代码执行后返回的结果如下:
img format: JPEG
img size: (435, 361)
img mode: RGB
其中图像的类型是图像本身的格式,例如jpg、gif、png等;图像尺寸是指图像分辨率,示例中的尺寸是435×361(单位是像素);图像的模式指的是颜色模式,示例图像是RGB模式。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

除此以外,基于该文件对象也可以进行其他操作,例如图像格式转换、旋转、裁剪、合并、滤波处理、色彩处理、缩略图处理等。限于篇幅,在此不做过多介绍。
2.使用OpenCV读取图像
在第1章介绍了OpenCV的安装方法,但截至本书撰写时,通过pip安装的包仅为3.4.3版本。而此时4.0版本已经发布,但通过其他方法无法安装该版本。
OpenCV读取和展示图像主要使用cv2库。
import cv2 # 导入库
file = 'cat.jpg' # 定义图片地址
img = cv2.imread(file) # 读取图像
cv2.imshow('image', img) # 展示图像
cv2.waitKey(0) # 与显示参数配合使用
上述两种方法执行后,都会产生如图2-28所示的结果。不同的是,图2-28中通过PIL调用的是系统默认的图像显示工具,而在OpenCV中是通过自身创建的图像功能显示图像。
另外,两种方法中都有一个waitKey()的方法,该方法的作用是键盘绑定函数,其中的参数表示等待毫秒数。执行该方法后,程序将等待指定的毫秒数,看键盘是否有输入,然后返回值对应的ASCII值。如果其参数为0,则表示无限期地等待,直到键盘有输入。
笔者通常使用第2种方法读取图像,此方法更加简单。其中imread方法细节如下。
语法:
cv2.imread(filename[, flags])
描述:
读取图像内容,如果图像无法读取则返回空信息。支持的图像格式几乎包括了日常所有场景下的格式。具体包括以下这些。

  • Windows bitmaps文件:*.bmp、*.dib。
  • JPEG文件:*.jpeg、*.jpg、*.jpe。
  • JPEG 2000文件:*.jp2。
  • PNG文件:*.png。
  • WebP文件:*.webp。
  • 移动图像格式:*.pbm、*.pgm、*.ppm *.pxm、*.pnm。
  • Sun rasters文件:*.sr、*.ras。
  • TIFF 文件:*.tiff、*.tif。
  • OpenEXR文件:*.exr。
  • Radiance HDR文件:*.hdr、*.pic。

参数:
filename必填,字符串,图像地址。
flags可选,int型或对应字符串,颜色的读取模式。如果flag>0或者cv2.IMREAD_COLOR,读取具有R/G/B三通道的彩色图像;如果flag=0或cv2.IMREAD_GRAYSCALE,读取灰度图像;如果flag<0或cv2.IMREAD_UNCHANGED,读取包含Alpha通道的原始图像。
返回:
图像内容,如果图像无法读取则返回NULL。
3.使用Matplotlib展示图像
除了使用OpenCV自带的图像展示方法外,OpenCV还常与matplotlib配合展示图像,这种场景更加常用。组合使用时可借用Matplotlib的强大图像展示能力进行图像的对比和参照以及不同图像模式的输出。
但是需要注意的是,使用OpenCV读取彩色图像时,OpenCV是以B、G、R的顺序存储和显示图像数据的,而Matplotlib是以R、G、B的顺序显示图像的;如果直接使用OpenCV读取图像后调用Matplotlib显示,那么会与原始图像不一致。
下面通过实例代码来演示如何通过Matplotlib显示OpenCV读取的图像,以及OpenCV和Matplotlib显示图像的差异。
# 导入库
import matplotlib.pyplot as plt
import cv2 # 导入库
# 读取图像文件并创建多图像副本
file = 'cat.jpg' # 定义图片地址
img = cv2.imread(file) # 读取图像
b, g, r = cv2.split(img) # 分离颜色三通道
img2 = cv2.merge([r, g, b]) # 重新组合图像数据
# 使用Matplotlib展示图像
plt.subplot(121) # 定位第1个网格
plt.title('plt BGR image') # 设置子网格标题
plt.imshow(img) # 设置子网格展示的图像
plt.subplot(122) # 定位第2个网格
plt.title('plt RGB image') # 设置子网格标题
plt.imshow(img2) # 设置子网格展示的图像
# 使用OpenCV展示图像
cv2.imshow('OpenCV BGR image', img) # 展示BGR图像
cv2.imshow('OpenCV RGB image', img2) # 展示RGB图像
cv2.waitKey(0) # 与显示参数配合使用
cv2.destroyAllWindows() # 关闭所有窗口
上述代码中,我们分别导入用到的matplotlib.pyplot和cv2库,然后读取图像文件并创建多图像副本。其中涉及两个新的参数用法:split和merge。

  • split:使用cv2.split可以将OpenCV读取的图像数据,分离为B、G、R单颜色通道图像。
  • merge:使用cv2.merge将多个通道颜色数据以R、G、B的次序再次组合起来(跟img中的模式不同),形成img2。

使用Matplotlib展示图像中,我们用到了以下参数:

  • subplot:用来定位子网格的位置,默认参数包括subplot(nrows, ncols, plot_number),nrws为行数,ncols为列数,plot_number为网格位置,该位置以行为索引标准,行索引完毕之后再换另一行。例如,一个[4, 2, 3]的位置代表的是创建一个4行2列的网格,并定位在第3个子网格(第2行的第1个位置)。如果3个值都小于10,那么可以组合并简写为一个3位数,例如本示例中写为plt.subplot(121)或plt.subplot(1, 2, 1)都是可以的,二者是等效的。
  • title:用来设置网格的标题。
  • imshow:用来展示一个图像对象。

使用Matplotlib展示的图像结果如图2-30所示。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

使用OpenCV展示图像中的参数基本都是我们之前用过的。其中的cv2.destroyAllWin-dows()用来关闭所有窗口,该函数在下面读取视频数据时还会用到。本段函数的展示图像结果如图2-31所示。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

观察通过Matplotlib和OpenCV读取的图像结果,会发现二者在默认模式下的显示结果是不同的。因此,读者如果要用Matplotlib展示OpenCV读取的图像结果,必须注意图像显示模式的差异和调整。

2.3.4 读取视频数据

Python读取视频最常用的库也是Opencv。本节以“附件-chapter2”文件夹中Megamind.avi的视频为例进行说明,以下是一段读取视频内容的代码示例。
import cv2 # 导入库
cap = cv2.VideoCapture("tree.avi") # 获得视频对象
status = cap.isOpened() # 判断文件是否正确打开
# 输出基本属性
if status: # 如果正确打开,则获得视频的属性信息

frame_width = cap.get(3)          # 获得帧宽度
frame_height = cap.get(4)          # 获得帧高度
frame_count = cap.get(7)          # 获得总帧数
frame_fps = cap.get(5)         # 获得帧速率
print('frame width: ', frame_width)  # 打印输出
print('frame height: ', frame_height) # 打印输出
print('frame count: ', frame_count)  # 打印输出
print('frame fps: ', frame_fps)      # 打印输出

# 读取视频内容并展示视频
success, frame = cap.read() # 读取视频第1帧
while success: # 如果读取状态为True

cv2.imshow('vidoe frame', frame)      # 展示帧图像
success, frame = cap.read()         # 获取下1帧
k = cv2.waitKey(int(1000 / frame_fps))    # 每次帧播放延迟一定时间,同时等待输入指令
if k == 27:                  # 如果等待期间检测到按Esc键
    break                  # 退出循环

# 操作结束释放所有对象
cv2.destroyAllWindows() # 关闭所有窗口
cap.release() # 释放视频文件对象
上述代码分为4个部分,以空行分隔。
第一部分为前3行,先导入库,然后读取视频文件并获得视频对象,最后获得视频读取状态。其中的关键方法是VideoCapture,用来读取图像。
语法:
cv2.VideoCapture(VideoCapture ID|filename|apiPreference)
描述:
读取视频设备或文件,并创建一个视频对象实例。
参数:

  • VideoCapture ID:必填。int型,系统分配的设备对象的ID,默认的设备对象的ID为0。
  • Filename:必填。包括如下部分。

    • 视频文件的名称,字符串,例如abc.avi。目前版本下只支持avi格式。
    • 序列图像,字符串,例如img_%2d.jpg(图像序列包括img_00.jpg, img_01.jpg, img_ 02.jpg, ...)。
    • 视频URL地址,字符串,例如protocol://host:port/script_name?script_params|auth。
    • apiPreference:int型,后台使用的API。

返回:
一个视频对象实例。
第2部分为if循环体内的9行代码,该代码主要用来在判断文件被正确读取的情况下,输出视频文件的整体信息。除了代码中get方法使用的参数值外,OpenCV还支持更多图像属性,如表2-7所示。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源
带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

该段代码输出如下视频信息:
frame width: 320.0
frame height: 240.0
frame count: 444.0
frame fps: 14.999925000374999
第3部分为具体读取和展示视频的每一帧内容。首先读取视频的第1帧,如果状态为True,则展示图像并读取下一帧,期间通过cv2.waitKey参数做图像延迟控制,同时延迟期间等待系统输入指定,如果有输入Esc则退出循环读取帧内容。视频内容的截图如图2-32所示。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源
带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

在视频中有几个关键名词。

  • 帧率(FPS):每秒播放的帧数被定义为帧率,帧率越高,在视觉上认为图像越连贯,就越没有卡顿的现象。常见的帧率包括23.967(电影)、25(PAL电视),示例图像大约为15。帧率与图像清晰度无关,它只是决定了视频的连贯性。
  • 帧分辨率:帧分辨率基本决定了视频的清晰度(除此之外还有视频处理效果、设备播放差异等,这里指的是同等条件下的视频源)。在同样大小的图像中,分辨率越高图像通常就会越清晰。所以形容视频时提到的1080P(1920×1080)、720P(1280×720)其实指的就是分辨率标准。当然,对于同样分辨率下,在不同国家、不同电视规制、不同扫描标注下,也会更加细分。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

第4部分为当所有操作结束后,删除所有由OpenCv创建的窗体,释放视频文件对象。
有关OpenCV的更多信息,具体可查阅opencv.org。

2.3.5 读取语音数据

对于语音文件的读取,可以使用Python的audioop、aifc、wav等库实现。但针对语音处理这一细分领域,当前市场上已经具备非常成熟的解决方案,例如科大讯飞、百度语音等。大多数情况下,我们会通过调用其API实现语音分析处理的功能,或者作为分析处理前的预处理功能。
在具体实现过程中,既可以直接下载SDK做离线应用,也可以使用在线的服务。科大讯飞的语音服务如图2-33所示。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

本节将以百度语音API服务应用为例,说明如何通过请求百度语音的API,将语音数据转换为文字信息。
在正式应用百度语音API之前,请读者先参照2.2.5节中介绍的步骤,建立百度账户并注册成为百度开发者。基于该条件下,我们继续开通语音识别服务。具体方法如下:
1)进入http://yuyin.baidu.com/app ,在弹出的界面中单击要针对哪个应用开通语音识别服务。我们默认使用在之前建立的API_For_Python应用。因此,单击该应用的“开通服务”,如图2-34所示。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

2)在弹出的窗口中,单击选择“语音识别”并确定,如图2-35所示。
3)开通成功后系统会提示,然后单击图2-36中右侧的,会弹出如图2-36所示信息。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

弹出的API Key和Secret Key为在后续语音识别中要使用的信息。
以下为完整代码:
# 导入库
import json # 用来转换JSON字符串
import base64 # 用来做语音文件的Base64编码
import requests # 用来发送服务器请求

# 获得token
API_Key = 'DdOyOKo0VZBgdDFQnyhINKYDGkzBkuQr' # 从申请应用的key信息中获得
Secret_Key = 'oiIboc5uLLUmUMPws3m0LUwb00HQidPx' # 从申请应用的key信息中获得
token_url = "https://openapi.baidu.com/oauth/2.0/token?grant_type=client_credentials&client_id=%s&client_secret=%s"    # 获得token的地址
res = requests.get(token_url % (API_Key, Secret_Key)) # 发送请求
res_text = res.text # 获得请求中的文字信息
token = json.loads(res_text)['access_token'] # 提取token信息

# 定义要发送的语音
voice_file = 'baidu_voice_test.pcm' # 要识别的语音文件
voice_fn = open(voice_file, 'rb') # 以二进制的方式打开文件
org_voice_data = voice_fn.read() # 读取文件内容
org_voice_len = len(org_voice_data) # 获得文件长度
base64_voice_data = base64.b64encode(org_voice_data).decode('utf-8')

    # 将语音内容转换为base64编码格式

# 发送信息
# 定义要发送的数据主体信息
headers = {'content-type': 'application/json'} # 定义header信息
payload = {

'format': 'pcm',                  # 以具体要识别的语音扩展名为准
'rate': 8000,                  # 支持8000或16000两种采样率
'channel': 1,                  # 固定值,单声道
'token': token,                  # 上述获取的token
'cuid': 'B8-76-3F-41-3E-2B',          # 本机的MAC地址或设备唯一识别标志
'len': org_voice_len,              # 上述获取的原始文件内容长度
'speech': base64_voice_data              # 转码后的语音数据

}
data = json.dumps(payload) # 将数据转换为JSON格式
vop_url = 'http://vop.baidu.com/server_api' # 语音识别的API
voice_res = requests.post(vop_url, data=data, headers=headers) # 发送语音识别请求
api_data = voice_res.text # 获得语音识别文字返回结果
text_data = json.loads(api_data)['result']
print(api_data) # 打印输出整体返回结果
print(text_data) # 打印输出语音识别的文字
代码以空行作为分隔,包括4个部分:
第1部分为导入需要的库信息,具体用途见代码注解。
第2部分为获得要使用百度语音识别API的token信息。其中的API_Key和Secret_Key见图2-36。token_url通过占位符定义出完整字符串,并在请求时发送具体变量数据,从返回的信息中直接读取token便于在下面应用中使用。有关获取token的更多信息,具体查阅http://yuyin.baidu.com/docs/asr/56

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

第3部分主要用于获取和处理语音文件数据。通过最常见的open方法以二进制的方式读取语音数据,然后从获得的语音数据中获取原始数据长度,并将原始数据转换为base64编码格式。这里需要注意的是,需要将其decode为utf-8格式的编码,否则产生的结果对象为bytes类型,JSON会报解析错误“TypeError: Object of type 'bytes' is not JSON serializable”。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

第4部分为本节内容的主体,发送请求获取语音识别结果。本段落中先定义了发送头信息;然后定义了一个字典,用于存储要发送的key-value字符串并将其转换为JSON格式;接着通过post方法以隐式发送的方式进行上传并获得返回结果;最后输出返回结果和其中的语音转文字的信息。该部分内容的细节比较多,具体参见百度语音API开发说明http://yuyin.baidu.com/docs/asr/57
关于cuid的获取,由于笔者是在本地计算机上测试的,因此使用的是MAC地址。获取MAC地址的方法是:打开系统终端命令行窗口(Win+R,输入cmd并按Enter键),在命令行中输入命令ipconfig/all,在列出的所有连接中找到其中媒体状态不是“媒体已断开”并且属于当前连接的物理地址信息,如图2-37所示为笔者计算机MAC信息。

带你读《Python数据分析与数据化运营(第2版)》之二:数据化运营的数据来源

有关语音服务的更多信息,具体查阅http://www.xfyun.cn
上述代码执行后返回如下结果:
{"corpus_no":"6520028890940897658","err_msg":"success.","err_no":0,"result":["百度语音提供技术支持,"],"sn":"989585587221518062523"}
['百度语音提供技术支持,']
系统成功返回识别结果,录音的内容是“百度语音提供技术支持”。第2段的编码是unicode编码格式的中文。
总结:上述语音识别仅提供了关于语音转文字的方法。其实语音本身包括非常多的信息,除了相对浅层的生理和物理特征,例如语速、音调、音长、音色、音强等外,还包括更深层次的社会属性,这部分内容需要自然语音理解的深层次应用。目前的语音数据读取后主要应用方向包括:

  • 语音转文字。这也是广义上语音识别的一种,直接将语音信息转为文字信息,例如微信中就有这个小功能。
  • 语音识别。语音识别指的是对说话者通过选取语音识别单元、提取语音特征参数、模型训练、模型匹配等阶段,实现其角色识别和个体识别的过程,例如通过某段语音识别出是哪个人说的话。
  • 语音语义理解。在语音识别的基础上,需要对语义特征进行分析,目的是通过计算得到语音对应的潜在知识或意图,然后提供对应的响应内容或方法。语音识别和语音理解的差异之处在于,语音识别重在确定语音表达的字面含义,属于表层意义;而语音理解重在挖掘语音的背后含义,属于深层意义。
  • 语音合成。语音合成就是让计算机能够“开口说话”,这是一种拟人的技术方法。语音合成,又称文本转语音(Text to Speech)技术,它通过机械的、电子的方法将文字信息转变为人类可以听得懂的语音。
  • 应用集成。经过分析、识别后的信息可以与硬件集成,直接通过语音发送指令。例如通过跟Siri(苹果手机上的语音助理)的“沟通”,除了可以进行日常对话,还可以告诉你天气情况、帮你设置系统日程、介绍餐厅等。这是智能机器人在模式识别方面的典型应用。

基于上述的复杂应用场景,通常语音后续分析、处理和建模等过程都无法由数据工程师单独完成,还需要大量的语料库素材,以及社会学、信号工程、语言语法、语音学、自然语音处理、机器学习、知识搜索、知识处理等交叉学科和相关领域才有可能解开其中的密码。

2.4 本章小结

内容小结:本章的内容较多,主要涉及企业数据化运营可能产生数据的方方面面,包括数据来源的类型、通过不同方式获得运营数据以及对非结构化数据的获取等方面。不同的企业由于其行业和企业背景不同,通常不会全部覆盖其中的所有数据场景,读者可根据自身情况和需求选择。另外,大多数读者所在的企业,应该以结构化的数据为主,内容延展中的知识作为课外补充和了解即可,真正到需要用到这些知识时,再学习和查阅更多资料。本书所有示例中的原始代码,在“附件-chapter2”中的chapter2_code.ipynb中可以找到,同时在该文件夹下存储了所有示例用到的本地数据。
重点知识:本章需要读者重点掌握2.2节所讲的内容,这里介绍了数据工作者常用的数据来源,其中从文本文件读取运营数据、从关系型数据库MySQL读取数据最为常用。
外部参考:由于数据来源的获取与数据生产、采集、存储、处理和挖掘工具息息相关,不同的系统和工具之间需要了解更多才有可能更好地利用数据。以下工具或知识是本书以及很多企业中都会用到的,希望读者能进行更深入的学习。

  • Google BigQuery:BigQuery可以作为云服务应用,可以与几乎所有的Google服务打通并将数据导入其中(当然也包括Google Analytics数据)。同时BigQuery还提供了BQML,即数据库内的Machine Learning的功能,在数据库中可以实现从查询、建模、检验到预测的整个数据分析和挖掘工作,因此BQML值得读者一探究竟。
  • Google Analytics API:Google Analytics几乎是目前世界上最流行的流量采集和分析工具之一,它直接支持了多种类型的API,可以为用户提供数据导入导出、查询、账户管理等操作,包括报告API、实时API、meta API等,是Google Analytics数据分析的利器。配合Google BigQuery的hit(点击)级别/粒度的数据,可实现流量数据的二次深度发掘。
  • SAS:做数据挖掘的读者一般都会知道这个工具,SAS是数据挖掘和商业智能领域最为权威和流行的商用工具之一。该工具在很多大型企业内部都有应用,例如国家信息中心、国家统计局、卫生部、中国科学院等,其专业能力可见一斑。
  • SQL:作为关系型数据库应用的核心,常用的查询语法需要数据工作者掌握。除了用于关系型数据库外,SQL也可以应用到大数据工作处理领域,例如HIVE、Spark SQL等。其通用性(当然需要做语法需要适当修改)使得SQL几乎在各个企业都有用武之地。
  • 正则表达式:本书在多个应用示例中都用到了正则表达式,尤其在非结构化数据工作领域,正则表达式几乎是“标配”知识。

应用实践:本章的内容属于数据工作的第1步,因此希望读者能熟悉不同的数据接入和读取方法。每种数据来源类型建议读者都逐一进行实践,然后集中精力到现有工作或学习环境中,以熟练掌握获取不同数据来源的方法和技巧。

上一篇:JavaScript进阶【一】JavaScript模块化开发的基础知识


下一篇:物联网“兴奋剂”让传感器应用遍地开花