Python数据分析与数据化运营

2.2 使用Python获取运营数据-1

Author
宋天龙
发布于 2018-02-23
2845 次阅读
0 次赞
0 次分享
2.2 使用Python获取运营数据-1
AI 智能核心导读

本文系统介绍了Python读取文本数据的三种核心方式:Python内置文件操作、Numpy库与Pandas库,详细解析了各工具的常用读取方法、参数及适用场景。同时,结合数据源特性与处理目标,总结了在文本解析、矩阵计算及结构化数据分析等不同场景下选择最佳数据读取方法的策略。

说明:本文是《Python 数据分析与数据化运营》中的“2.2 使用 Python 获取运营数据”中的第一部分,由于本节内容较多,这里分几个文章。

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

1. 使用 read、readline、readlines 读取数据

Python 可以读取任何格式的文本数据,使用 Python 读取文本数据的基本步骤是:

  • 定义数据文件
  • 获取文件对象
  • 读取文件内容
  • 关闭文件对象

定义数据文件 定义数据文件即定义要读取的文件,该步骤不是必须的,可以跟“获取文件对象”整合。但为了后续操作的便捷性、全局数据对象的可维护性以及减少代码冗余,建议读者养成习惯,将数据文件预先赋值给一个对象。

定义文本数据文件的方法是:`file_name = [文件名称]`。示例:`file_name = 'd:/python_data/data/text.txt'`

文件名称中可以只写文件名,此时默认 Python 读取当前工作目录下的文件;也可以加入路径,默认使用斜杠,尤其是 Windows 下要注意用法。

获取文件对象

获取文件对象的意义是基于数据文件产生对象,后续所有关于该数据文件的操作都基于该对象产生。语法:

python
1file object = open(name [, mode][, buffering])

参数

  • `name`:要读取的文件名称,即上一个环节定义的 file_name,必填。
  • `mode`:打开文件的模式,选填,在实际应用中,rr+ww+aa+ 是使用最多的模式;完整 mode 模式如表 2-1:

表 2-1 Python 文件打开模式(mode)

模式(mode)描述
r以只读方式打开文件。文件的指针将会放在文件的开头。默认打开模式。
rb以二进制格式打开一个文件用于只读。
r+打开一个文件用于读写。
rb+以二进制格式打开一个文件用于读写。
w打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
wb以二进制格式打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
w+打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
wb+以二进制格式打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
a打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
ab以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
a+打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。
ab+以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。
  • `buffering`:文件所需的缓冲区大小,选填;0 表示无缓冲,1 表示线路缓冲。

返回

通过 open 函数会创建一个文件对象(file object)。

示例

python
1file_name = 'text.txt' 2file_object = open(file_name)

在“定义数据文件”部分提到可以将前两个环节结合起来,定义的语法是:

python
1file_object = open('text.txt')

读取文件内容

Python 基于文件对象的读取分为三种方法,如表 2-2:

表 2-2 Python 读取文件内容的 3 中方法

方法描述返回数据
read读取文件中的全部数据,直到到达定义的 size 字节数上限。内容字符串,所有行合并为一个字符串
readline读取文件中的一行数据,直到到达定义的 size 字节数上限。内容字符串
readlines读取文件中的全部数据,直到到达定义的 size 字节数上限。内容列表,每行数据作为列表中的一个对象

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

1
1
图 2-2 示例数据源文件内容

  • 通过 read 方法读取该数据文件得到的数据结果:`'line1: This is line1\nline2: This is line2'`
  • 通过 readline 方法读取该数据文件得到的数据结果:`'line1: This is line1\n'`
  • 通过 readlines 方法读取该数据文件得到的数据结果:`['line1: This is line1\n', 'line2: This is line2`

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

相关知识点:指针

Python 文件操作中的指针类似于 Word 操作中的“光标”,指针所处的位置就是“光标”的位置,它决定了 Python 的读写从哪里开始。

默认情况下,当通过 open 函数打开文件时,文件的指针处于第一个对象的位置。

因此,在上述通过 readline 读取文件内容时,获取的是第一行的数据。仍然是上面示例中的数据文件,我们通过如下代码演示基于不同指针位置读取的内容:

python
1fn = open('text.txt')# 获得文件对象 2print (fn.tell())# 输出指针位置 3line1 = fn.readline()# 获得文件第一行数据 4print (line1) # 输出第一行数据 5print (fn.tell())# 输出指针位置 6line2 = fn.readline()# 获得文件第二行数据 7print (line2)# 输出第二行数据 8print (fn.tell())# 输出指针位置 9fn.close() # 关闭文件对象

执行上述代码后,返回如下信息:

code
10 2line1: This is line1 322 4line2: This is line2 542

从返回结果看:

  • 当打开文件时,文件指针的位置处于文件开头,输出为 0;
  • 当读取完第一行之后,文件指针位置处于第一行行末,位置是第 22 个字符后面(也就是 \n 后面,\n 是换行符);
  • 当读取完第二行(最后一行)之后,文件指针位置处于第二行行末,位置是第 42 个字符后面(注意:由于是最后一行,没有换行符 \n)。

关闭文件对象

每次使用完数据对象之后,需要关闭数据对象。方法是 `file_object.close()`

提示 理论上,Python 可以读取任意格式的文件,但在这里通常以读取格式化的文本数据文件为主,其中包括有扩展名的 txtcsvtsv 等格式的文件,以及有固定分隔符分隔并以通用数据编码和字符集编码(例如 utf8ASCIIGB2312 等)存放的无扩展名格式的数据文件。在 2.3 中我们会介绍使用 Python 读取非结构化的数据的方法。

2. 使用 Numpy 的 loadtxt、load、fromfile 读取数据

Numpy 读取数据的方法包括 loadtxtloadfromfile 三种方法,概要描述如表 2-3:

表 2-3 Numpy 读取文件的三种方法

方法描述返回数据
loadtxttxt 文本中读取数据从文件中读取的数组
load使用 Numpy 的 load 方法可以读取 Numpy 专用的二进制数据文件,从 npynpzpickled 文件加载数组或 pickled 对象从数据文件中读取的数组、元组、字典等
fromfile使用 Numpy 的 fromfile 方法可以读取简单的文本文件数据以及二进制数据从文件中读取的数据

使用 loadtxt 方法读取数据文件

Numpy 可以读取 txt 格式的数据文件,数据通常都是 1 维或 2 维。

语法

python
1loadtxt(fname, dtype=<type 'float'>, comments='#', delimiter=None, converters=None, skiprows=0, usecols=None, unpack=False, ndmin=0)

参数

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

表 2-4 Numpy 数据类型

类型描述
bool用一位存储的布尔类型(值为 TRUEFALSE
inti由所在平台决定其精度的整数
int8整数,大小为一个字节,范围:-128 ~ 127
int16整数,范围:-32768 ~ 32767
int32整数,范围:-2**31 ~ 2*31-1
int64整数,范围:-2**31 ~ 2*31-1
uint8无符号整数,0 ~ 255
uint16无符号整数:0 ~ 65535
uint32无符号整数: 0 ~ 2**32-1
uint64无符号整数: 0 ~ 2**64-1
float16半精度浮点数: 16 位 ,正负号 1 位,指数 5 位,精度 10 位
float32单精度浮点数: 32 位,正负号 1 位,指数 8 位,精度 23 位
float64 / float双精度浮点数: 64 位,正负号 1 位,指数 11 位,精度 52 位
complex64复数,分别用于两个 32 位浮点数表示实部和虚部
complex128 / complex复数,分别用两个 64 位浮点数表示实部和虚部

备注:其中 2**32 代表 2 的 32 次方,其他表示方法类似。

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

返回

从文件中读取的数组

示例

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

2
2
图 2-3 示例 numpy 数据源文件内容

python
1import numpy as np # 导入numpy库 2file_name = 'numpy_data.txt' # 定义数据文件 3data = np.loadtxt(file_name, dtype='float32', delimiter=' ') # 获取数据 4print (data) # 打印数据

上述代码输出的结果如下:

code
1[[ 0. 1. 2. 3. 4.] 2[ 5. 6. 7. 8. 9.] 3[ 10. 11. 12. 13. 14.]]

使用 load 方法读取数据文件

使用 Numpy 的 load 方法可以读取 Numpy 专用的二进制数据文件,从 npynpzpickled 文件加载数组或 pickled 对象,该文件通常基于 Numpy 的 savesavez 等方法产生。

语法

python
1load(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 字符串时使用何种编码,选填。

返回

从数据文件中读取的数组、元组、字典等。

示例

我们将在这个示例中,先定义一份数据,然后保存为 .npy 格式的数据文件(该文件也在“附件-chapter2”中,名为 load_data.npy),接着使用 Numpy 的 load 方法读取并打印输出。代码如下:

python
1import numpy as np # 导入nump库 2write_data = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12]])# 定义要存储的数据 3np.save('load_data', write_data) # 保存为npy数据文件 4read_data = np.load('load_data.npy') #读取npy文件 5print (read_data)# 输出读取的数据

上述代码输出的结果如下:

code
1[[ 1 2 3 4] 2[ 5 6 7 8] 3[ 9 10 11 12]]

使用 fromfile 方法

使用 Numpy 的 fromfile 方法可以读取简单的文本文件数据以及二进制数据。

通常情况下,该方法读取的数据来源于 Numpy 的 tofile 方法,即通过 Numpy 的 tofile 方法将特定数据保存为文件(默认为二进制数据文件,无论文件扩展名如何定义),然后通过 fromfile 方法读取该二进制文件。

语法

python
1fromfile(file, dtype=float, count=-1, sep='')

参数

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

返回

从文件中读取的数据。

示例

我们仍然以“附件-chapter2”文件夹 numpy_data.txt 数据文件为例,首先通过 tofile 方法创建 1 个二进制文件,然后再对该文件进行读取。

python
1import numpy as np # 导入numpy库 2file_name = 'numpy_data.txt' # 定义数据文件 3data = np.loadtxt(file_name, dtype='float32', delimiter=' ') #获取数据 4tofile_name = 'binary' # 定义导出二进制文件名 5data.tofile(tofile_name) # 导出二进制文件 6fromfile_data = np.fromfile(tofile_name, dtype='float32') # 读取二进制文件 7print (fromfile_data) # 打印数据

上述代码输出的结果如下:

code
1[ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14.]

注意 请务必确保读入文件跟存储文件时的数据类型保持一致,否则将导致数据的错误。有兴趣的读者在使用 fromfile 导入数据时,不指定 float32 格式,看下输出结果。另外,由于使用 tofile 方法保存的数据会丢失数据形状信息,因此导入时无法重现原始数据矩阵。

3. 使用 Pandas 的 read_csv、read_fwf、read_table 读取数据

相对于 Python 默认函数以及 Numpy 读取文件的方法,Pandas 读取数据的方法更加丰富。Pandas 读取文本文件数据的常用方法如表 2-5:

表 2-5 Pandas 读取数据的常用方法

方法描述返回数据
read_csv读取csv文件DataFrame 或TextParser
read_fwf读取表格或固定宽度格式的文本行到数据框DataFrame 或TextParser
read_table读取通用分隔符分隔的数据文件到数据框DataFrame 或TextParser

使用 read_cvs 方法读取数据

通过 read_csv 方法可以读取 csv 格式的数据文件。

语法

python
1read_csv(filepath_or_buffer, sep=',', delimiter=None, header='infer', names=None, index_col=None, usecols=None, **kwds)

参数

read_csv 的参数众多,以下介绍最常用的几个参数)

  • `filepath_or_buffer`:字符串,要读取的文件对象,必填。
  • `sep`:字符串,分隔符号,选填,默认值为英文逗号 ,
  • `names`:类数组,列名,选填,默认值为空。
  • `skiprows`:类字典或整数型,要跳过的行或行数,选填,默认为空。
  • `nrows`:整数型,要读取的前记录总数,选填,默认为空,常用来在大型数据集下做初步探索之用。
  • `thousands`:字符串,千位符符号,选填,默认为空。
  • `decimal`:字符串,小数点符号,选填,默认为点(.),在特定情况下应用,例如欧洲的千位符和小数点跟中国地区相反,欧洲的 4.321,1 对应中国的 4,321.1。

返回

DataFrame 或 TextParser

示例

我们以“附件-chapter2”文件夹 csv_data.csv 数据文件为例,直接读取文件并打印输出。数据内容如下图 2-4:

3
3
图 2-4 数据文件内容

python
1import pandas as pd # 导入Pandas库 2csv_data = pd.read_csv('csv_data.csv', names=['col1', 'col2', 'col3', 'col4', 'col5']) # 读取csv数据 3print (csv_data) # 打印输出数据

上述代码输出的结果如下:

code
1col1 col2 col3 col4 col5 20 0 1 2 3 4 31 5 6 7 8 9 42 10 11 12 13 14

使用 read_fwf 方法读取数据

通过 read_fwf 方法可以读取表格或固定宽度格式的文本行到数据框。

语法

python
1read_fwf(filepath_or_buffer, colspecs='infer', widths=None, **kwds)

参数

read_fwfread_csv 一样都具有非常多的参数(只是在语法中前者通过 kwds 省略了,查询完整语法请使用 help(pd.read_fwf)),并且大多数参数的用法相同。

除了 read_csv 中的常用参数外,以下介绍几个 read_fwf 特有且常用的参数。

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

返回

DataFrame 或 TextParser

示例

我们以“附件-chapter2”文件夹 fwf_data 数据文件为例,直接读取文件并打印输出。数据内容如图 2-5:

2-5
2-5
图 2-5 数据文件内容

python
1import pandas as pd # 导入Pandas库 2fwf_data = pd.read_fwf('fwf_data', widths=[5, 5, 5, 5], names=['col1', 'col2', 'col3', 'col4']) # 读取csv数据 3print (fwf_data) # 打印输出数据

上述代码输出的结果如下:

code
1 col1 col2 col3 col4 20 a2331 a9013 a3211 a9981 31 b4432 b3199 b9766 b2212 42 c3294 c1099 c7631 c4302

使用 read_table 方法读取数据

通过 read_table 方法可以读取通用分隔符分隔的数据文件到数据框。

语法

python
1read_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_csvsep=','(默认)。因此,具体参数请查阅 read_csv 的参数部分。

返回

DataFrame 或 TextParser

示例

我们以“附件-chapter2”文件夹 table_data.txt 数据文件为例,直接读取文件并打印输出。数据内容如下图 2-6:

2-6
2-6
图 2-6 数据文件内容

python
1import pandas as pd # 导入Pandas库 2table_data = pd.read_table('table_data.txt', sep=';', names=['col1', 'col2', 'col3', 'col4', 'col5']) # 读取csv数据 3print (table_data) # 打印输出数据

上述代码输出的结果如下:

code
1col1 col2 col3 col4 col5 20 0 1 2 3 4 31 5 6 7 8 9 42 10 11 12 13 14

总结:作为数据分割(或分列)的常用思路分为两种,一种是基于固定宽度,一种是基于分割符号。上述三种方法中,常用的方法是第二和第三种,即 read_fwfread_table 方法。

除了上述用于读取文本文件的方法外,Pandas 还提供了非常丰富的用于其他场景的数据读取方法,限于篇幅,在此不做更多介绍,仅提供读取列表供有兴趣的读者参考以及做知识延伸。具体如表 2-6:

表 2-6 Pandas 其他数据读取方法

方法描述返回数据
read_clipboard读取剪贴板数据,然后将对象传递给 read_table 方法DataFrame 或 TextParser
read_excel从 excel 中读取数据DataFrame 或 DataFrame 构成的字典
read_gbq从 Google Bigquery 中读取数据DataFrame
read_hdf读取文件中的 Pandas 对象所选择的数据对象
read_html读取 HTML 中的表格由 DataFrame 构成的字典
read_json将 JSON 对象转换为 Pandas 对象Series 或 DataFrame,具体取决于参数 typ 设置
read_msgpack从指定文件中加载 msgpack Pandas 对象文件中的对象类型
read_pickle从指定文件中加载 pickled Pandas 或其他 pickled 对象文件中的对象类型
read_sas读取 XPORT 或 SAS7BDAT 格式的 SAS(统计分析软件)文件DataFrame 或 SAS7BDATReader 或 XportReader,具体取决于设置
read_sql读取 SQL 请求或数据库中的表DataFrame
read_sql_query从 SQL 请求读取数据DataFrame
read_sql_table读取 SQL 数据库中的表DataFrame
read_stata读取 Stata(统计分析软件)文件DataFrame 或 StataReader

4. 如何选择最佳读取数据的方法

关于“最佳”方法其实没有固定定义,因此所谓的最佳方法往往跟以下具体因素有关:

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

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

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