文章目录
Pandas的三个对象
1.概述
上一章主要讲解了Pandas的一些基本概念.
本章就将讲解Pandas的三个对象:
- Series对象
- DataFrame对象
- Index对象
Series对象类似于Excel表格只有一列的表格,DataFrame对象则类似于既有行又有列的Excel表格
之所以有这样的设计,就是因为Pandas主要的作用就是读取Excel表格中的数据,进行处理,然后在使用Numpy进行处理
2.Pandas的Series对象
Pandas的Series对象是一个带索引数据构成的一维数组.
使用Pandas库的时候需要首先导入Numpy库
Series对象的创建
Sereis对象的创建即直接进行实例化
import pandas as pd
import numpy as np
# 使用列表来创建
变量名=pd.Series(列表)
# 使用Numpy的ndarray对象来创建
变量名=pd.Series(数组)
# 使用字典来创建
变量名=pd.Series(字典)
# 当给定的值只有一个时候,生成的对象的每个位置上的值都会填到所有索引上
变量名=pd.Series(给定值,index=数组) #其中index指定Series对象的索引和元素个数
其中:
-
使用字典创建的Series对象的索引值就是字典的键值.
-
此外,当我们使用字典来创建数组的时候,只会保留index中指定的索引所对应的值
dict_1={2:'a',1:'b',3:'c'} data=pd.Series(dict_1,index=[3,2]) print(data) >>> 3 'c' 2 'a'
可以看到,data只保留了键值为3和2的数据,并且按照index中的顺序保留
例如:
import numpy as np
import pandas as pd
data_1=pd.Series([0.25,0.5,0.75,1.0])
print(data_1)
>>>
0 0.25
1 0.50
2 0.75
3 1.00
dtype:float64
data_2=pd.Series({'a':0.25,'b':0.50,'c':0.75,'d':1.00})
print(data_2)
>>>
'a' 0.25
'b' 0.50
'c' 0.75
'd' 1.00
array_1=np.array([0.25,0.5,0.75,1.0])
data_3=pd.Series(array_1)
print(data_3)
>>>
0 0.25
1 0.50
2 0.75
3 1.00
dtype: float64
通过上面的这个例子,我们可以发现Series对象将我们传入的数据和一组索引绑定在一起.
我们可以通过values属性和index属性来获取数据
Series对象数据的获取
获取Series对象的值
我们可以使用Series对象的values属性类获取所有的值,结果将返回numpy的ndarray对象
数组名.values
例如:
data_1=pd.Series([0.25,0.5,0.75,1.0])
print(data_1)
print(type(data_1))
print(data_1.values)
print(type(data_1.values))
>>>
0 0.25
1 0.50
2 0.75
3 1.00
dtype: float64
<class 'pandas.core.series.Series'>
[0.25 0.5 0.75 1. ]
<class 'numpy.ndarray'>
可以发现,我们通过Series的Value属性得到的是包含所有值的numpy.ndarray对象
获取Series对象的索引
我们可以使用Series对象的index属性来获取所有的索引,结果将返回pandas的Index对象(Index对象将在后面讲)
变量名.index
例如:
data_1=pd.Series([0.25,0.5,0.75,1.0])
print(data_1)
print(type(data_1))
print(data_1.index)
print(type(data_1.index))
>>>
0 0.25
1 0.50
2 0.75
3 1.00
dtype: float64
<class 'pandas.core.series.Series'>
RangeIndex(start=0, stop=4, step=1)
<class 'pandas.core.indexes.range.RangeIndex'>
这里的索引表示方法类似于切片操作,使用起始偏移量,终止偏移量和步长来描述所有的索引.这里就是[0,1,2,3]
获取Series对象元素的值
前面使用Value属性获取的是整个Series对象所包含的所有值的一个numpy.ndarrray对象
但是和Numpy中的数组一样,我们可以使用索引和切片来获取元素的值
变量名[偏移量]
变量名[起始偏移量:终止偏移量:步长]
其中:
-
后面会讲到,Series对象的偏移量不一定是一个数字,可以是其他任何类型的数据,这个时候切片和偏移量操作依旧可以
data_1=pd.Series({'a':1,'b':2,'c':3,'d':4}) print(data_1['a':'c']) >>> a 1 b 2 c 3
例如:
data_1=pd.Series([0.25,0.5,0.75,1.0])
print(data_1[1])
print(data_1[1:3])
print(type(data_1[1]))
print(type(data_1[:3]))
>>>
0.5
1 0.50
2 0.75
dtype: float64
<class 'numpy.float64'>
<class 'pandas.core.series.Series'>
我们会发现,输出单个值的时候只输出值,输出切片的时候会连索引一起输出
并且和Numpy类似,返回的依旧是原Series对象的一个视图,对视图进行修改的话原Series对象也会被改变
同样,如果我们想要得到是原Series对象的一个副本的话,可以用Series对象的copy方法
Series是Numpy数组的加强版
我们可能觉得Series对象和Numpy的一维数组几乎可以等价替换.
因为他们在很多地方都很相似,包括都可以用索引,切片操作.
其实随着我们学习的深入,我们还会学到更多与Numpy数组方法和属性类似的Series对象更多的方法和属性.
其实两者本质区别就是:
- Numpy数组的索引是隐式的.即Numpy数组是通过隐式定义整数索引获得整数值
- Pandas的Series对象通过一种显示定义的索引和数值关联
因此,既然Pandas的Series对象是通过显示定义的,这也就赋予了Series对象更强的能力.
事实上,我们可以修改索引的值,可以用任意数据来定义索引
数组名.index=([索引1,索引2,...,索引n])
#或者在创建Series对象的时候,直接指定索引
pd.Series([元素值1,...元素值n],index=[索引1,...,索引n])
其中:
- 索引可以是任何类型的数据,包括字符,字符串,数字等
例如:
data_1=pd.Series([0.25,0.5,0.75,1.0])
data_2=pd.Series([0.25,0.5,0.75,1.0],index=['a','b','c','d'])
print(data_1)
data_1.index=['a','b','c','d']
print(data_1)
print(data_2)
>>>
0 0.25
1 0.50
2 0.75
3 1.00
dtype: float64
a 0.25
b 0.50
c 0.75
d 1.00
dtype: float64
a 0.25
b 0.50
c 0.75
d 1.00
dtype: float64
Series是特殊的字典
事实上,我们可以把Pandas的Series对象看成一种特殊的Python字典.
字典是一种将任意键映射到一组任意值的数据结构
而Series对象其实是一种将类型键映射到一组类型值的数据结构
需要注意,类型在这里至关重要,就像Numpy中的数组使用同一种类型的数据是因为Numpy的代码通过底层的编译使得对Numpy数组的操作非常的便捷.
同理,Pandas的Series的类型信息使得Pandas在某些操作上比Python中原生的字典更高效.
所以我们自然可以通过键名来获取对对应的键值
data_1=pd.Series([0.25,0.5,0.75,1.0],index=['a','b','c','d'])
print(data_1[1])
print(data_1['b'])
>>>
0.5
0.5
可以看到对Series对象使用偏移量和使用键名来索取的效果一样
3.Pandas的DataFrame对象
Pandas的另外一个基础数据结构是DataFrame.和上面介绍的Series对象一样,DataFrame既可以作为一个通用型Numpy数组,也可以看做特殊的Python字典.
下面就将讲解DataFrame对象
DataFrame是通用的Numpy数组
Series可以看做是具有灵活行索引的一维数组,那么DataFrame就可以看做具有列索引和行索引的二维数组,所以DataFrame是通用的,具有行列索引的Numpy二维数组
我们也可以把DataFrame对象看成多个Series对象有序排列.每个Series对象在同一行的元素都共享同一行索引.每个Series对象都有各自的列索引
DataFrame是特殊的字典
与Series对象类似,我们可以把DataFrame看成是一种特殊的字典.Series对象是一个列索引映射到任意的值的字典.而DataFrame对象则是一个列索引映射一个Series对象.
DataFrame对象的创建
前面讲过,DataFrame既可以看成具有行索引和列索引的二维数组.也看看成是一个自列索引映射到Series对象的字典.所以我们创建Series对象,也就具有如下方法:
-
通过多个Serie对象创建.
DataFrame对象可以看成是一组Series对象的集合.所以就可以用值为Series对象的字典创建pd.DataFrame({列索引1:Series对象1,...,列索引n:Series对象n})
例如:
import numpy as np import pandas as pd Series_1=pd.Series({'row_1':1,'row_2':2,'row_3':3,'row_4':4}) Series_2=pd.Series({'row_1':5,'row_2':6.'row_3':7.'row_4':8}) print(pd.DataFrame({'col_1':Series_1,'col_2':Series_2})) >>> col_1 col_2 row_1 1 5 row_2 2 6 row_3 3 7 row_4 4 8
需要注意的是,如果运用拼接Series对象来创DataFrame对象的话,那么只有行索引相同的值才会并列到一起.否则就会显示缺失值NaN(Not a number),例如:
import numpy as np import pandas as pd Series_1=pd.Series({'row_1':1,'row_2':2,'row_3':3,'row_4':4}) Series_2=pd.Series({'row_a':5,'row_b':6.'row_c':7.'row_d':8}) print(pd.DataFrame({'col_1':Series_1,'col_2':Series_2})) >>> col_1 col_2 row_1 1.0 NaN row_2 2.0 NaN row_3 3.0 NaN row_4 4.0 NaN row_a NaN 5.0 row_b NaN 6.0 row_c NaN 7.0 row_d NaN 8.0 -------------------------------------------------------------------------------------- import numpy as np import pandas as pd Series_1=pd.Series({'row_1':1,'row_2':2,'row_a':3,'row_b':4}) Series_2=pd.Series({'row_a':5,'row_b':6.'row_3':7.'row_4':8}) print(pd.DataFrame({'col_1':Series_1,'col_2':Series_2})) >>> col_1 col_2 row_1 1.0 NaN row_2 2.0 NaN row_3 NaN 7.0 row_4 NaN 8.0 row_a 3.0 5.0 row_b 4.0 6.0 -------------------------------------------------------------------------------------- import numpy as np import pandas as pd Series_1=pd.Series({'row_1':1,'row_2':2,'row_3':3,'row_4':4}) Series_2=pd.Series({'row_1':5,'row_2':6,'row_3':7,'row_4':8}) Series_3=pd.Series({'row_a':9,'row_b':10,'row_c':11,'row_d':12}) Series_4=pd.Series({'row_1':13,'row_2':14,'row_a':15,'row_b':16}) DataFrame_1=pd.DataFrame({'col_1':Series_1,'col_2':Series_2,'col_3':Series_3,'col_4':Series_4}) print(DataFrame_1) >>> col_1 col_2 col_3 col_4 row_1 1.0 5.0 NaN 13.0 row_2 2.0 6.0 NaN 14.0 row_3 3.0 7.0 NaN NaN row_4 4.0 8.0 NaN NaN row_a NaN NaN 9.0 15.0 row_b NaN NaN 10.0 16.0 row_c NaN NaN 11.0 NaN row_d NaN NaN 12.0 NaN ``
-
通过一个Series对象创建
有的时候,我们只需要创建出一个包含一个Series对象的DataFrame对象,有点类似于Numpy中ndarray对象从(3,)升维成(3,1)pd.DataFrame(Series对象名,columns=[列索引值])
例如:
import numpy as np import pandas as pd Series_1=pd.Series({'row_1':1,'row_2':2,'row_3':3,'row_4':4}) print(pd.DataFrame(Series_1,columns=['col_1'])) >>> col_1 row_1 1 row_2 2 row_3 3 row_4 4
-
通过Numpy数组对象Numpy.ndarray创建
pd.DataFrame(Numpy.ndarray对象名,columns=[列索引值],index=[行索引值])
例如:
import numpy as np import pandas as pd np_matrix=np.full((3,4),5) print(pd.DataFrame(np_matrix)) >>> 0 1 2 3 0 5 5 5 5 1 5 5 5 5 2 5 5 5 5
从上面的例子中我们可以看到,通过这种方式创建的DataFrame对象不指定行列索引时,默认会添加上数字索引
我们可以在创建DataFrame对象的时候通过指定columns和Index参数来指定行列名import numpy as np import pandas as pd np_matrix=np.full((3,4),5) print(pd.DataFrame(np_matrix,columns=['col_1','col_2','col_3','col_4'],index=['row_1','row_2','row_3'])) >>> col_1 col_2 col_3 col_4 row_1 5 5 5 5 row_2 5 5 5 5 row_3 5 5 5 5
-
通过字典列表创建
前面见过,我们可以通过二维数组创建,可以通过值是Series对象的字典创建,那么我们其实还可以通过列表字典创建.pd.DataFrame([字典1,字典2,...,字典n])
其中,每个字典的键名将作为列索引
和用字典创建DataFrame对象一样,只有当列同名的时候,才会将值排列到同一列,否则就会显示NaN缺失值import numpy as np import pandas as pd dict_1={'col_1':1,'col_2':2} dict_2={'col_1':1,'col_2':2} print(pd.DataFrame([dict_1,dict_2])) >>> col_1 col_2 0 1 2 1 1 2 -------------------------------------------------------------------------------------- import numpy as np import pandas as pd dict_1={'col_1':1,'col_2':2} dict_2={'col_1':1,'col_3':2} print(pd.DataFrame([dict_1,dict_2])) >>> col_1 col_2 col_3 0 1 2.0 NaN 1 1 NaN 2.0
4.Pandas的Index对象
我们已经发现,Pandas中的Series对象和DataFrame对象都使用便于引用和调整的显式索引.
而Pandas的Index对象则可以看做一个不可变的数组或者是有序集合
因此,这两种观点下Index对象就会有很多奇妙的功能.
Index对象的创建
pd.Index(数组或者numpy.ndarray对象)
例如:
import numpy as np
import pandas as pd
index_1=pd.Index(linspace(1,10,5))
index_2=pd.Index([1,2,3,4,5])
print(index_1)
print(index_2)
>>>
Float64Index([1.0, 3.25, 5.5, 7.75, 10.0], dtype='float64')
Int64Index([1, 2, 3, 4, 5], dtype='int64')
但是需要注意,如果输入的高维数组,最后打印出来是一维的,如果使用Index对象的shape属性查询却是原来的形状,此时我们使用索引来取值的时候,要使用原数组的索引,例如
index_1=pd.Index(np.arange(12).reshape((3,4)),5)
print(index_1)
print(index_1.shape)
print(np.arange(12).reshape((3,4)))
print(index_1[1])
>>>
Int64Index([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], dtype='int64')
(3, 4)
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[4 5 6 7]
发现尽管Index对象的==“外形”==是一个一维数组,但实际上它的形状和原数组一样,包括在使用偏移量和切片来获取值的时候都是一模一样的.
Index对象的属性
Index对象具有许多与Numpy类似的属性
Index对象名.size
Index对象名.shape
Index对象名.ndim
Index对象名.dtype
例如:
import numpy as np
import pandas as pd
array_1=np.arange(1,10).reshape(3,3)
index_1=pd.Index(array_1)
print(index_1.shape)
print(index_1.size)
print(index_1.dtype)
print(index_1.ndim)
>>>
(3, 3)
3
1
int64
将Index对象看做不可变的数组
如果我们把Index对象看做是不可变的数组,那么我们对一般的数组可以进行的操作都可以对Index使用.
取值
Index对象名[偏移量]
切片
Index对象名[起始偏移量:终止偏移量:步长]
例如:
index_1=pd.Index(np.linspace(1,10,5))
print(index_1)
print(index_1[1])
print(index_1[1:3])
print(index_1[-1:-3:-1])
>>>
Float64Index([1.0, 3.25, 5.5, 7.75, 10.0], dtype='float64')
3.25
Float64Index([3.25, 5.5], dtype='float64')
Float64Index([10.0, 7.75], dtype='float64')
但是注意,由于Index对象是不可变的数组,因此无法对其进行赋值操作,否则就会报错
index_1=pd.Index(np.linspace(1,10,5))
print(index_1)
index_1[1]=2
>>>
Float64Index([1.0, 3.25, 5.5, 7.75, 10.0], dtype='float64')
Traceback (most recent call last):
File "地址1", line 91, in <module>
index_1[1]=2
File "地址2", line 4260, in __setitem__
raise TypeError("Index does not support mutable operations")
TypeError: Index does not support mutable operations
将Index对象看做有序集合
Pandas对象被设计用于实现许多操作,包括连接数据集(join),其中会涉及到许多集合操作.
Index对象遵循Python标准库中集合数据结构的许多习惯用法.包括交并补差等运算.
Index对象名_1 & Index对象名_2 #求交集
Index对象名_1 | Index对象名_2 #求并集
Index对象名_1 ^ Index对象名_2 #求异或
例如:
index_1=pd.Index([1,2,3,4,5])
index_2=pd.Index([4,5,6,7,8])
index_3=pd.Index([0,0,0,0,0])
print(index_1)
print(index_2)
print(index_3)
print(index_1&index_2)
print(index_1|index_2)
print(index_1^index_2)
print(index_1|index_3)
>>>
Int64Index([1, 2, 3, 4, 5], dtype='int64')
Int64Index([4, 5, 6, 7, 8], dtype='int64')
Int64Index([0, 0, 0, 0, 0], dtype='int64')
Int64Index([4, 5], dtype='int64')
Int64Index([1, 2, 3, 4, 5, 6, 7, 8], dtype='int64')
Int64Index([1, 2, 3, 6, 7, 8], dtype='int64')
Int64Index([0, 0, 0, 0, 0, 1, 2, 3, 4, 5], dtype='int64')
但是需要注意的是:数学中的集合,元素是互异的,但是在Python里并不一定互异