[学习笔记]Python for Data Analysis, 3E-6.数据加载、存储和文件格式

读取数据并使其可访问(通常称为数据加载)是使用本书中大多数工具的必要第一步。术语parsing(分析)有时也用于描述加载文件数据并将其解释为表和不同的数据类型。我将重点介绍使用pandas进行数据输入和输出,尽管其他库由许多工具可以帮助读取和写入各种格式的数据。
输入和输出通常分为几个主要类别:读取文本文件和其他更有效的磁盘格式,从数据库加载数据以及与WebAPI等网络源交互。

6.1以文本格式读取和写入数据

pandas具有许多函数,用于将表格数据作为DataFrame对象进行读取。下表总结了其中的一些。pandas.read_csv是本书中最常使用的函数。我们将会在6.2节二进制形式中查看二进制数据格式。

[表]pandas中的文本和二进制数据加载函数

我将概述这些函数的机制,这些函数旨在将文本数据转化为DataFrame。这些函数的可选参数可分为以下几类:

  • 索引
    可以将以一列或者多列作为返回的DataFrame,无论是否从文件、你提供的参数中获取列名
  • 类型推断和数据转换
    包括用户定义的值转换和缺失值标记的自定义列表
  • 日期和时间解析
    包括合并功能,包括将分布在多个列中的日期和时间信息合并到结果中的单个列中
  • 迭代
    支持循环访问非常大的文件块
  • 数据不干净问题
    包括跳过行或页脚、注释或其他次要内容,如以逗号分隔的数千个数字数据

因为现实世界中的数据可能非常混乱,因此随着时间的推移,一些数据加载函数(尤其是pandas.read_csv)已经积累了一长串可选参数。对不同参数的数量感到不知所措时正常的(pandas.read_csv大约有50个可选参数)。在线pandas文档有很多关于这些如何工作的示例。
其中一些函数执行类型推断,因为列数据类型不是数据格式的一部分。这意味着你不必指定哪些列是数字、整数、布尔值或字符串。其他数据格式(如HDF5、ORC和Parquet),在格式中嵌入了数据类型信息。
处理日期和其他自定义类型可能需要额外的工作。
让我们从一个小的逗号分隔值(CSV)文本文件开始:

# 使用Unix的'cat' shell命令将文件的原始内容打印到屏幕上。如果你使用的是windows,你可以用type而不是cat来实现相同的效果
!cat examples/ex1.csv # 返回逗号分隔的文本文件原始内容

# 由于文件是用逗号隔开的(虽然显示是表格),我们可以用pandas.read_csv来将它读取为DataFrame
df = pd.read_csv('examples/ex1.csv')

# 没有标题行的文件示例
!cat examples/ex2.csv
# 用pandas读取此文件,可以选择pandas默认分配列名,也可以自己指定列名
pd.read_csv('examples/ex2.csv', header=None) # pandas默认分配列名(从0开始的整数标题),不加header=None,会默认第一行为是标题行并生成DataFrame
pd.read_csv('examples/ex2.csv', names=['a', 'b', 'c', 'd', 'message']) # 自己指定列名

# 如果你希望'message'列成为DataFrame的索引,你可以用index_col传递第4列索引或'message'
names = ['a', 'b', 'c', 'd', 'message']
pd.read_csv('examples/ex2.csv', names=names, index_col='message') # 先设置names为列名,然后将其中'message'列作为行索引

# 如果想从多个列中形成分层索引(如8.1节:分层索引中所述),则需要传递列号或名称的列表:
!cat examples/csv_mindex.csv
parsed = pd.read_csv('examples/csv_mindex.csv', index_col=['key1', 'key2']) # 'key1'和'key2'组成分层索引

某些情况下,表可能没有固定的分隔符,而是使用空格或其他一些模式来分隔字段

!cat examples/ex3.txt # 返回纯文本文件

# 虽然可以手动修改文件,但此处的字段由可变数量的空格分隔。在这些情况下,可将正则表达式作为分隔符传递给pandas.read_csv
# \s匹配所有空白符,包括空格、制表符、换页符等,等价于[\f\n\r\t\v];+表示匹配前面的子表达式一次或多次。所以\s+表示匹配一次或多次的空白符
result = pd.read_csv('examples/ex3.txt', sep='\s+') # 以一次或多次空白符为分隔符
# 由于列名数比数据列数少一个,因此pandas.read_csv推断第一列是DataFrame的索引

文件解析函数由很多附加参数,可以帮助处理出现的各种异常文件格式(详见6.2中的表)。

# 例如,可以利用skiprows跳过文件的第一行、第三行和第四行
!cat examples/ex4.csv
pd.read_csv('examples/ex4.csv', skiprows=[0, 2, 3]) # 略过文件的第一行、第二行和第四行

处理缺失值是文件读取过程中一个非常重要且经常有细微差别的部分。缺失值通常不存在(空字符串)或由某个占位符标记。默认情况下,pandas用NA或NULL表示缺失值。

!cat examples/ex5.csv
result = pd.read_csv('examples/ex5.csv') # pandas将默认缺失值(如'NA'字符串、空值)输出为NaN
pd.isna(result) # 生成布尔数组,其中值为NaN的元素对应的布尔值为True

# na_values参数接受要被识别为缺失值的字符串序列
result = pd.read_csv('examples/ex5,csv', na_values=['NULL']) # 除了默认缺失值外,将所有'NULL'的元素被识别为缺失值

# pandas.read_csv有一个默认NA值表示形式的列表,但是可以使用keep_default_na选项禁用这些默认值
result2 = pd.read_csv('examples/ex5.csv', keep_default_na=False) # 禁用默认缺失值
result2.isna() # 由于禁用默认缺失值,所以所有元素对应的布尔值都是False
result3 = pd.read_csv('examples/ex5.csv', keep_default_na=False, na_values=['NA']) # 只将'NA'识别为缺失值
result3.isna() # 只有'NA'元素对应的布尔值为True

# 可以在字典中的每一列指定不同的默认NA值
sentinels = {'message': ['foo', 'NA'], 'something': ['two']}
pd.read_csv('examples/ex5.csv', na_values=sentinels, keep_default_na=False) # 对'message'列,'foo'和'NA'为缺失值,对'something'列,'two'是缺失值

下表列出了pandas.read_csv的一些函数参数。

[表]一些pandas.read_csv的函数参数

分段读取文本文件

在处理非常大的文件或找出正确的参数集以处理大文件时,你可能只想读取文件的一小部分或循环文件的较小块。

pd.options.display.max_rows = 10 # 设置pandas最多显示10行条目(包括...条目)
result = pd.read_csv('examples/ex6.csv')

# 传递nrows参数:只读取前若干行
pd.read_csv('example/ex6.csv', nrows=5)

# 为chunksize参数指定一个行数,则可以分段读取文件
chunker = pd.read_csv('example/ex6.csv', chunksize=1000) # 1000行为一段
type(chunker) # 返回迭代器pandas.io.parsers.TextFileReader:它允许你按照chunksize迭代文件的各部分
# 迭代ex6.csv,聚合'key'列的值计数:
tot = pd.Series([], dtype='int64')
for piece in chunker: # piece为迭代部分
    tot = tot.add(piece['key'].value_counts(), fill_value=0) # 迭代部分的DataFrame的'key'列的value_counts加到tot中,缺失值用0代替
tot = tot.sort_values(ascending=False) # 降序排列tot
tot[:10] # 显示Series前10个条目

# TextFileReader迭代器也可以通过.getchunk()方法来返回任意大小的块(当然是从指针所在位置开始计数)
chunker.get_chunk(12) # 返回一个包含12个条目的块

将数据写入文本格式

数据也可以被导出到一个分隔形式的文件。

data = pd.read_csv('examples/ex5.csv')
# 使用DataFrame的.to_csv方法,可以将数据导出成一个逗号分隔的文件
data.to_csv('examples/out.csv')
!cat examples/out.csv   # 缺失值在写入的文件中会显示为空值

# 别的分隔符也可以被使用(如'|')
import sys
data.to_csv(sys.stdout, sep='|') # 写入sys.stdout,则会将文本结果打印到控制台而不是写入到文件

# 不希望写入时,缺失值被标记为空值,则可传递na_rep指定缺失值的标记值
data.to_csv(sys.stdout, na_rep='NULL') # 所有缺失值在写入时,替换为'NULL'

# 如果传递index=False和header=False,则行和列标签都不会被写入(如果数据中有行和列标签,则默认会被写入)
data.to_csv(sys.stdout, index=False, header=False)

# 你还可以仅写入列的子集,并且按照你选择的顺序
data.to_csv(sys.stdout, index=False, columns=['a', 'b', 'c']) # 只写入'a','b','c'三列

使用其他分隔形式

使用如pandas.read_csv的函数可以从磁盘中加载大多数形式的表格数据。但在某些情况下,可能需要进行一些手动处理。接收到包含一个或者多个错误行的文件并不少见。

!cat examples/ex7.csv

# 对任何带有单字符分隔符的文件,你可以使用Python内置的csv模块。为了使用它,你必须传递任何打开的文件或类文本对象给csv.reader
import csv
f = open('examples/ex7.csv')
reader = csv.reader(f)
for line in reader: # 循环访问读取器并生成删除任何引号字符的值列表
    print(line)
f.close()

# 将文件读入行列表
with open('examples/ex7.csv') as f:
    lines = list(csv.reader(f))
# 将行列表拆分成标题行和数据行
header, values = lines[0], lines[1:]
# 利用字典生成式和表达式创建数据列的字典(注意:这将在大文件上使用大量内存),这将会将行转置为列
data_dict = {h: v for h, v in zip(header, zip(*values))}

CSV文件有很多不同的格式。要定义有不同的分隔符、字符串引用约定或行终止符的新格式,我们可以定义一个简单的子类:csv.Dialect

class my_dialect(csv.Dialect):
    lineterminator = '\n'
    delimiter = ';'
    quotechar = '"'
    quoting = csv.QUOTE_MINIMAL
reader = csv.reader(f, dialect=my_dialect) # dialect是方言的意思
# 还可以将单个CSV方言参数(如delimiter)作为关键字给csv.reader,而不用定义一个子类
reader = csv.rader(f, delimiter='|') # 分隔符为'|'

下表是关于CSV可能的方言参数和作用。

[表]CSV dialect参数

注意:对于具有更复杂或固定的多字符分隔符的文件,则无法使用csv模块。在这些情况下,你必须用字符串的split方法或正则表达式方法re.split来进行行拆分和其他数据清理。值得庆幸的是,如果你传递了必要的参数,pandas.read_csv几乎可以执行任何你想要的操作,因此你很少需要手动解析文件。

# 要手动写入带分隔符的文件,可以使用csv.write。它接受一个开放的、可写的文件对象,以及和csv.reader相同的方言和格式选项:
with open('mydata.csv', 'w') as f:
    writer = csv.writer(f, dialect=my_dialect)  # 创建写入器对象
    writer.writerow(('one', 'two', 'three'))    # 利用writer的writerow方法写入行数据
    writer.writerow(('1', '2', '3'))
    writer.writerow(('4', '5', '6'))
    writer.writerow(('7', '8', '9'))

JSON数据

JSON(JavaScript对象表示法的缩写)已成为在Web浏览器和其他应用程序之间通过HTTP请求发送数据的标准格式之一。它是一种比CSV等表格文本形式更自由的数据格式

# JSON数据的示例
obj = """
{"name": "Wes",
 "cities_lived": ["Akron", "Nashville", "New York", "San Francisco"],
 "pet": null,
 "siblings": [{"name": "Scott", "age": 34, "hobbies": ["guitars", "soccer"]},
              {"name": "Katie", "age": 42, "hobbies": ["diving", "art"]}]
}
"""

JSON几乎是有效的Python代码,除了它的空值和其他一些细微差别(如不允许在列表末尾使用尾随逗号)。JSON基本类型包括对象(字典)、数组(列表)、字符串、数字、布尔值和null。对象中的所有键都必须是字符串。有几个用于读取和写入JSON数据的Python库。这里将使用json库,因为它内置于Python标准库中。

# 使用json.loads可以将JSON字符串转化为Python字典
import json
result = json.loads(obj) # 返回一个字典

# 利用json.dumps可以将Python对象转化为JSON字符串
asjson = json.dumps(result) # 返回一个JSON字符串

# 如何将JSON对象或对象列表转换为DataFrame或其他一些数据结构以进行分析将取决于你
# 你可以方便地将字典列表(以前是JSON对象)传递给DataFrame构造函数,并选择数据字段的子集
siblings = pd.DataFrame(result['siblings'], columns=['name', 'age']) # 返回只有'name'列和'age'列的DataFrame

# pandas.read_json函数将自动将JSON数据集转换为特定排列的Series或DataFrame
!cat examples.example.json
# 未设置任何选项,则默认选项假定JSON数组中的每个对象都是表中的一行
data = pd.read_json('examples/example.json')

有关读取和操作JSON数据(包括嵌套记录)的扩展示例,详见第13章:数据分析示例中的USDA食物数据库示例。

# 如果你想要将数据从pandas中导出到json,一种方法是在Series或者DataFrame上使用to_json方法
data.to_json(sys.stdout) # 这里导出到控制台,也可以导出到文件
data.to_json(sys.stdout, orient='records') # 另一种导出格式

XML和HTML:网页抓取

Python有很多库用于在无处不在的HTML和XML格式中读取和写入数据。示例包括lxml、Beautiful Soup和htmp5lib。虽然lxml通常相对快得多,但其他库可以更好地处理格式错误的HTML或XML文件。
pandas有一个内置函数pandas.read_html,它使用所有这些库来自动将HTML文件中的表解析为DataFrame对象。为了展示它是如何工作的,我从美国FDIC下载来一个HTML文件。
首先,你必须安装一些read_html库使用的附加库:lxml、beautifulsoup4、html5lib

# 如果你使用conda,可以用下面命令安装这些附加库
conda install lxml beautifulsoup4 html5lib
# 也可以用pip命令安装
pip install lxml

pandas.read_hmtl函数有许多选项,但默认情况下,它会搜索并尝试分析所有包含在

标签中的表格数据。返回的结果是一个DataFrame对象的列表

tables = pd.read_html('example/fdic_failed_bank_list.html') # 返回一个DataFrame对象组成的列表
len(tables) # 返回1,说明列表里只有一个DataFrame
failures = tables[0] # 读取列表中的DataFrame元素
failures.head() # 显示DataFrame前5行
# 注意:当有很多列时,因为无法在一行内显示,所以pandas会插入换行符'\'

正如你将在后续章节中了解到的那样,从这里我们可以继续进行一些数据清理和分析。

# 按年计算银行倒闭次数
colse_timestamps = pd.to_datetime(failures['Closing Date']) # 将'Closing Date'列的数据转化为datetime类型的,并返回对应的Series
close_timestamps.dt.year.value_counts() # 按照年份计数

用lxml.objectify解析XML文件

XML是另一种常见的支持元数据分层嵌套的结构化数据格式。当前阅读的本文也是由一系列大的XML文件创建而来。
前面已经展示了使用lxml或Beautiful Soup解析来自HTML的数据的pandas.read_html函数。XML和HTML结构上很相似,但是XML更常见。在这里,一个如何使用lxml模块来解析从更通用的XML文件格式的例子将被给出。
多年来,纽约大都会交通管理局(MTA)以XML格式发布了许多关于其公共汽车和火车服务的数据。在这里,我们将查看包含在一组XML文件中的性能数据。每个火车或公共汽车服务都有一个不同的文件(如Metro-North Railroad的Performance_MNR.xml文件),其中包含一系列XML记录,其形式如下所示:

<INDICATOR>
  <INDICATOR_SEQ>373889</INDICATOR_SEQ>
  <PARENT_SEQ></PARENT_SEQ>
  <AGENCY_NAME>Metro-North Railroad</AGENCY_NAME>
  <INDICATOR_NAME>Escalator Availability</INDICATOR_NAME>
  <DESCRIPTION>Percent of the time that escalators are operational
  systemwide. The availability rate is based on physical observations performed
  the morning of regular business days only. This is a new indicator the agency
  began reporting in 2009.</DESCRIPTION>
  <PERIOD_YEAR>2011</PERIOD_YEAR>
  <PERIOD_MONTH>12</PERIOD_MONTH>
  <CATEGORY>Service Indicators</CATEGORY>
  <FREQUENCY>M</FREQUENCY>
  <DESIRED_CHANGE>U</DESIRED_CHANGE>
  <INDICATOR_UNIT>%</INDICATOR_UNIT>
  <DECIMAL_PLACES>1</DECIMAL_PLACES>
  <YTD_TARGET>97.00</YTD_TARGET>
  <YTD_ACTUAL></YTD_ACTUAL>
  <MONTHLY_TARGET>97.00</MONTHLY_TARGET>
  <MONTHLY_ACTUAL></MONTHLY_ACTUAL>
</INDICATOR>
# 使用lxml.objectify,我们可以解析文件并用getroot函数得到一个XML的根结点
from lxml import objectify
path = 'datasets/mta_perf/Performance_MNR.xml'
with open(path) as f:
    parsed = objectify.parse(f)
root = parsed.getroot() # 得到XML的根结点
data = []
skip_fields = ['PARENT_SQE', 'INDICATOR_SEQ', 'DESIRED_CHANGE', 'DECIMAL_PLACES'] # 要跳过的标签
for elt in root.INDICATOR: # root.INDICATOR会返回一个生成器产生每一个<INDICATOR>XML元素
    el_data = {} # 创建字典
    for child in elt.getchildren():
        if child.tag in skip_fields:
            continue
        el_data[child.tag] = child.pyval # 向字典中添加键值对
    data.append(el_data)  # 将字典作为元素添加到列表中
perf = pd.DataFrame(data) # 将字典转化为DataFrame
perf.head()

# pandas的pandas.read_xml函数(但这个函数只在version1.3可用,但其他版本无法使用)可以在一行表达式中完成这个流程
perf2 = pd.read_xml(path)
perf2.head()
# 对更完整的XML文件,参考pandas.read_xml的文档字符串,它描述了如何选择和过滤来提取感兴趣的表。

6.2二进制数据格式

存储(或者序列化)二进制格式文件中的数据的简单方法是用Python的内置pickle模块。pandas对象都有to_pickle方法用于将数据以pickle格式写入磁盘:

frame = pd.read_csv('example/ex1.csv')   # 读取csv文件到DataFrame
frame.to_pickle('examples/frame_pickle') # 将DataFrame对象以pickle格式写入磁盘

Pickle文件一般只在Python中可读。你可以用内置的pickle模块直接读取任何’pickled’对象,或者直接方便地用pandas.read_pickle

pd.read_pickle('example/frame_pickle')

注意:pickle只推荐作为短期存储的文件格式。它的问题是很难保证这种格式随着时间的推移仍然稳定;一个今天生成的pickled对象可能在之后的库版本就不再能unpickle。pandas已经尝试保持尽可能向下兼容,但是在未来的某个时间点,仍然可能打破pickle格式。

pandas有内置支持一些其他开源二进制数据格式,如HDF5,ORC和Aphache Parquet。举个例子,如果你安装了pyarrow包(使用conda install pyarrow),然后你可以通过pandas.read_parquet来读取Parquet文件:

fec = pd.read_parquet('datasets/fec/fec.parquet')

读取微软Excel文件

pandas也支持使用pandas.ExcelFile类或pandas.read_excel函数读取存储在Excel2003(以及更高版本)文件中的表格数据。在内部,这些工具使用附加的包xlrd和openpyxl来分别读取旧版的XLS和新版的XLSX文件。这些包必须通过pip或conda分别安装:

conda install openpyxl xlrd
# 使用pandas.ExcelFile,通过传递一个xls或者xlsx文件的路径来创建一个实例
xlsx = pd.ExcelFile('examples/ex1.xlsx')
# 通过.sheet_names属性获得可用的工作簿的名称
xlsx.sheet_names
# 利用.parse方法将存储在工作簿的数据读取到DataFrame中
xlsx.parse(sheet_name='Sheet1')
# Excel表有一个索引列(第0列),所以可以在.parse方法中,通过设置index_col=0来告诉DataFrame第0列是索引列
xlsx.parse(sheet_name='Sheet1', index_col=0)

如果你想读取一个文件中的多个sheets,那么使用pandas.ExcelFile更快,但是你也可以简单地传递文件名到pandas.read_excel来实现:

# 使用pandas.read_excel方法直接将xlsx文件的sheet1读取到DataFrame中
frame = pd.read_excel('examples/ex1.xlsx', sheet_name='Sheet1')

为了将pandas数据写入到Excel格式的文件中,你必须先创建一个ExcelWriter对象,然后通过pandas对象的to_excel方法将数据写入到该对象中

# 如何将pandas数据写入Excel格式的文件中

# 方法一:创建ExcelWriter对象,然后通过pandas对象的to_excel方法将数据写入到该对象中
writer = pd.ExcelWriter('examples/ex2.xlsx') # 传递文件路径,创建ExcelWriter对象
frame.to_excel(writer, 'Sheet1') # 将DataFrame写入到ExcelWriter对象中,并指定写入的工作簿
writer.save # 文件保存

# 方法二:直接调用pandas.to_excel方法,并船体传递文件路径
frame.to_excel('examples/ex2.xlsx')

使用HDF5格式文件

HDF5是一种备受推崇的文件格式,它用于存储大量科学数组数据。它可以作为C语言库使用,并且具有许多其他语言的接口,包括Java、Julia、MATLAB和Python。HDF5中的’HDF’表示分层数据格式(hierarchical data format)。每一个HDF5文件可以存储多个数据集以及支持元数据。与更简单的格式相比,HDF5支持具有多种压缩模式的动态压缩,从而能够更有效地存储具有重复模式的数据。HDF5是处理不匹配内存的数据集的不错选择,因为你可以有效地读取和写入较大数组的小部分。
要开始使用HDF5和pandas,你必须先用conda安装pytables包:

conda install pytables

注意:Pytables包在PyPI中被称为’tables’包,所以如果你要用pip安装,你必须运行pip install tables命令。

尽管可以使用PyTables或h5py库直接访问HDF5文件,但pandas提供了一个高级接口,简化了Series和DataFrame对象的存储。HDFStore类的工作方式类似于字典,且可可以处理低级详细信息:

frame = pd.DataFrame({'a': np.random.standard_normal(100)})
store = pd.HDFStore('examples/mydata.h5') # 创建一个HDFStore实例
store['obj1'] = frame # 赋值DataFrame
store['obj1_col'] = frame['a'] # 赋值Series

# HDF5文件中的对象可以通过类似字典的API检索
store['obj1']

# HDFStore支持两种存储模式,'fixed'和'table'(默认是'fixed')。后者通常更慢,但支持使用特殊的语法进行查询操作:
# put是store['obj2'] = frame方法的显化版本,但允许我们设置其他参数,如存储模式
store.put('obj2', frame, format='table') # 'table'模式存储
store.select('obj2', where=['index >= 10 and index <= 15']) # 查询索引在10到15之间的条目
store.close()

# pandas.read_hdf函数提供了这些工具的捷径:
frame.to_hdf('examples/mydata.h5', 'obj3', format='table')
pd.read_hdf('examples/mydata.h5', 'obj3', mode='r+', where=['index < 5']) # mode必须设置为r+

# 可以通过os.remove方法来删除文件
import os
os.remove('examples/mydata.h5')

如果你正在处理存储在远程服务器(如Amazon S3或HDFS)上的数据,则使用专为分布式存储(如Aphache Parquet)设计的其他二进制格式可能更合适。

如果你在本地处理大量数据,我建议你探索PyTables和h5py,看看它们是否能满足你的需求。由于许多数据分析问题都是I/O密集型的(而不是与CPU绑定的),因此使用像HDF5这样的工具可以极大地加速你的应用程序。

HDF5不是数据库,它最适合一次写入,多次读取的数据集。虽然可以随时将数据添加到文件中,但如果多个编写器同时这样做,则文件可能损坏。

6.3与Web APIs交互

许多网站都有公共APIs,它们通过JSON或者其他格式提供数据。有很多方法可从Python访问这些APIs:我推荐的方法是requests包,它可以使用pip或conda命令安装:

conda install requests

要查找GitHub上pandas的最后30个GitHub问题,我们可以使用requests库来发送一个GET的HTTP请求:

import requests
url = 'http://api.github.com/repos/pandas-dev/pandas/issues'
resp = requests.get(url)
resp.raise_for_status() # 在使用requests.get之后总是调用raise_for_status来检查HTTP错误是一个好习惯
data = resp.json()      # 响应对象的json方法会返回一个包含将已解析的JSON数据作为字典或列表(依赖于返回的JSON)的Python对象
# 这里data是字典组成的列表
data[0]['title']        # 由于检索的结果基于实时数据,因此在运行此代码时看到的内容可能会不同

# data中的每个元素是一个字典,其中包含正在一个GitHub问题页的所有数据(评论除外)。我们可以直接将data传递给pandas.DataFrame并提取感兴趣的字段
issues = pd.DataFrame(data, columns=['number', 'title', 'labels', 'state'])

6.4与数据库交互

在业务设置中,许多数据可能不会存储在文本或Excel文件中。基于SQL的关系数据库(如SQL服务器、PostgreSQL和MySQL)被广泛使用,许多代替数据库已经变得非常流行。数据库的选择通常取决于应用程序的性能、数据完整性和可伸缩性需求。
pandas有一些函数可以简化加载SQL查询的结果到DataFrame的过程。例如,我用Python内置的sqlite3驱动程序创建一个SQLite3数据库:

import sqlite3
query = '''
        CREATE TABLE test
        (a VARCHAR(20), b VARCHAR(20),
         c REAL,        d INTEGER
        );'''
con = sqlite3.connect('mydata.sqlite') # 创建sqlite3数据库连接
con.execute(query)  # 创建表
con.commit()

# 插入几行数据
data = [("Atlanta", "Georgia", 1.25, 6),
        ("Tallahassee", "Florida", 2.6, 3),
        ("Sacramento", "California", 1.7, 5)]
stmt = "INSERT INTO test VALUES(?, ?, ?, ?)"
con.executemany(stmt, data) # 插入多条数据
con.commit()

# 多数Python SQL驱动程序从表中选择数据时会返回元组的列表
cursor = con.execute('SELECT * FROM test') # 执行查询操作
rows = cursor.fetchall() # 返回查询的所有结果:结果是元组组成的列表

# 可以将元组的列表传递给DataFrame构造函数,但还需要包含在cursor的description属性中的列名
# 注意,对SQLite3,cursor.description仅仅提供列名(其他字段是Python的数据库API规范的一部分,是None),但对于其他数据库驱动程序,更多列信息被提供
cursor.description # 返回四个元组,每个元组的索引为0的元素为列名
pd.DataFrame(rows, columns=[x[0] for x in cursor.description])

你不希望每次查询数据库时都大量重复的修改。SQLAlchemy是一个流行的Python-SQL工具包,它抽象出SQL数据库的很多常见差异。pandas有read_sql函数,使你可以轻松地从一个一般的SQLAIchemy连接中读取数据。你可以使用conda安装SQLAIchemy:

conda install sqlalchemy

现在,我们用SQLAIchemy连接到相同的SQLite数据库并读取之前创建表格的数据:

import sqlalchemy as sqla
db = sqla.create_engin('sqlite:///mydata.sqlite') # 创建一个SQLAIchemy连接
pd.read_sql('SELECT * FROM test', db) # 利用pandas.read_sql从SQLAIchemy连接读取数据:返回一个DataFrame
!rm mydata.sqlite

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值