第2章介绍的NumPy和它的ndarray对象. 为多维数组提供了高效的存储和处理方法. Pandas是在NumPy的基础上建立的新程序库, 提供DataFrame数据结构. DataFrame带行标签(索引),列标签(变量名),支持相同数据类型和缺失值的多维数组. 和电子表格很像.
NumPy的ndarray提供处理数据常见功能. 但对比如添加标签,处理缺失值,分组,透视等处理起来较难.
3.1 Pandas安装
使用Anaconda, Pandas已经安装好.
检测Pandas版本号
import pandas as pd
import numpy as np
print(pd.__version__,np.__version__) # 不是vision
0.23.0 1.14.3
3.2 Pandas对象介绍
Pandas三个基础数据结构 : Series, DataFrame, Index (注意字母大小写)
3.2.1 Pandas的 Series对象
Series是一个带索引数据的一维数组
# 可以用一个数组创建Series对象
data1 = pd.Series([0.25,0.5,0.75,1])
data2 = np.array([0.25,0.5,0.75,1])
data3 = [0.25,0.5,0.75,1]
print("data1的数据类型是:",type(data1),'---',data1)
print("data2的数据类型是:",type(data2),'---',data2)
print("data3的数据类型是:",type(data3),'---',data3)
data1的数据类型是: <class 'pandas.core.series.Series'> --- 0 0.25
1 0.50
2 0.75
3 1.00
dtype: float64
data2的数据类型是: <class 'numpy.ndarray'> --- [0.25 0.5 0.75 1. ]
data3的数据类型是: <class 'list'> --- [0.25, 0.5, 0.75, 1]
从上面输出结构看,Series将一组数据和一组索引绑定在一起,可用values属性和index属性属性获取. (注意字母大小写和是否为复数格式)
data1.values
array([0.25, 0.5 , 0.75, 1. ])
data1.index
RangeIndex(start=0, stop=4, step=1)
可以通过中括号索引标签获取值
data1[2] # 第3个数值
0.75
data1[1:3] # 第2-3个 ,含左不含右
1 0.50
2 0.75
dtype: float64
data[:3] # 前3个
0 0.25
1 0.50
2 0.75
dtype: float64
Series和NumPy的一维数组基本相同, 本质差别在索引上.
NumPy数组是***隐式定义***的***整数索引***获取数值, 而Pandas的Series对象用一种***显示定义***的索引与数值关联.
显示索引 : 索引不仅仅是整数, 还可以是***任何想要的类型***.
data = pd.Series([0.25,0.5,0.75,1,'nihao'],index=['a','a','c','d',100])
data
a 0.25
a 0.5
c 0.75
d 1
100 nihao
dtype: object
Series数组中索引和数值都可以是不同类型的. 而NumPy中数组类型必须是同类型的.
Series数组中索引值可以相同.
Series是特殊的字典
- 可以把Pandas的Series对象看成是一种特殊的Python字典.
- NumPy的数组比Python列表高效. Pandas Series对象在某些操作上比Python的字典高效.
用Python的字典创建一个Series对象. 用字典创建Series对象是, 其索引默认按照顺序排列.
rk_dict = {'湖北':23213,
'湖南':213323, # 用冒号 而不是逗号
'广东':233232,
'江西':8238238,
'山东':992329}
rk = pd.Series(rk_dict)
rk
湖北 23213
湖南 213323
广东 233232
江西 8238238
山东 992329
dtype: int64
rk['湖北']
23213
和字典不同, Series对象还支持数组形式的操作.
- 首先, Series不是字典
- 字典不能执行数组形式的操作?
rk['湖北':'广东']
湖北 23213
湖南 213323
广东 233232
dtype: int64
创建Series对象的方法:
- pd.Series(data, index=index)
- index是一个可选参数, data参数支持多种数据类型
data可以是类表(list)或NumPy数组
pd.Series([2,4,6,8])
0 2
1 4
2 6
3 8
dtype: int64
data可以是一个标量, 创建Series时会重复填充到每个索引上
pd.Series(5,index=[100,200,300])
100 5
200 5
300 5
dtype: int64
data还可以是一个字典, index默认排序方式是字典键
pd.Series({2:'a',3:'b',4:'d'})
2 a
3 b
4 d
dtype: object
通过显示索引进行筛选
pd.Series({2:'a',3:'b',4:'d'},index=[4,2])
4 d
2 a
dtype: object
3.2.2 Pandas的DataFrame对象
可以将Series类比为灵活的索引的一维数组,那么DataFrame就可以看作一个就有灵活行***索引***, 又有灵活***列名***的二维数组.
rk_dict = {'湖北':23213,
'湖南':213323, # 用冒号 而不是逗号
'广东':233232,
'江西':8238238,
'山东':992329}
rk = pd.Series(rk_dict)
sh_dict = {'湖北':'武汉',
'湖南':'长沙',
'广东':'广州',
'江西':'南昌',
'山东':'济南'}
sh = pd.Series(sh_dict)
print(rk)
print(sh)
湖北 23213
湖南 213323
广东 233232
江西 8238238
山东 992329
dtype: int64
湖北 武汉
湖南 长沙
广东 广州
江西 南昌
山东 济南
dtype: object
用上面的两个Series对象定义一个DataFrame
states = pd.DataFrame({'省会':sh,
'人口':rk})
states
省会 | 人口 | |
---|---|---|
湖北 | 武汉 | 23213 |
湖南 | 长沙 | 213323 |
广东 | 广州 | 233232 |
江西 | 南昌 | 8238238 |
山东 | 济南 | 992329 |
和Series一样,DataFrame也有index属性可以获取索引(行标签)的标签
states.index
Index(['湖北', '湖南', '广东', '江西', '山东'], dtype='object')
DataFrame有columns属性,存放列标签的Index对象. 注意复数和字母大小写
states.columns
Index(['省会', '人口'], dtype='object')
DataFrame的特点是列也有索引, 所以数据可以通过行/列索引获得.
DataFrame是特殊的字典
字典是一个键映射一个值, DataFrame是一列映射一个Series的数据. 也就是索引列标签的话, 返回一列数据
print(states['省会']) # 为什么结果把行索引也都带出了呢 ?
# print(states['湖北']) 报错
湖北 武汉
湖南 长沙
广东 广州
江西 南昌
山东 济南
Name: 省会, dtype: object
创建DataFrame对象
方式1 : 通过单个Series对象创建
pd.DataFrame(rk,columns=['人口'])
# rk是个Series对象,没有列标签. DataFrame是有列标签的, 所以需要指定.
# 人口需要用中括号[],不能用小括号
人口 | |
---|---|
湖北 | 23213 |
湖南 | 213323 |
广东 | 233232 |
江西 | 8238238 |
山东 | 992329 |
方式2 : 通过字典创建(应该是用字典,列表创建)
data = [{'a': i, 'b': 2*i} for i in range(3)]
print(data)
print(type(data))
# 这是创建了一个list, list里面有三个字典元素?
data1 = pd.DataFrame(data)
print(data1)
[{'a': 0, 'b': 0}, {'a': 1, 'b': 2}, {'a': 2, 'b': 4}]
<class 'list'>
a b
0 0 0
1 1 2
2 2 4
从上代码可以看出, 当用字典创建DataFrame的时候, 原字典的关键字变成了DataFrame中的列(columns)
pd.DataFrame([{'a':1,'b':100},{'b':1000,'a':12},{'b':123,'c':"湖北"},{'a':1000}])
a | b | c | |
---|---|---|---|
0 | 1.0 | 100.0 | NaN |
1 | 12.0 | 1000.0 | NaN |
2 | NaN | 123.0 | 湖北 |
3 | 1000.0 | NaN | NaN |
x1 = {'a':1,'b':100,'a':100} # 两个a, 居然不报错,但是输出的结果中a只有一个
x1
{'a': 100, 'b': 100}
方式3 : 通过Series创建
rk_dict = {'湖北':23213,
'湖南':213323, # 用冒号 而不是逗号
'广东':233232,
'江西':8238238,
'山东':992329} #注意 山东在 sh中没有
rk = pd.Series(rk_dict)
sh_dict = {'湖北':'武汉',
'湖南':'长沙',
'广东':'广州',
'江西':'南昌',
'广西':'南宁'} #注意广西在rk中没有
sh = pd.Series(sh_dict)
pd.DataFrame({'人口':rk,'省会':sh})
人口 | 省会 | |
---|---|---|
山东 | 992329.0 | NaN |
广东 | 233232.0 | 广州 |
广西 | NaN | 南宁 |
江西 | 8238238.0 | 南昌 |
湖北 | 23213.0 | 武汉 |
湖南 | 213323.0 | 长沙 |
方式4 : 通过NumPy二维数组创建
pd.DataFrame(np.random.rand(3,2),columns=['x1','x2'],index = ['a','b','c'])
x1 | x2 | |
---|---|---|
a | 0.922554 | 0.996392 |
b | 0.878324 | 0.389322 |
c | 0.835772 | 0.593807 |
方式5 : 通过NumPy结构化数组创建. 在2.9节中介绍
A = np.zeros(3,dtype=[('a','i8'),('b','f8')])
print(A)
print(type(A))
A
[(0, 0.) (0, 0.) (0, 0.)]
<class 'numpy.ndarray'>
array([(0, 0.), (0, 0.), (0, 0.)], dtype=[('a', '<i8'), ('b', '<f8')])
pd.DataFrame(A) # 无缝连接?
a | b | |
---|---|---|
0 | 0 | 0.0 |
1 | 0 | 0.0 |
2 | 0 | 0.0 |
3.2.2 Pandas的Index对象
Index可以看作是一个不可变数组或有序集合
ind = pd.Index([2,3,4,7,11])
ind
Int64Index([2, 3, 4, 7, 11], dtype='int64')
将Index看作是不可变数组
ind[1]
3
ind[::2]
Int64Index([2, 4, 11], dtype='int64')
ind[1] = 0 # 值不可修改?
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-77-906a9fa1424c> in <module>()
----> 1 ind[1] = 0
D:\Anaconda3\lib\site-packages\pandas\core\indexes\base.py in __setitem__(self, key, value)
2048
2049 def __setitem__(self, key, value):
-> 2050 raise TypeError("Index does not support mutable operations")
2051
2052 def __getitem__(self, key):
TypeError: Index does not support mutable operations
Index对象遵循Python标准库集合(set)数据结构的许多习惯用法,包括并集,交集,差集等.
inda = pd.Index([1,3,5,7,9])
indb = pd.Index([2,4,5,9,10])
print(inda & indb) # 交集
print(inda | indb) #并集
print(inda ^ indb) # 异或
Int64Index([5, 9], dtype='int64')
Int64Index([1, 2, 3, 4, 5, 7, 9, 10], dtype='int64')
Int64Index([1, 2, 3, 4, 7, 10], dtype='int64')