- 首页 > 知识库 > >
【读书笔记】《利用Python进行数据分析》第2版
- pandas经常是和其他数值计算工具 , 比如NumPy和SciPy , 以及数据可视化工具比如matplotlib一起使用 。
- pandas支持大部分NumPy的数组计算 , 尤其是数组函数以及没有for循环的各种数据处理 。
- pandas处理表格型或异质型数据 , NumPy处理同质型的数值类数组数据
- 常用的类:Series和DataFrame
5.1 pandas数据结构介绍 Series
- Series是一种一维的数组型对象 , 它包含了一个值序列 , 并且包含了数据标签 , 称为索引(index) 。
- 默认生成索引从0到N-1(N是数据的长度) , 通过values属性和index属性分别获得Series对象的值和索引 。
- 通常会创建一个索引序列 , 用标签标识每个数据点
import pandas as pdobj2 = pd.Series([4,7,-5,3],index=['d','b','a','c'])obj2"""d4b7a-5c3dtype: int64"""obj2.index # Index(['d', 'b', 'a', 'c'], dtype='object')# 使用标签进行索引obj2['a'] # -5obj2[['c','a','d']] # 包含的不是数字而是字符串 , 作为索引列表"""c3a-5d4dtype: int64""" - 可以使用类似NumPy的风格操作:比如使用布尔值数组进行过滤 , 与标量相乘 , 或是应用数学函数 , 这些操作将保存索引值连接 。
- Series是一个长度固定且有序的字典 , 在你可能会使用字典的上下文中 , 也可以使用Series 。
- 使用字典可以生成Series:
pd.Series(字典对象)
- 可以将字典排序后生成Series
sdata = https://tazarkount.com/read/{'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah':5000}states = ['California','Ohio','Oregon','Texas']obj4= pd.Series(sdata,index=states)obj4"""CaliforniaNaN# not a number pandas标记缺失值Ohio35000.0Oregon16000.0Texas71000.0dtype: float64"""
- pandas中使用isnull和notnull函数来检查缺失数据 , “缺失”或“NA”表示缺失数据
pd.isnull(obj4)pd.notnull(obj4)- isnull和notnull也是Series的实例方法:
obj4.isnull()
- Series可用来在数学操作中自动对齐
- Series对象自身和其索引都有name属性
obj4.name = 'population'obj4.index.name = 'state'obj4"""stateCaliforniaNaNOhio35000.0Oregon16000.0Texas71000.0Name: population, dtype: float64""" - 改变Series的索引:按位置赋值
In [41]: objOut[41]:04172-533dtype: int64In [42]: obj.index = ['Bob', 'Steve', 'Jeff', 'Ryan']In [43]: objOut[43]:Bob4Steve7Jeff-5Ryan3dtype: int64
DataFrame
DataFrame是矩阵的数据表 , 它包含已排序的列集合 , 每一列可以是不同的值类型(数值、字符串、布尔值等) 。
DataFrame既有行索引也有列索引 , 它可以被视为一个共享相同索引的Series的字典 。
分层索引是pandas中一种更为高级的数据处理特性 。
构建DataFrame
- 利用等长度列表或NumPy数组的字典来形成DataFrame
data = https://tazarkount.com/read/{'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]}frame = pd.DataFrame(data)frame"""state year pop0 Ohio 2000 1.51 Ohio 2001 1.72 Ohio 2002 3.63 Nevada 2001 2.44 Nevada 2002 2.95 Nevada 2003 3.2"""
一些常用操作
- 大型DataFrame , head方法会选出头部的五行
- 指定列顺序后 , DataFrame的列将会按照指定顺序排列;列不包含在字典中时 , 结果会出现缺失值
- DataFrame中的一列 , 可以按字典型标记或属性那样检索为Series:
frame2['state'] , frame2.year
frame2[colunm]对于任意列名均有效 , 但是frame2.column只在列名是有效的Python变量名时有效
- 返回的Series与原DataFrame有相同的索引 , 且Series的name属性也会被合理地设置 。
- 通过位置或特殊属性loc进行选取:
frame2.loc['three']
- 列的引用是可以修改的 , 例如 , 空的’debt’列可以赋值为标量值或值数组 。
frame2['debt'] = 16.5frame2['debt'] = np.arange(6) - 将列表或数组赋值给一个列时 , 值的长度必须和DataFrame的长度相匹配
- 将Series赋值给一列时 , Series的索引将会按照DataFrame的索引重新排列 , 并在空缺的地方填充缺失值
- 如果被赋值的列并不存在 , 则会生成一个新的列
- del关键字可以删除DataFrame列(像在字典中)
- 向DataFrame中增加一列
-
# 增加一列布尔值 , 判断条件是state是否为'ohio'frame2['eastern'] = frame2.state == 'Ohio'# 注意: frame2.eastern的语法无法创建新的列# del移除之前新建的列del frame2['eastern']
从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)frame3""" Nevada Ohio2001 2.4 1.72002 2.9 3.62000 NaN 1.5"""# 使用类似NumPy语法进行转置操作frame3.T"""2001 2002 2000Nevada 2.4 2.9 NaNOhio 1.7 3.6 1.5"""# 显示指明索引 , 内部字典的键不会排序pd.DataFrame(pop,index=[2001,2002,2003])"""Nevada Ohio2001 2.4 1.72002 2.9 3.62003 NaN NaN""" - DataFrame构造函数的有效输入
- DataFrame的索引和列拥有name属性 , 则这些name属性也会被显示
frame3.index.name='year'frame3.columns.name = 'state'frame3"""state Nevada Ohioyear2001 2.4 1.72002 2.9 3.62000 NaN 1.5""" - DataFrame的values属性会将包含在DataFrame中的数据以二维ndarray的形式返回
frame3.values"""array([[2.4, 1.7],[2.9, 3.6],[nan, 1.5]])"""DataFrame的列是不同的dtypes , 则values的dtype会自动选择适合所有列的类型
索引对象
用于存储轴标签和其他元数据的(例如轴名称或标签)
构造Series或DataFrame时 , 你所使用的任意数组或标签序列都可以转换为索引对象
- 索引对象不可修改 , 分享更为安全
obj = pd.Series(range(3),index=['a','b','c'])index = obj.indexindex # Index(['a', 'b', 'c'], dtype='object')index[1:] # Index(['b', 'c'], dtype='object') - pandas索引对象是一个固定大小的集合 , 但是它可以包含重复标签
- 一些索引对象的方法和属性
5.2 基本功能 重建索引
- reindex是pandas对象的重要方法 , 用于创建一个符合新索引的新对象 , 并进行排列 , 如果某个索引值之前并不存在 , 则会引入缺失值 。
import pandas as pdobj = pd.Series([4.5,7.2,-5.3,3.6],index=['d','b','a','c'])obj"""d4.5b7.2a-5.3c3.6dtype: float64"""obj2 = obj.reindex(['a','b','c','d','e'])obj2"""a-5.3b7.2c3.6d4.5eNaN #如果某个索引值之前并不存在 , 则会引入缺失值dtype: float64""" - 重建顺序数据(时间序列等)索引时可能需要进行插值或填值
- method可选参数可使用ffill等方法在重建索引时插值 , 向前填充
-
obj3 = pd.Series(['blue','purple','yellow'],index=[0,2,4])obj3"""0blue2purple4yellowdtype: object"""obj3.reindex(range(6),method='ffill')"""0blue1blue2purple3purple4yellow5yellowdtype: object"""
DataFrame中的reindex
- reindex可以改变行索引、列索引或同时改变二者 。当仅传入一个序列时 , 结果中的行会重建索引
frame = pd.DataFrame(np.arange(9).reshape((3,3)),index=['a','c','d'],columns=['Ohio','Texas','California'])frame"""Ohio Texas Californiaa 0 1 2c 3 4 5d 6 7 8"""frame2 = frame.reindex(['a','b','c','d'])frame2"""Ohio Texas Californiaa 0.0 1.0 2.0b NaN NaN NaNc 3.0 4.0 5.0d 6.0 7.0 8.0"""# 列可以使用columns关键字重建索引states = ['Texas','Utah','Califormia']frame.reindex(columns=states)""" Texas Utah Califormiaa 1 NaN NaNc 4 NaN NaNd 7 NaN NaN""" - reindex的index参数:新建作为索引的序列 , 可以是索引实例或任意其他序列型Python数据结构 , 索引使用时无须复制
轴向上删除条目
- drop方法会返回一个含有指示值或轴向上删除值的新对象
obj = pd.Series(np.arange(5.),index=['a','b','c','d','e'])obj"""a0.0b1.0c2.0d3.0e4.0dtype: float64"""obj.drop(['d','c'])"""a0.0b1.0e4.0dtype: float64"""
DataFrame中的drop
- 调用drop时默认删除行标签(轴0)
data = https://tazarkount.com/read/pd.DataFrame(np.arange(16).reshape((4, 4)),index=['Ohio', 'Colorado', 'Utah', 'New York'],columns=['one', 'two', 'three', 'four'])data""" one two three fourOhio 0 1 2 3Colorado 4 5 6 7Utah 8 9 10 11New York 12 13 14 15"""data.drop(['Colorado','Ohio'])"""one two three fourUtah 8 9 10 11New York 12 13 14 15"""# 传递axis=1或axis='columns’来从列中删除值data.drop('two',axis=1)"""one three fourOhio 0 2 3Colorado 4 6 7Utah 8 10 11New York 12 14 15""" - drop , 会修改Series或DataFrame的尺寸或形状;直接操作原对象而不是返回新对象
- 【注意】inplace属性:会清除被删除的数据:
obj.drop(‘c’,inplace=True)
索引、选择与过滤
- Series的索引与NumPy数组类似 , 但是不仅可以索引整数
obj = pd.Series(np.arange(4.),index=['a','b','c','d'])obj"""a0.0b1.0c2.0d3.0dtype: float64"""obj['b'] # 1.0obj[2:4]"""c2.0d3.0dtype: float64"""obj[['b','a','d']]"""b1.0a0.0d3.0dtype: float64"""obj[[1,3]]"""b1.0d3.0dtype: float64"""obj[obj<2]"""a0.0b1.0dtype: float64""" - Series切片(不同于Python切片)
- 使用切片修改值会修改Series的相应部分:
obj[‘b’ : ‘c’] - 使用单个值或序列 , 可以从DataFrame中索引出一个或多个列
- 可根据布尔值数组切片选择数据
data[:2] # 选前两行data[data[‘three’]>5]
- 使用布尔值DataFrame进行索引 , 可以和标量比较产生
data < 5 (data是DataFrame类型)data[data<5] = 0 (小于5的数赋值为0)
使用loc和iloc选择数据
DataFrame允许你使用轴标签(loc)或整数标签(iloc)以NumPy风格的语法从DataFrame中选出数组的行和列的子集
- 示例
data.loc['Colorado',['two','three']]"""two5three6Name: Colorado, dtype: int32"""# 整数标签iloc进行类似的数据选择data.iloc[2,[3,0,1]]"""four11one8two9Name: Utah, dtype: int32""" - 所以用于切片
data.loc[:'Utah','two']"""Ohio1Colorado5Utah9Name: two, dtype: int32"""data.iloc[:,:3][data.three >5]"""one two threeColorado 4 5 6Utah 8 9 10New York 12 13 14""" - DataFrame索引选项
整数索引
- 在pandas对象上使用整数索引会产生歧义 , 非整数索引不会有潜在的歧义
- 使用loc(用于标签)或iloc(用于整数)
ser = pd.Series(np.arange(3.))ser"""00.011.022.0dtype: float64"""ser[:1] # 00.0# dtype: float64ser.loc[:1]"""00.011.0dtype: float64"""ser.iloc[:1]"""00.0dtype: float64"""
算术和数据对齐
- 对象相加时 , 索引对不相同 , 返回结果的索引将是索引对的并集 , 类似于数据库的自动外连接(Outer join)
s1 = pd.Series([7.3,-2.5,3.4,1.5],index=['a','c','d','e'])s2 = pd.Series([-2.1,3.6,-1.5,4,3.1],index=['a','c','e','f','g'])s1 +s2"""a5.2c1.1dNaNe0.0fNaNgNaNdtype: float64""" - 【【读书笔记】《利用Python进行数据分析》第2版】将DataFrame对象加在一起 , 返回一个DataFrame , 它的索引、列是每个DataFrame的索引、列的并集 。
- 两个行或列完全不同的DataFrame对象相加 , 结果将全部为空
使用填充值的算术方法
- 两个DataFrame对象相加时 , 一些不重叠的位置会出现NA值 , 举例:填充0:
df1.add(df2,fill_value=https://tazarkount.com/read/0)
- 灵活算术方法
以r开头的副本方法的参数是翻转的 , 1/df1和df1.rdiv(1)等价
DataFrame和Series间的操作
和NumPy中不同维度数组间的操作类似
- 考虑二维数组和其中一行的区别 , 广播机制:减法在每一行都进行了操作(对列进行匹配 , 并广播到各行)
arr = np.arange(12.).reshape((3,4))arr[0] # array([0., 1., 2., 3.])arr - arr[0]"""array([[0., 0., 0., 0.],[4., 4., 4., 4.],[8., 8., 8., 8.]])""" - 在列上进行广播 , 在行上匹配 , 必须使用算术方法的一种:
frame.sub(series3,axis=‘index’) , 使用axis=‘index’或axis=0
函数应用和映射
- NumPy的通用函数(逐元素数组方法)对pandas对象也有效:
np.abs(frame)
- DataFrame的apply方法将函数应用到**一行或一列(默认)**的一维数组上
- 举例
frame = pd.DataFrame(np.random.randn(4,3),columns=list('bde'),index=['Utah','Ohio','Texas','Oregon'])# 函数f , 可以计算Series最大值和最小值的差 , 会被frame中的每一列调用一次# 结果是一个以frame的列作为索引的Seriesf =lambda x:x.max() - x.min()frame.apply(f)"""b3.071398d2.095664e2.016091dtype: float64"""# 函数每行被调用一次frame.apply(f,axis='columns')"""Utah2.410035Ohio0.303477Texas0.808933Oregon1.718999dtype: float64""" - 大部分最常用的数组统计(sum和mean)都是DataFrame的方法 , apply不是必需的
- 传递给apply的不一定要返回一个标量值 , 也可以返回带有多个值的Series
- 可以使用逐元素的Python函数 , 举例:根据frame总的每个浮点数计算一个格式化字符串 , 可以使用applymap方法
format = lambda x: '%.2f' % xframe.applymap(format)"""b d eUtah -0.86 1.53 0.19Ohio 0.25 0.46 -1.16Texas -0.59 -0.60 -1.08Oregon -1.09 0.36 -0.19"""用applymap作为函数名是因为Series有map方法
将逐元素应用到Series上:frame[‘e’].map(format)
排序和排名 排序
- 按行或列索引进行字典型排序 , 使用sort_index方法 , 返回一个新的、排序好的对象
- 默认升序 , 也可以降序排序:ascending=False
- 对DataFrame进行排序时 , 使用一列或多列作为排序键 , 通过给sort_values的可选参数by实现
frame.sort_values(by=‘b’)frame.sort_values(by = [‘a’,’b])
- 使用sort_values方法根据Series的值进行排序
排名
排名是指对数组从1到有效数据点总数分配名次的操作
- Series和DataFrame的rank方法是实现排名的方法 。
- 默认通过平均排名分配到每个组来打破平级关系 。
- 也可以根据他们在数据中的观察顺序进行分配
- 对条目0和2设置的名次为6和7 , 而不是之前的平均排名6.5 , 是因为在数据中标签0在标签2的前面 。
- 按降序排名:
obj.rank(ascending=False,method=‘max’)
- 排名中的平级关系打破方法
- DataFrame可以对行或列计算排名:frame.rank(axis = ‘columns’)
含有重复标签的轴索引
- 轴索引并不是强制唯一性 , 但pandas函数(比如reindex)需要的标签是唯一的
obj = pd.Series(range(5),index=['a','a','b','b','c'])obj"""a0a1b2b3c4dtype: int64"""- 索引的is_unique属性:标签是否唯一
obj.index.is_unique # False - 有重复索引时 , 标签索引多个条目会返回一个序列 , 单个条目会返回标量值
obj['a']"""a0a1dtype: int64"""obj['c'] # 4 - 重复索引会使代码更复杂 , 因为来自索引的输出类型可能因标签是否重复而有所不同
5.3 描述性统计的概述与计算
- Pandas对象封装了常用数学、统计学方法的集合 , 大部分属于规约或汇总统计的类别 。
- 从DataFrame的行或列中抽取一个Series或一系列值的单个值(如总和或平均值)
- 内建了处理缺失值的功能
- 传入axis='columns’或axis=1 , 则会将一行上各个列的值相加:
df.sum(axis=‘columns’)
- NA值会被自动排除(除非全都是) , 可以通过禁用skipna来实现不排除NA值
- 规约方法可选参数
- 有一些方法返回间接统计信息:比如最小值或最大值的索引值:比如idxmin和idxmax
- 积累型方法:
df.cumsum()
- describe方法:一次产生多个汇总统计 , 既不是规约方法也不是积累型方法 。
- 描述性统计和汇总统计方法
相关性和协方差
- Series的corr方法计算的是两个Series中重叠的、非NA的、按索引对齐的值的相关性 。相应地 , cov计算的是协方差 。
returns[‘MSFT’].corr(returns[‘IBM’])returns.MSFT.corr(returns.IBM) , MSFT是一个有效的Python属性- 以DataFrame的形式返回相关性和协方差矩阵
- DataFrame的corrwith方法:DataFrame中的行或列与另一个序列或DataFrame的相关性
- 传入一个Series时 , 会返回一个含有为每列计算相关性值的Series
- 传入一个DataFrame时 , 会计算匹配到列名的相关性数值
- 传入axis='columns’会逐行地进行计算
唯一值、计数和成员属性
另一类相关的方法可以从一维Series包含的数值中提取信息
- unique:给出Series中的唯一值
import pandas as pdobj = pd.Series(['c','a','d','a','a','b','b','c','c'])uniques = obj.unique()uniques # array(['c', 'a', 'd', 'b'], dtype=object) - 计算Series包含值的个数:
value_counts()
- 按照数量降序排序:
pd.value_counts(obj.values,sort=False)
- isin执行向量化的成员属性检查 , 将数据集以Series或DataFrame一列的形式过滤为数据集的值子集 。
- 示例
obj"""0c1a2d3a4a5b6b7c8cdtype: object"""mask = obj.isin(['b','c'])mask"""0True1False2False3False4False5True6True7True8Truedtype: bool"""obj[mask]"""0c5b6b7c8cdtype: object""" - isin相关的Index.get_indexer方法:提供一个索引数组可以将可能非唯一值数组转换为另一个唯一值数组
to_match = pd.Series(['c','a','b','b','c','a'])unique_vals = pd.Series(['c','b','a'])pd.Index(unique_vals).get_indexer(to_match)# array([0, 2, 1, 1, 0, 2], dtype=int64)
- 唯一值、计数和集合成员属性方法
- 计算DataFrame多个相关列的直方图
这里 , 结果中的行标签是所有列中出现的不同值 , 数值则是这些不同值在每个列中出现的次数 。