2.Pandas的三个对象

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对象,也就具有如下方法:

  1. 通过多个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
    ``
    
    
  2. 通过一个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
    
  3. 通过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
    
  4. 通过字典列表创建
    前面见过,我们可以通过二维数组创建,可以通过值是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里并不一定互异

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值