pandas入门1--数据结构


前言

pandas所包含的数据结构和数据处理工具的设计使得在Python中进行数据清洗和分析非常快捷。pandas支持大部分NumPy语言风格的数组计算,尤其是数组函数以及没有for循环的各种数据处理。尽管pandas采用了很多NumPy的代码风格,但最大的不同在于pandas是用来处理表格型或异质型数据的。而NumPy则相反,它更适合处理同质型的数值类数组数据。


一、pandas数据结构介绍

pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。为了入门pandas,需要先了解两个常用的工具数据结构:Series和DataFrame。别忘了在代码实现中,导入pandas:

import pandas as pd

1.1 Series

Series是一种一维的数组型对象,它包含了一个值序列,并且包含了数据标签,称为索引(index)。最简单的序列可以仅仅由一个数组组成:

n = pd.Series([4, 5, -7, 1])
print(n)
----------------------------------------------------------------
0    4
1    5
2   -7
3    1
dtype: int64

交互式环境中Series的字符串表示,索引在左边,值在右边。由于我们不为数据指定索引,默认生成的索引是从0到N-1( N是数据长度)。你可以通过values属性和index属性分别获得Series对象的值和索引:

n1 = n.values
print(n1)
n1 = n.index
print(n1)
----------------------------------------------------------------
[ 4  5 -7  1]

RangeIndex(start=0, stop=4, step=1)

我们通常需要创建一个索引序列,用标签标识每个数据点:

n2 = pd.Series([4, 5, -7, 3], index=['a', 'b', 'c', 'd'])
print(n2)

n3 = n2.index
print(n3)
----------------------------------------------------------------
a    4
b    5
c   -7
d    3
dtype: int64
Index(['a', 'b', 'c', 'd'], dtype='object')

你可以在从数据中选择数据的时候使用标签来进行索引:

n3 = n2['a']
print(n3)

n2['d'] = 6
print(n2[['b', 'c', 'd']])
----------------------------------------------------------------
4
b    5
c   -7
d    6
dtype: int64

若是使用NumPy的函数或NumPy风格的操作,比如使用布尔值数组进行过滤,与标量相乘,或是应用数学函数,这些操作将保存索引值连接:

n3 = n2[n2>0]
print(n3)

n3 = n2 * 2
print(n3)

n3 = np.exp(n2)
print(n3)
----------------------------------------------------------------
a    4
b    5
d    6
dtype: int64

a     8
b    10
c   -14
d    12
dtype: int64

a     54.598150
b    148.413159
c      0.000912
d    403.428793
dtype: float64

从另一个角度考虑Series,可以认为它是一个长度固定且有序的字典,因为它将索引值和数据值按位置配对。如果你已经有数据包含在Python字典中,你可以使用字典生成一个Series:

sdata = {'oi': 35000, 'texas': 71000, 'oregon': 16000, 'utah': 5000}
n3 = pd.Series(sdata)
print(n3)
----------------------------------------------------------------
oi        35000
texas     71000
oregon    16000
utah       5000
dtype: int64

当你把字典传递给Series构造函数时,产生的Series的索引将是排序好的字典键。你可以将字典键按照你所想要的顺序传递给构造函数,从而使生成的Series的索引顺序符号你的预期:

stats = ['california', 'oi', 'oregon', 'texas']
n4 = pd.Series(sdata,index=stats)
print(n4)
----------------------------------------------------------------
california        NaN
oi            35000.0
oregon        16000.0
texas         71000.0
dtype: float64

在这个例子中sdata中的三个值被放置在正确的位置,但是因为‘california‘没有出现在sdata的键中,因此它对应的是NaN,这是pandas中标记缺失值或NA值的方式。而因为sdata中的utah并不在stats中,被排除在结果对象外。

当遇到缺失数据时,pandas中使用isnull和notnull函数来检查缺失数据:

n5 = pd.isnull(n4)
print(n5)

n5 = n4.notnull()
print(n5)
----------------------------------------------------------------
california     True
oi            False
oregon        False
texas         False
dtype: bool

california    False
oi             True
oregon         True
texas          True
dtype: bool

对于很多应用来说,在数学操作中自动对齐索引是Series的一个非常有用的特性:

n5 = n3 + n4
print(n5)
----------------------------------------------------------------
california         NaN
oi             70000.0
oregon         32000.0
texas         142000.0
utah               NaN
dtype: float64

Series对象自身和其索引都有name属性,这个特性与pandas其他重要功能集成在一起:

n6 = n4.name
print(n6)
n7 = n4.index.name
print(n7)

n4.name = 'population'
n4.index.name = 'state'
print(n4)
----------------------------------------------------------------
None

None

state
california        NaN
oi            35000.0
oregon        16000.0
texas         71000.0
Name: population, dtype: float64

不过一开始Series对象自身和索引的name属性都为None。

Series的索引也可以通过按位赋值的方式进行改变:

n4.index=['1','2','4','3']
print(n4)
----------------------------------------------------------------
1        NaN
2    35000.0
4    16000.0
3    71000.0
Name: population, dtype: float64

1.2 DataFrame

DataFrame表示的是矩阵的数据表,它包含已排序的列集合,每一列可以是不同的值类型(数值、字符串、布尔型等)。DataFrame既有行索引也有列索引,它可以视为一个共享相同索引的Series的字典。在DataFrame中,数据被存储为一个以上的二维块,不是列表,字典或者其他一维数组的集合。

有多种方式可以构建DataFrame,其中最常用的方式是利用包含等长度列表或NumPy数组的字典来形成DataFrame:

data = {'state': ['zhangshang', 'lishi', 'lishi', 'lishi', 'lizi', 'lizi'],
        'year': [2000, 2001, 2002, 2001, 2002, 2003],
        'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]}

frame = pd.DataFrame(data)
print(frame)
----------------------------------------------------------------
        state  year  pop
0  zhangshang  2000  1.5
1       lishi  2001  1.7
2       lishi  2002  3.6
3       lishi  2001  2.4
4        lizi  2002  2.9
5        lizi  2003  3.2

对于大型的DataFrame,head方法将会只选出头部的五行:

p1 = frame.head()
print(p1)
----------------------------------------------------------------
        state  year  pop
0  zhangshang  2000  1.5
1       lishi  2001  1.7
2       lishi  2002  3.6
3       lishi  2001  2.4
4        lizi  2002  2.9

如果指定了列的顺序,DataFrame的列将会按照指定顺序排列:

frame1 = pd.DataFrame(data, columns=['year', 'pop', 'state'])
print(frame1)
----------------------------------------------------------------
   year  pop       state
0  2000  1.5  zhangshang
1  2001  1.7       lishi
2  2002  3.6       lishi
3  2001  2.4       lishi
4  2002  2.9        lizi
5  2003  3.2        lizi

如果你传的列不包含在字典里,将会在结果中出现缺失值:

frame2 = pd.DataFrame(data, columns=['year', 'pop', 'state', 'debt'],
                      index=['one', 'two', 'three', 'four', 'five', 'six'])
print(frame2)
----------------------------------------------------------------
       year  pop       state debt
one    2000  1.5  zhangshang  NaN
two    2001  1.7       lishi  NaN
three  2002  3.6       lishi  NaN
four   2001  2.4       lishi  NaN
five   2002  2.9        lizi  NaN
six    2003  3.2        lizi  NaN

DataFrame中的一列,可以按字典型标记或属性那样检索为Series:

p2 = frame2['state']
print(p2)

p2 = frame2.year
print(p2)
----------------------------------------------------------------
one      zhangshang
two           lishi
three         lishi
four          lishi
five           lizi
six            lizi
Name: state, dtype: object

one      2000
two      2001
three    2002
four     2001
five     2002
six      2003
Name: year, dtype: int64

注意frame2[colum]对于任意列名均有效,但是frame2.column只在列名是有效的Python变量名时有效。

行也可以通过位置或者特殊属性loc进行选取:

p2 = frame2.loc['three']
print(p2)
----------------------------------------------------------------
year      2002
pop        3.6
state    lishi
debt       NaN
Name: three, dtype: object

列的引用是可以修改的。例如,空的’debt‘列可以赋值为标量值或者值数组:

frame2['debt'] = np.arange(6.)
print(frame2)
----------------------------------------------------------------
       year  pop       state  debt
one    2000  1.5  zhangshang   0.0
two    2001  1.7       lishi   1.0
three  2002  3.6       lishi   2.0
four   2001  2.4       lishi   3.0
five   2002  2.9        lizi   4.0
six    2003  3.2        lizi   5.0

当你想要将列表或者数组赋给一个列时,值的长度必须和DataFrame的长度相匹配。如果你将Series赋值给一列时,Series的索引将会按照DataFrame的索引重新排列,并在空缺的地方填充缺失值:

val = pd.Series([-1.2, -1.5, -1.7], index=['two', 'four', 'five'])
frame2['debt'] = val
print(frame2)
----------------------------------------------------------------
       year  pop       state  debt
one    2000  1.5  zhangshang   NaN
two    2001  1.7       lishi  -1.2
three  2002  3.6       lishi   NaN
four   2001  2.4       lishi  -1.5
five   2002  2.9        lizi  -1.7
six    2003  3.2        lizi   NaN

如果被赋值的列并不存在,则会生成一个新的列。在下面这个例子中,我们首先增加一列,这一列是布尔值,判断条件是state列是否为’lishi‘:

frame2['eastern'] = (frame2.state == 'lishi')
print(frame2)
----------------------------------------------------------------
       year  pop       state  debt  eastern
one    2000  1.5  zhangshang   NaN    False
two    2001  1.7       lishi  -1.2     True
three  2002  3.6       lishi   NaN     True
four   2001  2.4       lishi  -1.5     True
five   2002  2.9        lizi  -1.7    False
six    2003  3.2        lizi   NaN    False

del关键字可以像在字典中那样对DataFrame删除列。del方法可以用于移除之前新建的列:

del frame2['eastern']
p2 = frame2.columns
print(p2)
----------------------------------------------------------------
Index(['year', 'pop', 'state', 'debt'], dtype='object')

从DataFrame中选取的列是数据的视图,而不是拷贝。因此对Series的修改会映射到DataFrame中。如果需要复制,则应当使用Series的copy方法。

另一种常用的数据形式是包含字典的嵌套字典。如果嵌套字典被赋值给DataFrame,pandas会将字典的键作为列,将内部字典的键作为行索引:

pop = {'nevada': {2001: 2.4, 2002: 2.9},
       'ohio': {2000: 1.5, 2001: 1.7, 2002: 3.6}}

frame3 = pd.DataFrame(pop)
print(frame3)
----------------------------------------------------------------
     nevada  ohio
2001     2.4   1.7
2002     2.9   3.6
2000     NaN   1.5

可以对DataFrame进行转置操作(调换行和列):

frame4 = frame3.T
print(frame4)
----------------------------------------------------------------
        2001  2002  2000
nevada   2.4   2.9   NaN
ohio     1.7   3.6   1.5

包含Series的字典也可以用于构造DataFrame:

pdata = {'ohio' : frame3['ohio'][:-1],
         'nevada':frame3['nevada'][:2]}

frame5 = pd.DataFrame(pdata)
print(frame5)
----------------------------------------------------------------
      ohio  nevada
2001   1.7     2.4
2002   3.6     2.9

可以向DataFrame构造函数传递的对象列表见下列表:
DataFrame构造函数的有效输入表:

类型注释
2D ndarray数据的矩阵,行和列的标签是可选参数
数组、列表和元组构成的字典每个序列成为DataFrame的一列,所有序列的长度必须相等
NumPy结构化、记录化数组与数组构成一致
Series构成的字典每个值成为一列,每个Series的索引联合起来形成结果的行索引,也可以显示地传递索引
字典构成的字典每一个内部字典成为一列,键联合起来形成结果的行索引
字典或Series构成的列表列表中的一个元素形成DataFrame的一行,字典键或Series索引联合起来形成DataFrame的列标签
列表或元组构成的列表与2Dndarry的情况一致
其他DataFrame如果不显示传递索引,则会使用原DataFrame的索引
NumPy MaskedArray与2D ndarry的情况类似,但隐藏值会在结果DataFrame中成为NA/缺失值

如果DataFrame的索引和列拥有name属性,则这些name属性也会被显示:

frame3.index.name = 'year'
frame3.columns.name = 'state'
print(frame3)
----------------------------------------------------------------
state  nevada  ohio
year               
2001      2.4   1.7
2002      2.9   3.6
2000      NaN   1.5

和Series类似,DataFrame的values属性会将包含在DataFrame中的数据以二维ndarry的形式返回:

n1 = frame3.values
print(n1)
----------------------------------------------------------------
[[2.4 1.7]
 [2.9 3.6]
 [nan 1.5]]

如果DataFrame的列是不同的dtypes,则values的dtype会自动选择适合所有列的类似:

n1 = frame2.values
print(n1)
----------------------------------------------------------------
[[2000 1.5 'zhangshang' nan]
 [2001 1.7 'lishi' -1.2]
 [2002 3.6 'lishi' nan]
 [2001 2.4 'lishi' -1.5]
 [2002 2.9 'lizi' -1.7]
 [2003 3.2 'lizi' nan]]

1.3 索引对象

pandas中的索引对象是用于存储轴标签和其他元数据的(例如轴名称或标签)。在构造Series或DataFrame时,你所使用的任意数组或标签序列都可以在内部转换为索引对象:

obj = pd.Series(range(3), index=['a', 'b', 'c'])
index = obj.index
print(index)
print(index[1:])
----------------------------------------------------------------
Index(['a', 'b', 'c'], dtype='object')
Index(['b', 'c'], dtype='object')

注意:索引对象是不可变的,因此用户是无法修改索引对象的

与Python集合不同,pandas索引对象可以包含重复标签:

dup_labels = pd.Index(['foo', 'foo', 'bar', 'bar'])
print(dup_labels)
----------------------------------------------------------------
Index(['foo', 'foo', 'bar', 'bar'], dtype='object')

根据重复标签进行筛选,会选取所有重复标签对应的数据。

每个索引都有一些集合逻辑的方法和属性,这些方法和属性解决了关于它所包含的数据的其他常见问题。下表中总结了这些方法和属性中常用的一部分。

方法描述
append将额外的索引对象粘贴到原索引后,产生一个新的索引
difference计算两个索引的差集
intersection计算两个索引的交集
union计算两个索引的并集
isin计算表示每一个值是否存在传值容器中的布尔数组
delete将位置i的元素删除,并产生新的索引
drop根据传参删除指定索引值,并产生新的索引
insert在位置i插入元素,并产生新的索引
is_monotonic如果索引序列递增则返回True
is_unique如果索引序列唯一则返回True
unique计算索引的唯一值序列

10月5日结束!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值