## 第5章 Pandas入门(2)

以下内容主要学习自《利用Python进行数据分析》

第5章 Pandas入门(2)

数据结构

为了入门pandas,你需要熟悉两个常用的数据结构:Series和DataFrame。

为便于理解,可以把DataFrame看成是关系型数据库的一个表、把Serise看成其中的一个列。但需要警惕,它们并不是完全相同,如:尽管DataFrame通常情况下是二维的,但可以用分层索引在DataFrame中展现更高维度的数据。


dataframe.png

DataFrame

DataFrame表示的是矩阵的数据表,每一列可以是不同的数据类型。DataFrame既有行索引也有列索引。DataFrame的每一列都是一个Series对象。

尽管不完全正确,但可以用关系数据库表来类比:行索引相当于主键、列索引相当于列名。

尽管DataFrame是二维的,但你可以利用分层索引在DataFrame中展现更高维度的数据,将在后续章节进行讨论。

创建DataFrame

下面的例子演示了用ndarray创建一个最简单的DataFrame。

# 引用numpy、pandas
In [1]: import numpy as np
In [2]: import pandas as pd
# 构建了一个3X4的二维ndarray
In [3]: arr = np.arange(12).reshape(3,4)
In [4]: arr
Out[4]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
# 用ndarray创建DataFrame
In [5]: df = pd.DataFrame(arr)
In [6]: df
Out[6]:
    0  1   2   3
0  0  1   2   3
1  4  5   6   7
2  8  9  10  11

注意上面的示例,DataFrame对象除了数据,还包含列索引和行索引,缺省情况下,它们都是从0开始编号的顺序值

如果我们不想使用默认的行/列索引,可以用index属性columns属性修改DataFrame对象的行/列索引。

In [7]: df.index = ['a','b','c']
In [8]: df.columns = ['cn1','cn2','cn3','cn4']
# 经过以上的修改,DataFrame有了新的行列索引
In [9]: df
Out[9]:
   cn1  cn2  cn3  cn4
a    0    1    2    3
b    4    5    6    7
c    8    9   10   11
# 可以给DataFrame的name属性赋值,类似于定义表名
In [10]: df.name = 'my datas'

当然,index、columns可以在构造时就指定,以下代码的效果与上面是一致的。

# 引用numpy、pandas
In [1]: import numpy as np
In [2]: import pandas as pd
# 构建了一个3X4的二维ndarray
In [3]: arr = np.arange(12).reshape(3,4)
# 用ndarray创建DataFrame
In [24]: df = pd.DataFrame(arr,
    ...: index = ['a','b','c'],
    ...: columns = ['cn1','cn2','cn3','cn4'])
In [25]: df
Out[25]:
   cn1  cn2  cn3  cn4
a    0    1    2    3
b    4    5    6    7
c    8    9   10   11

包含等长度列表或NumPy数组的字典,也可以用来构建DataFrame。字典的键将被pandas视为列名。请参考如下的代码:

In [1]: data = {'state': ['Ohio','Ohio','Ohio','Nevada','Nevada','Nevada'],
   ...: 'year': [2000,2001,2002,2001,2002,2003],
   ...: 'pop': [1.5,1.7,3.6,2.4,2.9,3.2]}
In [2]: df = pd.DataFrame(data)
In [3]: df
Out[3]:
   state  year  pop
0    Ohio  2000  1.5
1    Ohio  2001  1.7
2    Ohio  2002  3.6
3  Nevada  2001  2.4
4  Nevada  2002  2.9
5  Nevada  2003  3.2

用字典构建DataFrame时,如果传入columns参数,pandas会按照columns的顺序对列排序;如果字典的键不包含在colums中,pandas会填充缺失值,如下:

In [4]: df = pd.DataFrame(data, columns=['year','state','pop','debt'],
    ...: index=['one','tow','three','four','five','six'])
In [5]: df
Out[5]:
       year   state  pop debt
one    2000    Ohio  1.5  NaN
tow    2001    Ohio  1.7  NaN
three  2002    Ohio  3.6  NaN
four   2001  Nevada  2.4  NaN
five   2002  Nevada  2.9  NaN
six    2003  Nevada  3.2  NaN

在上面的示例中,我们还传入了index参数,用来取代pandas默认的、从0开始的数字行索引。

使用DataFrame构造函数创建DataFrame对象的有效输入小结如下:

类型说明
2D ndarray二维数组,行和列的标签是可选参数
数组、列表、元组构成的字典每个序列成为DataFrame的一列,所有序列必须长度相同
NumPy结构化数组与数组构成的字典一致
Series构成的字典每个值成为一列,每个Series的索引联合起来形成行索引
字典构成的字典每个内部字典成为一列,键联合起来形成行索引
字典或Series构成的列表列表中的一个元素形成一行,字典键或Series索引联合起来形成列标签
列表或元组构成的列表与2D ndarray一致
其它DataFrame默认使用原DataFrame的行列索引
NumPy MaskedArray与2D ndarry一致,但隐藏值会成为NaN缺失值
访问数据

在科学计算中,数据量往往非常大。如果仅要看看DataFrame的结构,可以调用head方法获取头部的5行数据

In [1]: data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'], 'year': [2000, 2001, 2002, 2001, 2002, 2003], 'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]}
In [2]: df = pd.DataFrame(data, columns=['year', 'state', 'pop'], index=['one', 'tow', 'three', 'four', 'five', 'six'])
In [3]: df
Out[3]:
       year   state  pop
one    2000    Ohio  1.5
tow    2001    Ohio  1.7
three  2002    Ohio  3.6
four   2001  Nevada  2.4
five   2002  Nevada  2.9
six    2003  Nevada  3.2
In [4]: df.head()
Out[4]:
       year   state  pop
one    2000    Ohio  1.5
tow    2001    Ohio  1.7
three  2002    Ohio  3.6
four   2001  Nevada  2.4
five   2002  Nevada  2.9

下面的示例演示了获取DataFrame的行数、列数、行索引、列索引等:

# 获取行索引
In [5]: df.index
Out[5]: Index(['ont', 'tow', 'three', 'four', 'five', 'six'], dtype='object')
# 得到行数
In [6]: len(df.index)
Out[6]: 6
# 获取列索引
In [7]: df.columns
Out[7]: Index(['year', 'state', 'pop'], dtype='object')
# 得到列数
In [8]: len(df.columns)
Out[8]: 3

获取行数据,采用与NumPy一致的索引方式,索引值可以是数字索引或标签索引,如下:

In [9]: df[1:3]  # 用数字索引获取第1、2行数据
Out[9]:
       year state  pop
two    2001  Ohio  1.7
three  2002  Ohio  3.6
In [10]: df['four':]  # 用标签索引获取行数据
Out[10]:
      year   state  pop
four  2001  Nevada  2.4
five  2002  Nevada  2.9
six   2003  Nevada  3.2

获取列数据,采用与字典键值索引一致的语法,按列索引得到的结果是Series对象:

In [11]: df['year']
Out[11]:
ont      2000
two      2001
three    2002
four     2001
five     2002
six      2003
Name: year, dtype: int64

获取单元数据,需要同时传入列索引和行索引,如下:

In [12]: df['year']['three']
Out[12]: 2002

获取切片数据,就是得到部分的行列数据子集,关键的语法是:起始行索引用冒号分割,列索引要明确指定并封装为一个列表。至于行索引在前还是列索引在前,都无所谓。如下:

In [13]: df['three':'five'][['state','pop']]
Out[13]:
        state  pop
three    Ohio  3.6
four   Nevada  2.4
five   Nevada  2.9
# 行列索引的先后次序没有关系,下面的语句与如上的等效
In [12]: df[['state','pop']]['three':'five']

调用DataFrame对象的values属性,可以得到ndarray类型的数据集(没有行列索引):

In [14]: df.values
Out[14]:
array([[2000, 'Ohio', 1.5],
       [2001, 'Ohio', 1.7],
       [2002, 'Ohio', 3.6],
       [2001, 'Nevada', 2.4],
       [2002, 'Nevada', 2.9],
       [2003, 'Nevada', 3.2]], dtype=object)
修改数据

初始化dataframe如下:

In [1]: data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'], 'year': [2000, 2001, 2002, 2001, 2002, 2003], 'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]}
In [2]: df = pd.DataFrame(data, columns=['year', 'state', 'pop'], index=['one', 'tow', 'three', 'four', 'five', 'six'])
In [3]: df
Out[3]:
       year   state  pop
one    2000    Ohio  1.5
tow    2001    Ohio  1.7
three  2002    Ohio  3.6
four   2001  Nevada  2.4
five   2002  Nevada  2.9
six    2003  Nevada  3.2

修改行数据,可以通过指定行索引为dataframe的行赋值,下面的例子把一个固定值赋值给行:

# 通过指定行索引为第一行数据赋值
In [4]: df[0:1] = 0
In [5]: df
Out[5]:
       year   state  pop
one       0       0  0.0
tow    2001    Ohio  1.7
three  2002    Ohio  3.6
four   2001  Nevada  2.4
five   2002  Nevada  2.9
six    2003  Nevada  3.2

您可以看出,上面的示例能够正确运行,按并不是一个好的示例。因为每列的数据类型并不相同,为某行的所有列赋值为同一个常量会导致有歧义。

更好些的方式,是为某行赋值一个列表,如下所示:

In [6]: df[0:1] = [2000,'Ohio',3.8]
In [7]: df
Out[7]:
       year   state  pop
one    2000    Ohio  3.8
tow    2001    Ohio  1.7
three  2002    Ohio  3.6
four   2001  Nevada  2.4
five   2002  Nevada  2.9
six    2003  Nevada  3.2

修改列数据
可以把常数赋值给某一列

In [8]: df['pop']=0
In [9]: df
Out[9]:
       year   state  pop
one    2000    Ohio    0
tow    2001    Ohio    0
three  2002    Ohio    0
four   2001  Nevada    0
five   2002  Nevada    0
six    2003  Nevada    0

也可以把一个列表赋值给某一列:

In [10]: df['pop']= [3.3, 1.2, 3.1, 1.9, 2.4, 2.7]
In [11]: df
Out[11]:
       year   state  pop
one    2000    Ohio  3.3
tow    2001    Ohio  1.2
three  2002    Ohio  3.1
four   2001  Nevada  1.9
five   2002  Nevada  2.4
six    2003  Nevada  2.7

还可以在列上直接使用标量运算:

In [12]: df['pop'] = df['pop'] * 3
In [13]: df
Out[13]:
       year   state  pop
one    2000    Ohio  9.9
tow    2001    Ohio  3.6
three  2002    Ohio  9.3
four   2001  Nevada  5.7
five   2002  Nevada  7.2
six    2003  Nevada  8.1

修改单元数据,需要同时指定行索引和列索引。
下面的示例演示了如何修改一个单元格数据

In [14]: df[0:1]['pop'] = 8.8
SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.Try using .loc[row_indexer,col_indexer] = value instead
In [15]: df
Out[15]:
       year   state  pop
one    2000    Ohio  8.8
tow    2001    Ohio  3.6
three  2002    Ohio  9.3
four   2001  Nevada  5.7
five   2002  Nevada  7.2
six    2003  Nevada  8.1

请注意,虽然上面的语句可以完成单元格赋值,但引发了一个警告,该警告说明:比起使用上面的方法,使用.loc[row_indexer,col_indexer] = value更好,在下方的整数索引章节会有更详细的说明。

添加数据

初始化dataframe如下:

In [1]: data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'], 'year': [2000, 2001, 2002, 2001, 2002, 2003], 'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]}
In [2]: df = pd.DataFrame(data, columns=['year', 'state', 'pop'], index=['one', 'tow', 'three', 'four', 'five', 'six'])
In [3]: df
Out[3]:
       year   state  pop
one    2000    Ohio  1.5
tow    2001    Ohio  1.7
three  2002    Ohio  3.6
four   2001  Nevada  2.4
five   2002  Nevada  2.9
six    2003  Nevada  3.2

添加行数据
下面的示例使用字典对象为dataframe添加一行

In [4]: df.append({'year': 2001, 'state': 'Kilo', 'pop': 2.5}, ignore_index=True)
Out[4]:
   year   state  pop
0  2000    Ohio  1.5
1  2001    Ohio  1.7
2  2002    Ohio  3.6
3  2001  Nevada  2.4
4  2002  Nevada  2.9
5  2003  Nevada  3.2
6  2001    Kilo  2.5

在上面的代码中,如果不使用ignore_index=True参数,会报告错误“TypeError: Can only append a Series if ignore_index=True or if the Series has a name”。

下面的代码演示如何用Series对象为dataframe添加行数据,其效果与上面是一样的。

In [5]: rd = pd.Series({'year': 2001, 'state': 'Kilo', 'pop': 2.5} , name='seven')
In [6]: df.append(rd)
Out[6]:
       year   state  pop
one    2000    Ohio  1.5
tow    2001    Ohio  1.7
three  2002    Ohio  3.6
four   2001  Nevada  2.4
five   2002  Nevada  2.9
six    2003  Nevada  3.2
seven  2001    Kilo  2.5

另外,如果两个dataframe的结构一致,也可以使用append方法追加行数据。

添加列数据
使用insert方法为dataframe对象添加一列。

# 把名为memo的数据添加到第二列
In [7]: df.insert(1, 'memo', ['m1','m2','m3','m4','m5','m6'])
In [8]: df
Out[8]:
       year memo   state  pop
one    2000   m1    Ohio  1.5
tow    2001   m2    Ohio  1.7
three  2002   m3    Ohio  3.6
four   2001   m4  Nevada  2.4
five   2002   m5  Nevada  2.9
six    2003   m6  Nevada  3.2
删除数据

使用drop方法删除行列,该方法中的参数axis为1表示删除列,0表示删除行。inplace为True表示直接对原表修改。

删除列

In [9]: df.drop('memo', axis=1, inplace=True)
In [10]: df
Out[10]:
       year   state  pop
one    2000    Ohio  1.5
tow    2001    Ohio  1.7
three  2002    Ohio  3.6
four   2001  Nevada  2.4
five   2002  Nevada  2.9
six    2003  Nevada  3.2

删除行

In [11]: df.drop(['two','three','five'], axis=0, inplace=True)
In [12]: df
Out[12]:
      year   state  pop
one   2000    Ohio  1.5
four  2001  Nevada  2.4
six   2003  Nevada  3.2
运算

使用dataframe对象的stack方法unstack方法可以行列转置,如下:

In [13]: df.stack()
Out[13]:
one   year       2000
      state      Ohio
      pop         1.5
four  year       2001
      state    Nevada
      pop         2.4
six   year       2003
      state    Nevada
      pop         3.2
dtype: object
In [14]: df.stack().unstack(0)
Out[14]:
        one    four     six
year   2000    2001    2003
state  Ohio  Nevada  Nevada
pop     1.5     2.4     3.2

https://www.jianshu.com/p/01cf00fbf144

Python量化投资网携手4326手游为资深游戏玩家推荐:《《执剑之刻》【活动公告】琉胡&深美萌夏限时UP!金秋签到福利来咯~

「点点赞赏,手留余香」

    还没有人赞赏,快来当第一个赞赏的人吧!
0 条回复 A 作者 M 管理员
    所有的伟大,都源于一个勇敢的开始!
欢迎您,新朋友,感谢参与互动!欢迎您 {{author}},您在本站有{{commentsCount}}条评论