书中源码与数据集http://github.com/pydata/pydata-book
目录
6.1 读写文件格式的数据
6.2 二进制数据格式
6.3 使用 html 和web API
6.4 使用数据库
输入和输出可以划分几个大类:读取文本文件和其他更高效的磁盘存储格式,加载数据库中的数据,利用web API操作网络资源。
6.1 读写文件格式的数据
pandas中得解析函数
函数
read_csv 从文件、URL、文件型对象中加载带分隔符的数据。默认分隔符为逗号
read_table 从文件、URL、文件型对象中加载带分隔符的数据。默认分隔符为制表符("\t")
reda_fwf 读取定宽格式数据(没有分隔符)
read_clipboard 读取剪贴板中的数据,可以看做read_table的剪贴板版。在将网页转换为表格时很有用
这些函数的选项可以划分下面几大类:
索引:将一个或多个列当做返回的DataFrame处理,以及是否从文件、用户获得列名
类型推断和数据转换:包括用户定义值得转换、缺失值标记列表等
日期解析:包括组合功能,比如将分散在多个列中的日期时间信息组合成结果中的单个列。
迭代:支持对大文件进行逐块迭代
不规整数据问题:跳过一些行、页脚、注释或其他一些不重要的东西(比如成千上万个逗号隔开的数值数据)
类型推断是这些函数中最重要的功能之一。我们不需要知道列的类型到底是数值、整数、布尔值、还是字符串。
我们给出一个以逗号分隔的(CSV)文件:
我们使用type的这个Window shell命令将文本的原始内容打印到屏幕上。
In [22]:!type E:\\ch06ex1.csv
a,b,c,d,message
1,2,3,4,hello
5,6,7,8,world
9,10,11,12,foo
由于文件以逗号分隔,所以我们可以使用read_csv将其读入一个DataFrame:
In [25]:df=pd.read_csv('E:\\ch06ex1.csv')
In [26]:df
Out[26]:
a b c d message
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo
还可以使用read_table ,这时需要指定分隔符:
In [28]:pd.read_table('E:\\ch06ex1.csv',sep=',')
Out[28]:
a b c d message
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo
假如不指定分隔符:
In [29]:pd.read_table('E:\\ch06ex1.csv')
Out[29]:
a,b,c,d,message
0 1,2,3,4,hello
1 5,6,7,8,world
2 9,10,11,12,foo
并不是所有的文件本身就有标题行。我们可以自己分配默认的列名,也可以自己定义列名:
In [3]:!type E:\\ch06ex2.csv
1,2,3,4,hello
5,6,7,8,world
9,10,11,12,foo
In [5]:pd.read_csv('E:\\ch06ex2.csv',header=None)
Out[5]:
0 1 2 3 4
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo
In [8]:pd.read_csv('E:\\ch06ex2.csv',names=['a','b','c','d','message'])
Out[8]:
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的位置上,也可以通过index_col参数指定“message” :
In [10]:names=['a','b','c','d','message']
In [11]:pd.read_csv('E:\\ch06ex2.csv',names=names,index_col='message')
Out[11]:
a b c d
message
hello 1 2 3 4
world 5 6 7 8
foo 9 10 11 12
如果我们希望将多个列做成一个层次化索引,只需要传入编号或列名组成的列表即可:
In [15]:!type E:\\ch06_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
In [17]:parsed=pd.read_csv('E:\\ch06_mindex.csv',index_col=['key1','key2'])
In [18]:parsed
Out[18]:
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
有些表格可能不是用固定的分隔符去分隔字段的,对于这种情况,我们编写一个正则表达式来作为 read_table的分隔符。
In [35]:list(open('E:\\ch06ex3.txt'))
Out[35]:
[' A B C\n',
'aaa -0.264438 -1.343465 -0.619500\n',
'bbb -0.264438 -1.343465 -0.619500\n',
'ccc -0.264438 -1.343465 -0.619500\n',
'ddd -0.264438 -1.343465 -0.619500\n']
该文件各个字段由数量不定的空白字符分隔。我们可以使用正则表达式\s+ 表示,
In [36]:result=pd.read_table('E:\\ch06ex3.txt',sep='\s+')
In [37]:result
Out[37]:
A B C
aaa -0.264438 -1.343465 -0.6195
bbb -0.264438 -1.343465 -0.6195
ccc -0.264438 -1.343465 -0.6195
ddd -0.264438 -1.343465 -0.6195
上面由于列名比数据行的数量少,索引read_table推断第一列应该是DataFrame的索引。
许多解析器函数的许多参数可以帮助你处理各种各样的异形文件格式。比如,用skiprows跳过文件的第一行、第三行、第四行。
In [4]:!type E:\\ch06ex4.csv
#hey!
a,b,c,d,message
#just wanted to make things more difficult for you
#who reads CSV files with computers,anyway?
1,2,3,4,hello
5,6,7,8,world
9,10,11,12,foo
In [5]:pd.read_csv('E:\\ch06ex4.csv',skiprows=[0,2,3])
Out[5]:
a b c d message
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo
缺失值处理是文件解析任务重要组成。缺失数据会没有空字符串,或者某个标记值表示。
默认下,pandas会用一组常出现的标记值进行识别,如NA,-1.#IND以及NULL等:
In [56]:!type E:\\ch06ex5.csv
something,a,b,c,d,message
one,1,2,3,4,NA
two,5,6,,8,world
three,9,10,11,12,foo
In [58]:import pandas as pd
In [59]:result=pd.read_csv('E:\\ch06ex5.csv')
In [60]:result
Out[60]:
something a b c d message
0 one 1 2 3.0 4 NaN
1 two 5 6 NaN 8 world
2 three 9 10 11.0 12 foo
In [61]:pd.isnull(result)
Out[61]:
something a b c d message
0 False False False False False True
1 False False False True False False
2 False False False False False False
na_values可以接受一组用于表示缺失值的字符串:
In [62]:result=pd.read_csv('E:\\ch06ex5.csv',na_values=['NULL'])
In [63]:result
Out[63]:
something a b c d message
0 one 1 2 3.0 4 NaN
1 two 5 6 NaN 8 world
2 three 9 10 11.0 12 foo
可以用一个字典为各列指定不同的NA标记值:
In [65]:sentinels={'message':['foo','NA'],'something':['two']}
In [66]:result=pd.read_csv('E:\\ch06ex5.csv',na_values=sentinels)
In [67]:result
Out[67]:
something a b c d message
0 one 1 2 3.0 4 NaN
1 NaN 5 6 NaN 8 world
2 three 9 10 11.0 12 NaN
6.1 .1 逐块读取文件文件
处理大文件时候,我们可能需要文件的一小部分,或者逐块对文件进行迭代:
In [4]: result=pd.read_csv(r'F:\pydata-book-master\ch06\ex6.csv')
In [5]: result
Out[5]:
one two three four key
00.467976-0.038649-0.295344-1.824726L
1 -0.3588931.4044530.704965-0.200638B
2 -0.5018400.659254-0.421691-0.057688G
30.2048861.0741341.388361-0.982404R
40.354628-0.1331160.283763-0.837063Q
51.8174800.7422730.419395-2.251035Q
... ... ... ... ... ..
99931.8211170.4164450.1738740.505118X
99940.0688041.3227590.8023460.223618H
99952.311896-0.417070-1.409599-0.515821L
9996 -0.479893-0.6504190.745152-0.646038E
99970.5233310.7871120.4860661.093156K
9998 -0.3625590.598894-1.8432010.887292G
9999 -0.096376-1.012999-0.657431-0.5733150
[10000 rows x 5 columns]
我们只想读取几行的,通过nrows来指定行即可:
In [7]: pd.read_csv(r'F:\pydata-book-master\ch06\ex6.csv',nrows=5)
Out[7]:
one two three four key
00.467976-0.038649-0.295344-1.824726L
1 -0.3588931.4044530.704965-0.200638B
2 -0.5018400.659254-0.421691-0.057688G
30.2048861.0741341.388361-0.982404R
40.354628-0.1331160.283763-0.837063Q
要逐块读取文件,需要设置chunksize (行数):
In [10]:chunker=pd.read_csv(r'F:\pydata-book-master\ch06\ex6.csv',chunksize=10000)
In [11]:chunker
Out[11]:
read_csv所返回的这个TextParser对象使你可以根据chunksize对文件进行逐块迭代。
比如我们可以迭代ex6.csv,将值计数聚合到“key”中,
In [10]:chunker=pd.read_csv(r'F:\pydata-book-master\ch06\ex6.csv',chunksize=10000)
In [11]:chunker
Out[11]:
In [13]:from pandas import Series,DataFrame
In [14]:tot=Series([])
In [15]:for piece in chunker:
...:tot=tot.add(piece['key'].value_counts(),fill_value=0)
...:
In [16]:tot.order(ascending=False)
__main__:1: FutureWarning: order is deprecated, use sort_values(...)
Out[16]:
E 368.0
X 364.0
L 346.0
O 343.0
Q 340.0
M 338.0
J 337.0
F 335.0
K 334.0
H 330.0
V 328.0
I 327.0
U 326.0
P 324.0
D 320.0
A 320.0
R 318.0
Y 314.0
G 308.0
S 308.0
N 306.0
W 305.0
T 304.0
B 302.0
Z 288.0
C 286.0
4 171.0
6 166.0
7 164.0
3 162.0
8 162.0
5 157.0
2 152.0
0 151.0
9 150.0
1 146.0
dtype: float64
In [17]:tot[:6]
Out[17]:
E 368.0
X 364.0
L 346.0
O 343.0
Q 340.0
M 338.0
dtype: float64
6.1.2 将数据写出到文本格式
将数据写出带文本格式
数据也可以被输出为分隔符个格式的文本。
我们看看之前读过的CSV文件。
In [1]: import pandas as pd
In [2]: data=pd.read_csv(r"F:\pydata-book-master\ch06\ex5.csv")
In [3]: data
Out[3]:
something a b c d message
0 one 1 2 3.0 4 NaN
1 two 5 6 NaN 8 world
2 three 9 10 11.0 12 foo
In [6]: !type "F:\pydata-book-master\ch06\out.csv"
,something,a,b,c,d,message
0,one,1,2,3.0,4,
1,two,5,6,,8,world
2,three,9,10,11.0,12,foo
当然,还可以使用其他分隔符
In [8]: import sys
In [9]: data.to_csv(sys.stdout,sep='|')
|something|a|b|c|d|message
0|one|1|2|3.0|4|
1|two|5|6||8|world
2|three|9|10|11.0|12|foo
缺失值在输出结果中会被表示为空字符,可能我们会希望将它表示其他字符
In [10]: data.to_csv(sys.stdout,na_rep="NULL")
,something,a,b,c,d,message
0,one,1,2,3.0,4,NULL
1,two,5,6,NULL,8,world
2,three,9,10,11.0,12,foo
没有其他选项会写出行和列标签。
In [11]: data.to_csv(sys.stdout,index=False,header=False)
one,1,2,3.0,4,
two,5,6,,8,world
three,9,10,11.0,12,foo
还可以写出一部分列,指定以下的顺序排列:
Series有一个to_csv的方法,
In [16]: from pandas import Series,DataFrame
In [18]: import numpy as np
In [20]: dates=pd.date_range('1/1/2000',periods=7)
In [21]: ts=Series(np.arange(7),index=dates)
In [22]: ts.to_csv(r"F:\pydata-book-master\ch06\tseries.csv")
In [23]: !type F:\pydata-book-master\ch06\tseries.csv"
2000-01-01,0
2000-01-02,1
2000-01-03,2
2000-01-04,3
2000-01-05,4
2000-01-06,5
2000-01-07,6
我们还有一个from_csv方法:
In [24]: Series.from_csv(r'F:\pydata-book-master\ch06\tseries.csv',parse_dates=True)
Out[24]:
2000-01-01 0
2000-01-02 1
2000-01-03 2
2000-01-04 3
2000-01-05 4
2000-01-06 5
2000-01-07 6
dtype: int64
6.1.3 ·手工处理分隔符格式
大部分表格型数据用到pandas.read_table进行加载。有时候我们需要一些手工处理。
In [25]: !type F:\pydata-book-master\ch06\ex7.csv
"a","b","c"
"1","2","3"
"1","2","3","4"
对于单字符分隔符文件,可以直接使用python内置的csv模块。将任意的打开的文件或文件型的对象传给csv.reader
In [26]: import csv
In [27]: f=open(r"F:\pydata-book-master\ch06\ex7.csv")
In [28]: reader=csv.reader(f)
#对这个reader进行迭代将会为每行产生一个元组:
In [30]: for line in reader:
...: print line
...:
['a', 'b', 'c']
['1', '2', '3']
['1', '2', '3', '4']
为了使数据格式合乎要求,需要我们整理一下:
In [4]:lines=list(csv.reader(open('F:\pydata-book-master\ch06\ex7.csv')))
In [5]:header,values=lines[0],lines[1:]
In [8]:header,values
Out[8]:(['a', 'b', 'c'], [['1', '2', '3'], ['1', '2', '3', '4']])
In [9]:data_dict={h:v for h,v in zip(header,zip(*values))}
In [10]:header,values
Out[10]:(['a', 'b', 'c'], [['1', '2', '3'], ['1', '2', '3', '4']])
csv文件的形式有很多种,只需要定义csv.Dialect的一个子类可定义出新格式(如专门的分隔符、字符串引用约定、行结束符等):
In [22]:class my_dialect(csv.Dialect):
...:lineterminator='\n'
...:delimiter=';'
...:quotechar='"'
...:
In [25]:f=open(r"E:\pydata-book-master\pydata-book-master\ch06\ex7.csv")
In [26]:reader = csv.reader(f, dialect=my_dialect, quoting = csv.QUOTE_ALL)
In [27]:reader
Out[27]:<_csv.reader at 0x245b0168>
各个csv语支的参数可以关键字的形式提供给csv.reader ,而无需定义子类:
reader=csv.reader(f,delimiter='|')
注意:对于复杂的分隔符或多字符的分隔符的文件,我们要使用字符串的split方法或正则表达式re.split进行拆分和其他整理工作。
我们在手动的输出分隔符的文件,可以使用csv.writer
它接收一个已经打开的且可写的文件对象以及跟csv.reader相同的那些语支和格式化选项:
In [30]:with open(r'E:\pydata-book-master\pydata-book-master\ch06\mydata.csv','w') as f:
...:writer=csv.writer(f,dialect=my_dialect,quoting = csv.QUOTE_ALL)
...:writer.writerow(('one','two','three'))
...:writer.writerow(('1','2','3'))
...:writer.writerow(('4','5','6'))
...:writer.writerow(('7','8','9'))
6.1.4 JSON数据
JSON(JavaScript Object Notation的简称)已经成为通过HTTP请求在Web浏览器和其他应用程序之间发送数据的标准格式之一。
JSON是一种比表格型文本格式(如CSV)灵活得多的数据格式:
json的本质是字典,是hash表,用来存储非结构化的数据。
csv本质是表,用来存储结构化数据
给出一个例子
obj="""{"name":"Wes","places_lived":["United States","Spain","Germany"],"pet":null,"siblings":[{"name":"Scott","age":25,"pet":"Zuko"},{"name":"Katie","age":33,"pet":"Cisco"}]}"""
In [12]:obj="""{"name":"Wes","places_lived":["United States","Spain","Germany"],"pet":null,"siblings":[{"name":"Scott","age":25,"pet":"Zuko"},{"name":"Katie","age":33,"pet":"Cisco"}]}"""
JSON非常接近有效的python代码。基本类型有对象(字典),数组(列表),字符串,数值,布尔值,以及null。
对象中的键必须是字符串。
In [13]:import json
In [14]:result=json.loads(obj)
In [15]:result
Out[15]:
{'name': 'Wes',
'pet': None,
'places_lived': ['United States', 'Spain', 'Germany'],
'siblings': [{'age': 25, 'name': 'Scott', 'pet': 'Zuko'},
{'age': 33, 'name': 'Katie', 'pet': 'Cisco'}]}
相反,json.dump则将python对象转换为JSON格式:
asjson=json.dumps(result)
如何将JSON对象转换为DataFrame 或其他便于分析的数据结构。
最为方便的一个方式:向DataFrame构造器传入一组JSON对象,并选取数据字段的子集。
In [29]:siblings=DataFrame(result['siblings'],columns=['name','age'])
In [30]:siblings
Out[30]:
name age
0 Scott 25
1 Katie 33
6.1.5 XML和HTML:Web信息收集
python中有许多可以读写HTML和XML格式数据的库,lxml就是其中之一,它能够高效的解析大文件。lxml有多编程接口,首先要要用lxml.html处理HTML,然后在用lxml.objetify做一些XML处理。
In [31]:from lxml.html import parse
In [32]:from urllib2 import urlopen
In [33]:parsed=parse(urlopen=('http://finance.yahoo.com/q/op?s=AAPL+Options'))
Traceback(most recent call last):
File"", line1, in
parsed=parse(urlopen=('http://finance.yahoo.com/q/op?s=AAPL+Options'))
TypeError:parse() takes at least 1 argument (0 given)
6.1.5.1 利用lxml.objectify 解析XML
XML(extensible markup language)是另一种常见的支持分层、嵌套数据以及元数据的结构化数据格式。
6.2 二进制数据格式
实现数据的二进制格式的存储的最简单的办法之一就是使用python内置的pickle序列化。为了使用方便,pandas 对象都有一个将数据以pickle形式保存到磁盘上的save的方法;
6.3 使用 html 和web API
6.4 使用数据库