将表格型数据读取为DataFrame对象是pandas的重要特征,read_csv和read_table可能是后期我们使用最多的函数。
从一个小型的逗号分隔文本文件(CSV)开始:
!type ex1.csv
a,b,c,d,message
1,2,3,4,hello
5,6,7,8,world
9,10,11,12,foo
with open('ex1.csv') as f:
lines = [x.rstrip() for x in f]#删除 string 字符串末尾的指定字符(默认为空格)
lines
['a,b,c,d,message', '1,2,3,4,hello', '5,6,7,8,world', '9,10,11,12,foo']
df = pd.read_csv('ex1.csv')#读取逗号分隔文件
df
a b c d message
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo
header = None参数允许自动分配默认列名,也可以自己指定列名:
pd.read_csv('ex2.csv',names = ['a','b','c','d','message'])
a b c d message
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo
假设你想要message列成为返回DataFrame的索引,你可以指定位置4的列为索引,或将‘message’传给参数index_col:
names = ['a','b','c','d','message']
pd.read_csv('ex2.csv',names = names,index_col = 'message')
a b c d
message
hello 1 2 3 4
world 5 6 7 8
foo 9 10 11 12
如果你想从多个类中形成一个分层索引,需要传入一个包含序列号或列明名的列表:
!type csv_mindex.csv
key1,key2,value1,value2
one,a,1,2
one,b,3,4
one,c,5,6
one,d,7,8
two,a,9,10
two,b,11,12
two,c,13,14
two,d,15,16
parsed = pd.read_csv('csv_mindex.csv',index_col = ['key1','key2'])
parsed
value1 value2
key1 key2
one a 1 2
b 3 4
c 5 6
d 7 8
two a 9 10
b 11 12
c 13 14
d 15 16
在某些情况下,一张表的分隔符并不是固定的,使用空白或其他方式来分隔字段。考虑如下文本文件:
list(open('ex3.txt'))
[' A B C\n',
'aaa -0.264438 -1.026059 -0.619500\n',
'bbb 0.927272 0.302904 -0.032399\n',
'ccc -0.264273 -0.386314 -0.217601\n',
'ddd -0.871858 -0.348382 1.100491\n']
当字段是以多种不同数量的空格分开时,可以向read_csv传递一个正则表达式作为分隔符。本例中,正则表达式为\s+,因此我们可得
pd.read_csv('ex3.txt',sep = '\s+')#由于列名的数量比数据的列数少一列,因此read_csv推断第一列应当作为DataFrame的索引
A B C
aaa -0.264438 -1.026059 -0.619500
bbb 0.927272 0.302904 -0.032399
ccc -0.264273 -0.386314 -0.217601
ddd -0.871858 -0.348382 1.100491
可以在read_csv中使用skiprows来跳过第一行、第三行和第四行,传入参数skiprows = [0,2,3]。
在尝试大文件之前,我们可以先对pandas的显示设置进行调整,使之更为紧凑。
pd.options.display.max_rows = 10#最大显示行数为10行
如果你只想读取一小部分行,可以指明要读取的行数nrows:
为了分块读入文件,可以指定chunksize作为每一块的行数,read_csv返回的TextParser对象允许你根据chunksize遍历文件。
#例如,我们可以遍历ex6.csv,并对'key'列聚合获得计数值:
tot = pd.Series([])
for piece in chunker:
tot = tot.add(piece['key'].value_counts(),fill_value = 0)
tot = tot.sort_values(ascending = False)
tot[:10]
X 210.0
E 207.0
O 197.0
L 196.0
Q 193.0
F 187.0
H 182.0
K 180.0
V 178.0
J 175.0
dtype: float64
TextParser对象还具有get_chunk方法,允许你按照任意大小读取数据块
a = pd.read_csv('ex6.csv',chunksize=1000)
a.get_chunk(size=4000)#省去文件中前400行,只显示4000行以后的内容,并按1000行分块显示
for x in a:
print(x)
将数据写入文本格式
使用DataFrame的to_csv方法,可以将数据导出为逗号分隔的文件。
当然,其他的分隔符也是可以的,(写入到sys.stdout时,控制台中打印的中文结果)
sys模块可以实现程序与python解释器交互,提供一系列变量或函数在python运行时的环境。sys.stdout指的是标准输出。
缺失值在输出时以空字符串出现,也可以使用na_rep参数对缺失值进行标注
import sys
data.to_csv(sys.stdout,sep='|',na_rep = 'NULL')
|something|a|b|c|d|message
0|one|1|2|3.0|4|NULL
1|two|5|6||8|world
2|three|9|10|11.0|12|foo
默认行和列的标签都会被写入,不过传入index = False,header = False二者也都可以禁止写入。
json数据
JSON已经成为Web浏览器和其他应用间通过HTTP请求发送数据的标准格式它是一种比CSV等表格文本形式更为自由的数据形式。
json非常接近与有效的Python代码,处理它的空值null合一起其他细小差异(例如不允许列表末尾的逗号)之外。json对象中所有的键都必须是字符串,基本类型是字典,列表、字符串、数字、布尔值和空值。
将JSON字符串转换为Python形式,使用Python的内置模块json的json.loads方法:
import json
result = json.loads(obj)
result
{'name': 'Wes',
'place_lived': ['United States', 'Spain', 'Germany'],
'pet': None,
'siblings': [{'name': 'Scott', 'age': 30, 'pets': ['Zeus', 'Zuko']},
{'name': 'Katie', 'age': 38, 'pets': ['Sixes', 'Stache', 'Cisco']}]}
另一方面,json.dumps可以将Python对象转换为JSON
asjson = json.dumps(result)
asjson
'{"name": "Wes", "place_lived": ["United States", "Spain", "Germany"], "pet": null, "siblings": [{"name": "Scott", "age": 30, "pets": ["Zeus", "Zuko"]}, {"name": "Katie", "age": 38, "pets": ["Sixes", "Stache", "Cisco"]}]}'
将JSON对象或对象列表转换为DataFrame或其他数据结构。
比较方便的方式是将字典构成的列表(之前是json对象)传入DataFrame构造函数,并选出数据字段的子集。
siblings = pd.DataFrame(result['siblings'],columns = ['name','age'])
siblings
name age
0 Scott 30
1 Katie 38
pandas.read_json 的默认选项是假设JSON数组中的每个对象是表里的一行,将数据导出为json,一种办法是对Series或DataFrame使用to_json方法。
XML和HTML:网络抓取
pandas的内建函数read_html函数可以使用lxml和Beautiful Soul等库将HTML中的表自动解析为DataFrame对象。
pandas.read_html函数有很多选项,默认情况下,它会搜索并尝试解析所有包含在<table>标签中的表格型数据,返回的结果是DataFrame对象的列表。
XML是另一种常用的结构化数据格式,它使用元数据支持分层,嵌套数据。XML和XTML结构类似,但是XML更通用。
使用lxml从更为通用的XML格式解析数据:
#使用lxml.objectify,我们可以解析这个文件,并用getroot来获得对XML文件的根节点的引用
from lxml import objectify
path = 'mta_perf/Performance_MNR.xml
parsed = objectify.parse(open(path))
root = parsed.getroot()
data = []
skip_field = ['PARENT_SEQ','INDICATOR_SEQ','DESIRED_CHANGE','DECIMAL_PLACES']
#root.INDICATOR返回一个用于产生各个XML元素的生成器。
for elt in root.INDICATOR:
el_data = {}
for child in elt.getchildren():
if child.tag in skip_field:
continue
el_data['child.tag'] = child.pyval
data.append(el_data)
#最后将包含字典的列表转换为DataFrame
perf = pd.DataFrame(data)
perf.head()
child.tag
0 96.9
1 95
2 96.9
3 98.3
4 95.8
child.tag返回的是xml文件每行中的第一个值,child.pyval返回的是第二个(也就是中间的)值。
XML 数据还可以更复杂,每个标签也可以包含元数据。考虑一个HTML连接标签,也是有效的XML:
from io import StringIO
tag = '<a href = "http://www.google.com">Google</a>'
root = objectify.parse(StringIO(tag)).getroot()
root
<Element a at 0x2a8b112bd48>
root.get('href')
'http://www.google.com'
root.text
'Google'
这里StringIO的概念:在内存中读写str,参考:https://blog.csdn.net/lucyxu107/article/details/82728266
二进制格式
使用Python内建的pickle序列化模块进行二进制操作是存储数据(也成为序列化)最高效、最方便的方式之一。pandas拥有一个to_pickle方法可以将数据以pickle格式写入硬盘
frame = pd.read_csv('ex1.csv')
frame
a b c d message
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo
rame.to_pickle('frame_pickle')
#可以直接使用内建的pickle读取文件中pickle化的对象,或更方便地使用pandas.read_pickle做上述操作
pd.read_pickle('frame_pickle')
a b c d message
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo
pickle仅被推荐作为短期的存储格式。问题在于pickle很难确保格式的长期有效性。
HDF5格式
HDF5是一个广受好评的文件格式,用于存储大量的科学数组数据。HDF5中的“HDF”代表分层数据格式。每个HDF5文件可以存储多个数据集并支持元数据。
与更简单的格式相比,HDF5支持多种压缩模式的即时压缩,使得重复模式的数据可以更高效的存储。HDF5适用于处理不适合在内存中存储的超大型数据,可以使你高效的读写大型数组的一小块。
尽管你可以通过PyTables和h5py等库直接访问HDF5文件,但pandas提供了一个高阶的接口,可以简化Series和DataFrame的存储。
HDFStore类像字典一样工作并处理低级别细节:
frame = pd.DataFrame({'a':np.random.randn(100)})
store = pd.HDFStore('mydata.h5')
store['obj1'] = frame
store['obj1_col'] = frame['a']
store
<class 'pandas.io.pytables.HDFStore'>
File path: mydata.h5
#包含在HDF5文件中的对象可以使用相同的字典型API进行检索:
store['obj1'].shape()
(100,1)
HDFStore支持两种存储模式,‘fixed’和‘table’。后者速度更慢,但支持一种特殊语法的查询操作
store.put('obj2',frame,format = 'table')
store.select('obj2',where = ['index>=10 and index <= 15'])
a
10 -0.518309
11 0.198280
12 0.488141
13 -0.711851
14 -0.709542
15 0.754240
store.close()
put是store['obj2']=frame 方法的显示版本,但允许我们设置其他选项,如存储格式。
#pandas.read_hdf函数是这些工具的快捷方法
frame.to_hdf('my_data.h5','obj3',format = 'table')
pd.read_hdf('my_data.h5','obj3',where =['index<5'] )
a
0 -1.260942
1 1.297276
2 -0.125102
3 0.211125
4 0.731398
!!HDF5并不是数据库,它是一种适合一次写入多次读取的数据集。尽管数据可以在嗯和实践添加到文件中,但如果多个写入者持续写入,文件可能会损坏。
读取Microdoft Excel文件
pandas也支持通过ExcelFile类或pandas.read_excel函数来读取存储在Excel文件中的表格型数据。
使用ExcelFile时,通过将xls或xlsx的路径传入,生成一个实例
xlsx = pd.ExcelFile('ex1.xlsx')
#存储在表中的数据可以通过pandas.read_excel读取到DataFrame中
pd.read_excel(xlsx,'Sheet1')
Unnamed: 0 a b c d message
0 0 1 2 3 4 hello
1 1 5 6 7 8 world
2 2 9 10 11 12 foo
#如果你读取的是含有多个表的文件,生成ExcelFile更快,但你也可以更简洁地将文件名传入pandas.read_excel:
frame = pd.read_excel('ex1.xlsx','Sheet1')
frame
Unnamed: 0 a b c d message
0 0 1 2 3 4 hello
1 1 5 6 7 8 world
2 2 9 10 11 12 foo
#如需将pandas数据写入到Excel格式中,你必须生成一个ExcelWriter,然后使用pandas对象的to_excel方法将数据写入
writer = pd.ExcelWriter('ex2.xlsx')
frame.to_excel(writer,'Sheet1')
writer.save()
#你也可以直接将文件路径传入to_excel,避免直接调用ExcelWriter:
frame.to_excel('ex2.xlsx')
与Web API交互
有多种方式可以利用Python来访问API,我推荐简单易用的方式是使用requests包
要获取GitHub上最新的30条关于pandas的问题,我们使用附加库requests发送一个HTTP GET请求
import numpy as np
import pandas as pd
from pandas import Series,DataFrame
import requests
url = 'https://api.github.com/repos/pandas-dev/pandas/issues'
resp = requests.get(url)
resp
输出#<Response [200]>
#Response(响应)对象的json方法将返回一个包含解析为本地Python对象的json字典
data = resp.json()
data[0]['title']
"`The default of the 'keep_tz' keyword in DatetimeIndex.to_series will change to True in a future release.`"
#data中的每个元素都是一个包含DitHub问题页面上的所有数据的字典(除注释外)
#我们可以直接将data传给DataFrame,并提取感兴趣的字段
issues = pd.DataFrame(data,columns=['number','title','labels','state'])
issues.head()
number title labels state
0 28083 `The default of the 'keep_tz' keyword in Datet... [] open
1 28082 Change `randn` to `np.random.randn` in v0.10.0... [{'id': 134699, 'node_id': 'MDU6TGFiZWwxMzQ2OT... open
2 28081 REF: separate bloated test [] open
3 28080 BUG: Series[int] + datetime64 should raise [] open
4 28079 API: flex comparisons DataFrame vs Series inco... [{'id': 35818298, 'node_id': 'MDU6TGFiZWwzNTgx... open
5 28078 Auto backport of pr 28074 on 0.25.x [] open
与数据库交互
...
网友评论