利用python进行数据分析之数据加载、存储与文件格式(五)

浏览: 1699

image.png

书中源码与数据集 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

image.png

image.png

image.png

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
0 0.467976 -0.038649 -0.295344 -1.824726 L
1 -0.358893 1.404453 0.704965 -0.200638 B
2 -0.501840 0.659254 -0.421691 -0.057688 G
3 0.204886 1.074134 1.388361 -0.982404 R
4 0.354628 -0.133116 0.283763 -0.837063 Q
5 1.817480 0.742273 0.419395 -2.251035 Q
... ... ... ... ... ..
9993 1.821117 0.416445 0.173874 0.505118 X
9994 0.068804 1.322759 0.802346 0.223618 H
9995 2.311896 -0.417070 -1.409599 -0.515821 L
9996 -0.479893 -0.650419 0.745152 -0.646038 E
9997 0.523331 0.787112 0.486066 1.093156 K
9998 -0.362559 0.598894 -1.843201 0.887292 G
9999 -0.096376 -1.012999 -0.657431 -0.573315 0

[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
0 0.467976 -0.038649 -0.295344 -1.824726 L
1 -0.358893 1.404453 0.704965 -0.200638 B
2 -0.501840 0.659254 -0.421691 -0.057688 G
3 0.204886 1.074134 1.388361 -0.982404 R
4 0.354628 -0.133116 0.283763 -0.837063 Q

要逐块读取文件,需要设置chunksize (行数):

In [10]: chunker=pd.read_csv(r'F:\pydata-book-master\ch06\ex6.csv',chunksize=10000)

In [11]: chunker
Out[11]: <pandas.io.parsers.TextFileReader at 0xb894d68>

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]: <pandas.io.parsers.TextFileReader at 0xb894d68>


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的一个子类可定义出新格式(如专门的分隔符、字符串引用约定、行结束符等):

class my_dialect(csv.Dialect):
lineterminator='\n'
delimiter=';'
quotechar=' " '
reader=csv.reader(f,dialect=my_dialect)

各个csv语支的参数可以关键字的形式提供给csv.reader ,而无需定义子类:

reader=csv.reader(f,delimiter='|')

image.png

注意:对于复杂的分隔符或多字符的分隔符的文件,我们要使用字符串的split方法或正则表达式re.split进行拆分和其他整理工作。

我们在手动的输出分隔符的文件,可以使用csv.writer

它接收一个已经打开的且可写的文件对象以及跟csv.reader相同的那些语支和格式化选项:

with open(r'F:\pydata-book-master\ch06\mydata.csv','w') as f: 
writer=csv.writer(f,dialect=my_dialect)
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
推荐 2
本文由 lingan 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
转载、引用前需联系作者,并署名作者且注明文章出处。
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

0 个评论

要回复文章请先登录注册