0%

第二章-数据加载

一、读取文本格式数据

read_csv

将以逗号分隔的csv文件读入DataFrame中

1
2
3
4
5
6
7
8
In [9]: df = pd.read_csv('examples/ex1.csv')

In [10]: df
Out[10]:
a b c d message
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo

处理没有标题行的文件

1
2
3
1,2,3,4,hello
5,6,7,8,world
9,10,11,12,foo

分配默认的列名

1
2
3
4
5
6
In [13]: pd.read_csv('examples/ex2.csv', header=None)
Out[13]:
0 1 2 3 4
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo

自己定义列名

1
2
3
4
5
6
In [14]: pd.read_csv('examples/ex2.csv', names=['a', 'b', 'c', 'd', 'message'])
Out[14]:
a b c d message
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo

将多个列做成一个层次化索引

1
2
3
4
5
6
7
8
9
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
In [18]: parsed = pd.read_csv('examples/csv_mindex.csv',
....: index_col=['key1', 'key2'])

In [19]: parsed
Out[19]:
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

处理不固定分隔符

1
2
3
4
5
6
7
In [20]: list(open('examples/ex3.txt'))
Out[20]:
[' 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']

上面不是txt文档中不是像csv统一同逗号分隔,而是用不等长空格分隔,所以使用read_table方法

1
2
3
4
5
6
7
8
9
In [21]: result = pd.read_table('examples/ex3.txt', sep='\s+')

In [22]: result
Out[22]:
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

跳过指定行

1
2
3
4
5
6
7
# 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
1
2
3
4
5
6
In [24]: pd.read_csv('examples/ex4.csv', skiprows=[0, 2, 3])
Out[24]:
a b c d message
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo

缺失值处理

1
2
3
4
something,a,b,c,d,message
one,1,2,3,4,NA
two,5,6,,8,world
three,9,10,11,12,foo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
In [26]: result = pd.read_csv('examples/ex5.csv')

In [27]: result
Out[27]:
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 [28]: pd.isnull(result)
Out[28]:
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

用一个列表或集合的字符串表示缺失值,指定原来文件中特定的值是缺失值

1
2
3
4
5
6
7
sentials = {'something':['two'], 'message':['foo', 'NA']}
result = pd.read_csv('examples/ex5.csv', na_values=sentials)
result
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

其中'something':['two']表示针对something这一列,其中值为two的值替换成缺失值

逐块读取文本文件

读取文件中指定行数

通过nrows进行指定读取行数即可:

1
2
3
4
5
6
7
8
In [36]: pd.read_csv('examples/ex6.csv', nrows=5)
Out[36]:
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(行数)

1
2
3
4
In [874]: chunker = pd.read_csv('ch06/ex6.csv', chunksize=1000)

In [875]: chunker
Out[875]: <pandas.io.parsers.TextParser at 0x8398150>

逐块迭代文件

比如说,我们可以迭代处理ex6.csv,将值计数聚合到"key"列中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
chunker = pd.read_csv('examples/ex6.csv', chunksize=1000)

tot = pd.Series([])
for piece in chunker:
tot = tot.add(piece['key'].value_counts(), fill_value=0)

tot = tot.sort_values(ascending=False)
In [40]: tot[:10]
Out[40]:
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
dtype: float64

将数据写出到文本格式

to_csv

1
2
3
4
5
6
7
In [43]: data.to_csv('examples/out.csv')

In [44]: !cat examples/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

使用其他分隔符

1
2
3
4
5
6
7
In [45]: import sys

In [46]: 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

禁用行和列的标签

1
2
3
4
In [48]: 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

操作指定列

1
2
3
4
5
In [49]: data.to_csv(sys.stdout, index=False, columns=['a', 'b', 'c'])
a,b,c
1,2,3.0
5,6,
9,10,11.0

处理分隔符格式

对于任何单字符分隔符文件,可以直接使用Python内置的csv模块。将任意已打开的文件或文件型的对象传给csv.reader:

1
2
3
4
import csv
f = open('examples/ex7.csv')

reader = csv.reader(f)

对这个reader进行迭代将会为每行产生一个元组(并移除了所有的引号):

1
2
3
4
5
In [56]: for line in reader:
....: print(line)
['a', 'b', 'c']
['1', '2', '3']
['1', '2', '3']

创建数据列的字典

首先解释zip的作用:

zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。

举例1:

a = [1,2,3]

b = [4,5,6]

c = [4,5,6,7,8]

ipped = zip(a,b) # 打包为元组的列表

输出:[(1, 4), (2, 5), (3, 6)]

举例2:

zip(*values)的作用是将values列表中的元素解压缩为多个独立的元组,然后将这些元组组合在一起成为一个迭代器。

具体来说,假设values列表是一个包含多个元组的列表,例如[(v1_1, v2_1, ...), (v1_2, v2_2, ...), ...]zip(*values)会将这些元组解压缩并重新组合,将它们的第一个元素组成一个元组,第二个元素组成一个元组,依此类推

具体使用:

首先,读取文件到一个多行的列表中:

1
2
In [57]: with open('examples/ex7.csv') as f:
....: lines = list(csv.reader(f))

然后,我们将这些行分为标题行和数据行

1
In [58]: header, values = lines[0], lines[1:]

接着,我们可以用字典构造式和zip(*values),后者将行转置为列,创建数据列的字典

1
2
3
4
In [59]: data_dict = {h: v for h, v in zip(header, zip(*values))}

In [60]: data_dict
Out[60]: {'a': ('1', '1'), 'b': ('2', '2'), 'c': ('3', '3')}

定义新格式的csv文件

1
2
3
4
5
6
class my_dialect(csv.Dialect):
lineterminator = '\n'
delimiter = ';'
quotechar = '"'
quoting = csv.QUOTE_MINIMAL
reader = csv.reader(f, dialect=my_dialect)
  1. lineterminator = '\n':定义行终止符为换行符 \n
  2. delimiter = ';':定义字段之间的分隔符为分号 ;
  3. quotechar = '"':定义引号字符为双引号 ",用于包围包含特殊字符的字段。
  4. quoting = csv.QUOTE_MINIMAL:定义引用约定为最小引用,表示只在必要时才使用引号。

JSON数据

1
2
3
4
5
6
7
8
9
obj = """
{"name": "Wes",
"places_lived": ["United States", "Spain", "Germany"],
"pet": null,
"siblings": [{"name": "Scott", "age": 30, "pets": ["Zeus", "Zuko"]},
{"name": "Katie", "age": 38,
"pets": ["Sixes", "Stache", "Cisco"]}]
}
"""

json.loads

1
2
3
4
5
6
7
8
9
10
11
In [62]: import json

In [63]: result = json.loads(obj)

In [64]: result
Out[64]:
{'name': 'Wes',
'pet': None,
'places_lived': ['United States', 'Spain', 'Germany'],
'siblings': [{'age': 30, 'name': 'Scott', 'pets': ['Zeus', 'Zuko']},
{'age': 38, 'name': 'Katie', 'pets': ['Sixes', 'Stache', 'Cisco']}]}

json.dumps

1
In [65]: asjson = json.dumps(result)

将json转换为DataFrame

最简单方便的方式是:向DataFrame构造器传入一个字典的列表(就是原先的JSON对象),并选取数据字段的子集:

1
2
3
4
5
6
7
In [66]: siblings = pd.DataFrame(result['siblings'], columns=['name', 'age'])

In [67]: siblings
Out[67]:
name age
0 Scott 30
1 Katie 38

read_json

特别格式的JSON数据集

1
2
3
4
[{"a":1, "b":2, "c":3},//里面字典,字典之间用“,”分割
{}
{}
{}]//外边整体列表

自动将特别格式的JSON数据集转换为Series或DataFrame

1
2
3
4
5
6
7
8
In [69]: data = pd.read_json('examples/example.json')

In [70]: data
Out[70]:
a b c
0 1 2 3
1 4 5 6
2 7 8 9

to_json

将数据从pandas输出到JSON

1
2
3
4
5
In [71]: print(data.to_json())
{"a":{"0":1,"1":4,"2":7},"b":{"0":2,"1":5,"2":8},"c":{"0":3,"1":6,"2":9}}

In [72]: print(data.to_json(orient='records'))
[{"a":1,"b":2,"c":3},{"a":4,"b":5,"c":6},{"a":7,"b":8,"c":9}]

二、二进制数据格式

实现数据的高效二进制格式存储最简单的办法之一是使用Python内置的pickle序列化。pandas对象都有一个用于将数据以pickle格式保存到磁盘上的to_pickle方法:

to_pickle:

1
2
3
4
5
6
7
8
9
10
In [87]: frame = pd.read_csv('examples/ex1.csv')

In [88]: frame
Out[88]:
a b c d message
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo

In [89]: frame.to_pickle('examples/frame_pickle')

read_pickle

1
2
3
4
5
6
In [90]: pd.read_pickle('examples/frame_pickle')
Out[90]:
a b c d message
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo

使用HDF5格式

准备数据集

1
frame = pd.DataFrame({'a': np.random.randn(100)})

创建了一个名为frame的Pandas DataFrame对象,其中包含一个名为a的列,该列包含了随机生成的100个标准正态分布(均值为0,标准差为1)的随机数值

创建

1
store = pd.HDFStore('mydata.h5')

创建了一个名为store的Pandas HDFStore对象,并打开了一个名为mydata.h5的HDF5文件。

像python中键值对一样存取

1
2
store['obj1'] = frame
store['obj1_col'] = frame['a']

table存储方式

obj2表示存储的键,frame表示存储的值,format定义存储形式,用table形式存储好处在于可以用特殊语法查询

read_hdf和to_hdf

1
frame.to_hdf('mydata.h5', 'obj3', format='table')

将frame中内容保存在mydata.h5的hdf5文件中,对应的键是obj3,形式是table

1
2
3
4
5
6
7
8
In [102]: pd.read_hdf('mydata.h5', 'obj3', where=['index < 5'])
Out[102]:
a
0 -0.204708
1 0.478943
2 -0.519439
3 -0.555730
4 1.965781

读写Microsoft Excel文件

读取excel文件

创建实例

1
In [104]: xlsx = pd.ExcelFile('examples/ex1.xlsx')

通过read_excel读取到DataFrame

1
2
3
4
5
6
In [105]: pd.read_excel(xlsx, 'Sheet1')
Out[105]:
a b c d message
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo

根据表单(sheet)读取

1
2
3
4
5
6
7
8
In [106]: frame = pd.read_excel('examples/ex1.xlsx', 'Sheet1')

In [107]: frame
Out[107]:
a b c d message
0 1 2 3 4 hello
1 5 6 7 8 world
2 9 10 11 12 foo

写入excel文件

创建实例

1
writer = pd.ExcelWriter('examples/ex2.xlsx')

写入

1
frame.to_excel(writer, 'Sheet1')

保存

1
writer.save()

Web APIs交互

发送HTTP GET请求

1
2
3
4
5
6
7
8
In [113]: import requests

In [114]: url = 'https://api.github.com/repos/pandas-dev/pandas/issues'

In [115]: resp = requests.get(url)

In [116]: resp
Out[116]: <Response [200]>

将相应返回的json字典加载到python对象中

1
2
3
4
In [117]: data = resp.json()

In [118]: data[0]['title']
Out[118]: 'Period does not round down for frequencies less that 1 hour'

通过DataFrame提取感兴趣字段

1
2
issues = pd.DataFrame(data, columns=['number', 'title', 'labels', 'state'])
issues
number title labels state
0 58019 CLN/PERF: Simplify argmin/argmax [{'id': 2822342, 'node_id': 'MDU6TGFiZWwyODIyM... open
1 58018 PERF: Allow Index.to_frame to return RangeInde... [{'id': 8935311, 'node_id': 'MDU6TGFiZWw4OTM1M... open
2 58017 Docs: Add note about exception for integer sli... [] open
3 58016 PERF: Allow np.integer Series/Index to convert... [{'id': 8935311, 'node_id': 'MDU6TGFiZWw4OTM1M... open
4 58015 BUG: Behaviour of sum/mean on sparse boolean a... [{'id': 76811, 'node_id': 'MDU6TGFiZWw3NjgxMQ=... open
5 58013 Potential regression induced by "CLN: Enforce ... [{'id': 2822342, 'node_id': 'MDU6TGFiZWwyODIyM... open
6 58012 Add tests for transform sum with series [{'id': 127685, 'node_id': 'MDU6TGFiZWwxMjc2OD... open
7 58011 DEPR: enforce deprecation of non-standard argu... [{'id': 211029535, 'node_id': 'MDU6TGFiZWwyMTE... open
8 58008 Backport PR #57553 on branch 2.2.x (API: avoid... [] open
9 58007 API: Make Series.array a read-only NumpyExte... [{'id': 2085877452, 'node_id': 'MDU6TGFiZWwyMD... open
10 58006 CLN: remove unnecessary check needs_i8_conver... | [{'id': 1218227310, 'node_id': 'MDU6TGFiZWwxMj... | open | | 11 | 58001 | BUG: Implementfillna(..., limit=x)for EAs | [{'id': 76811, 'node_id': 'MDU6TGFiZWw3NjgxMQ=... | open | | 12 | 57999 | DEPR: Enforce datetimelike deprecations | [{'id': 211029535, 'node_id': 'MDU6TGFiZWwyMTE... | open | | 13 | 57995 | FIX #57645: Cannot use numpy FLS as indicies s... | [] | open | | 14 | 57994 | DOC: DataFrame.reset_index names param can't b... | [{'id': 134699, 'node_id': 'MDU6TGFiZWwxMzQ2OT... | open | | 15 | 57993 | BUG: Nones in pd.concat MultiIndex keys are no... | [{'id': 76811, 'node_id': 'MDU6TGFiZWw3NjgxMQ=... | open | | 16 | 57990 | DOC: ecosystem.md: add pygwalker, add seaborn ... | [{'id': 134699, 'node_id': 'MDU6TGFiZWwxMzQ2OT... | open | | 17 | 57989 | BUG: CONTAINS_OP run on pd.NA results in pd.N... | [{'id': 76811, 'node_id': 'MDU6TGFiZWw3NjgxMQ=... | open | | 18 | 57988 | PERF: (partial) fix for np_datetime.c performa... | [{'id': 8935311, 'node_id': 'MDU6TGFiZWw4OTM1M... | open | | 19 | 57987 | DEPR: 'epoch' date format in to_json | [{'id': 49379259, 'node_id': 'MDU6TGFiZWw0OTM3... | open | | 20 | 57986 | CLN: enforce deprecation of frequencies deprec... | [{'id': 53181044, 'node_id': 'MDU6TGFiZWw1MzE4... | open | | 21 | 57985 | BUG: Fix error forboxplotwhen using a pre-... | [] | open | | 22 | 57984 | Fixto_timedeltanp.int32` casting bug with... [] open
23 57980 BUG: Unexpected Styler.format behavior [{'id': 1728592794, 'node_id': 'MDU6TGFiZWwxNz... open
24 57979 ENH: Add leftsemi merge [{'id': 76812, 'node_id': 'MDU6TGFiZWw3NjgxMg=... open
25 57976 ENH: set module for objects in pandas Scal... [{'id': 13101118, 'node_id': 'MDU6TGFiZWwxMzEw... open
26 57974 BUG: Fixed ADBC to_sql creation of table when ... [{'id': 76811, 'node_id': 'MDU6TGFiZWw3NjgxMQ=... open
27 57972 BUG: Wrong kurtosis outcome due to inadequate ... [{'id': 76811, 'node_id': 'MDU6TGFiZWw3NjgxMQ=... open
28 57968 BUG: #57954 encoding ignored for filelike [{'id': 42670965, 'node_id': 'MDU6TGFiZWw0MjY3... open
29 57967 BUG: 7023 allow style when using error bars [] open

数据库交互

将数据从SQL加载到DataFrame

创建表

1
2
3
4
5
6
query = """
CREATE TABLE test
(a VARCHAR(20), b VARCHAR(20),
c REAL, d INTEGER
);
"""

一个SQL查询语句,用于创建一个名为test的表。该表包含了四个列,分别是abcd,对应的数据类型分别为VARCHAR(20)、VARCHAR(20)、REAL和INTEGER。

创建到数据库的连接

1
con = sqlite3.connect('mydata.sqlite')

执行在sql中创建表

1
con.execute(query)

将修改提交到数据库

1
con.commit()

创建用于插入的数据

1
2
3
data = [('Atlanta', 'Georgia', 1.25, 6),
('Tallahassee', 'Florida', 2.6, 3),
('Sacramento', 'California', 1.7, 5)]

SQL 插入语句的模板

使用了参数化查询的形式,其中 ? 是占位符,表示待插入的值将在执行查询时动态地填充到相应的位置上。这种参数化查询的方式可以防止 SQL 注入攻击,并且使得查询更加灵活和可维护。

1
stmt = "INSERT INTO test VALUES(?, ?, ?, ?)"

SQL插入操作

1
con.executemany(stmt, data)

SQL 查询

创建了一个游标对象 cursor,并使用 execute 方法执行了一个 SQL 查询操作,从 test 表中选择所有的行和列。执行这个操作后,游标 cursor 将会指向查询结果的第一行。

1
cursor = con.execute('select * from test')

获取查询结果

1
2
rows = cursor.fetchall()
rows

调用了游标对象 cursorfetchall() 方法,用于获取执行 SQL 查询后返回的所有结果行。这将返回一个包含所有结果行的列表 rows

返回描述列的元祖项的集合

1
cursor.description

返回一个包含查询结果的元数据的元组,其中每个元组项描述了结果集中的一个列。每个元组项通常包含列的名称、数据类型、宽度、精度