学机器学习,不会数据处理怎么行?—— 二、Pandas详解
在上篇文章学机器学习,不会数据处理怎么行?—— 一、NumPy详解中,介绍了NumPy的一些基本内容,以及使用方法,在这篇文章中,将接着介绍另一模块——Pandas。(本文所用代码在这里)
Pandas数据结构介绍
大家应该都听过表结构,但是,如果让你自己来实现这么一个结构,并且能对其进行数据处理,能实现吗?我相信,大部分人都能做出来,但是不一定能做的很好。而Python中的一个模块pandas给我们提供了一个很好的数据结构,它包括了序列Series和数据框DataFrame。pandas是基于NumPy数组构建的,特别是基于数组的函数和不使用for循环的数据处理,让以Numpy为中心的应用变得更加简单。
Series
创建方式
Series是一种类似于一维数组的对象,它由一组数据(各种NumPy数据类型)以及一组与之相关的数据标签(即索引)组成,其创建主要有三种方式
1)通过一维数组创建序列
- import numpy as np
- import pandas as pd
- arr1 = np.arange(10)
- s1 = pd.Series(arr1)
通过type函数可查看arr1与s1的类型分别为,numpy.ndarray 和 pandas.core.series.Series。
3)通过字典的方式创建
- dic1 = {'a': 1,'b': 2,'c': 3,'d': 4,'e': 50}
- s2 = pd.Series(dic1)
通过type函数可查看dic1与s2的类型分别为,dict 和 pandas.core.series.Series。
3)通过DataFrame中的某一行或者某一列创建序列
这一步将在下面讲DataFrame的时候再补充
Series索引
我们上面在创建Series序列时,可以输出查看我们创建的Series长什么样,发现有两列,第二列的数据跟我们输入的是一样的,那第一列是什么呢?那就是索引。Series的字符串表现形式为:索引在左边,值在右边。如果我们没有为数据指定索引,就会自动创建一个0到N-1(N为数据的长度)的整数型索引。
我们可以通过 Series 的 values 和 index 属性获取其数组表示形式和索引对象。
- obj = pd.Series([6, 9, -8, 1])
- obj.values
- obj.index
我们也能修改其索引
- obj.index = ['a','b','c','d']
讲了那么多,知道这是索引了,但它有什么用呢?
1.我们可以通过索引值或索引标签进行数据的获取
- obj['a']
- obj[3]
- obj[[0,2,3]]
- obj[0:2]
- obj['a':'c']
注:若通过索引标签获取数据的话,末端标签对应的值也将返回!!!
2.自动化对齐
如果有两个序列,需要对这两个序列进行算术运算,这时索引的存在就体现的它的价值了—自动化对齐.
- obj1 = pd.Series(np.array([10,15,20,30,55,80]),index = ['a','b','c','d','e','f'])
- obj2 = pd.Series(np.array([12,11,13,15,14,16]),index = ['a','c','g','b','d','f'])
- obj1+obj2
- obj1*obj2
我们会发现,计算后的序列号中,g和e对应的值为NaN,这是因为obj1中没有g索引,obj2中没有e索引,所以数据的运算会产生两个缺失值NaN。
DataFrame
DataFrame是一个表格型的数据结构,它含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔值等)。DataFrame既有行索引也有列索引,它可以被看做由Series组成的字典。
创建方式
1)通过二维数组创建
- arr2 = np.array(np.arange(12).reshape(4,3))
- df1 = pd.DataFrame(arr2)
2)通过字典的方式创建
该方式可通过字典列表和嵌套字典实现,如果将嵌套字典传给DataFrame,pandas就会被解释为:外层字典的键作为列,内层键则作为行索引
- #字典列表
- dic2 = {'a': [1, 2, 3, 4],'b': [5, 6, 7, 8],'c': [9, 10, 11, 12],'d': [13, 14, 15, 16]}
- df2 = pd.DataFrame(dic2)
- #嵌套字典
- dic3 = {'one': {'a': 1,'b': 2,'c': 3,'d':4},
- 'two': {'a': 5,'b': 6,'c': 7,'d': 8},
- 'three':{'a': 9,'b': 10,'c': 11,'d':12}}
- df3 = pd.DataFrame(dic3)
3)通过数据框的方式创建
- df4 = df3[['one','three']]
- s3 = df4['one']
DataFrame索引
DataFrame的索引与Series的索引大体上是一样的,不过DataFrame有两个索引,分别是列索引和行索引,感觉看起来就跟excel差不多了。具体的实现方式可通过下面的部分来了解。
利用pandas进行数据处理
pandas可以通过布尔索引有针对的选取原数据的子集、指定行、指定列等,同时我们可以通过 pd.read_csv()来导入数据集,因为暂时找不到数据集,就从别人的代码里复制一些过来了
- 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]}
- frame = pd.DataFrame(data)
选择数据
简单筛选
我们可以使用以下函数来查询数据的前几行或后几行(默认5行)
- frame.head()
- frame.tail()
也可以使用行列索引来简单地查询指定的行和列
- frame['state']
- frame[0:3]
loc
当然,上面的方式只是比较简单的操作,复杂些的,我们可以通过 loc 来选取数据(: 表示所有行)
- frame.loc[:,['state','year']]
iloc
另外,我们也可以使用iloc,通过位置选择在不同情况下所需要的数据,可进行选取某个数据、连续或者跨行选择等操作
- frame.iloc[0:2,0:2]
ix
除此之外还有一种操作方式,使用 混合选择 ix ,我这里的表可能无法很好的体现,如果将行索引改为字符就可以看出来了
- frame.ix[3:5,['year']]
发现输入这行代码运行之后发出一条警告
- DeprecationWarning:
- .ix is deprecated. Please use
- .loc for label based indexing or
- .iloc for positional indexing
emmmmm。。想想以后主要还是用 loc 和 iloc 好了。
通过判断的筛选
除了上面讲的之外,我们还可以通过判断指令进行选择,即通过约束某项条件然后选择出当前所有数据。
- frame[frame['year']>2001]
数据修改
讲完了数据选择,既然选择出了数据,我们可能会想去修改数据,那么,怎么修改呢?
根据位置
我们可以利用索引或者标签确定需要修改的位置
- frame.iloc[0,2]=1.6
- frame.loc[1,'pop']=2
根据条件
如果我们想将数据中'pop'栏小于1.7的'year'改为1999,那么我们可以进行如下操作
- frame.year[frame['pop']<1.7]=1999
按行或按列设置
我们还可以对行列进行批处理
- frame['pop']=2.6
添加和删除数据
上面讲的都是数据的修改,再来讲讲数据的添加和删除
- #数据添加
- #方法一
- frame['A'] = np.nan
- #方法二
- frame['B'] = pd.Series([1, 2, 3, 4, 5, 6])
- #数据删除
- frame.drop('B',axis = 1)
注:
- 对于方法二,长度必须对齐,如果行索不为默认则需指定索引
- dates = pd.date_range('', periods=6)
- df = pd.DataFrame(np.arange(24).reshape((6,4)),index=dates, columns=['A','B','C','D'])
- df['E'] = pd.Series([1, 2, 3, 4, 5, 6],index=pd.date_range('',periods=6))
- 对于数据删除,axis取值 0表示删除行索引 1表示删除列索引 默认为0
统计分析
pandas模块为我们提供了非常多的描述性统计分析的指标函数,如总和、均值、最小值、最大值等,跟对应的NumPy数组方法相比,它们都是基于没有缺失数据的假设而构建的,下图中列举了大部分函数
这里有几点需要注意
- descirbe函数只能针对序列或者数据框,一维数组是没有这个方法的。
- 使用sum时,NaN值会自动被排除,除非整个切片都是NaN,通过skipna选项可以禁用该功能。
- 调用sum时,返回的时含有列的和的Series,需要传入axis的值才会进行行运算
当我们要对一列数据进行分析时,我们可以将要分析的内容封装成一个函数,方便调用
- def stats(x):
- return pd.Series([x.count(),x.min(),x.idxmin(),
- x.quantile(.25),x.median(),
- x.quantile(.75),x.mean(),
- x.max(),x.idxmax(),
- x.mad(),x.var(),
- x.std(),x.skew(),x.kurt()],
- index = ['Count','Min','Whicn_Min',
- 'Q1','Median','Q3','Mean',
- 'Max','Which_Max','Mad',
- 'Var','Std','Skew','Kurt'])
有时或许会需要对一个数据框进行分析,那该如何操作?是一列一列不断地取出来然后调用函数吗?这个方法也不是不可行,但面对众多数据时该怎么办?一个一个调用怕不是要弄到明年,在这里我们可以使用apply函数
- d1 = pd.Series(2*np.random.normal(size = 100)+3)
- d2 = np.random.f(2,4,size = 100)
- d3 = np.random.randint(1,100,size = 100)
- df = pd.DataFrame(np.array([d1,d2,d3]).T,columns=['x1','x2','x3'])
- df.head()
- df.apply(stats)
就这样很简单的创建了数值型数据的统计性描述。但如果是离散型数据呢?就不能用这个统计口径了,我们需要统计离散变量的观测数、唯一值个数、众数水平及个数。你只需要使用describe方法就可以实现这样的统计了。
缺失值处理
现实生活中的数据是非常杂乱的,其中缺失值也是非常常见的,对于缺失值的存在可能会影响到后期的数据分析或挖掘工作,那么我们该如何处理这些缺失值呢?常用的有三大类方法,即删除法、填补法和插值法。
删除法:当数据中的某个变量大部分值都是缺失值,可以考虑删除改变量;当缺失值是随机分布的,且缺失的数量并不是很多是,也可以删除这些缺失的观测。
替补法:对于连续型变量,如果变量的分布近似或就是正态分布的话,可以用均值替代那些缺失值;如果变量是有偏的,可以使用中位数来代替那些缺失值;对于离散型变量,我们一般用众数去替换那些存在缺失的观测。
插补法:插补法是基于蒙特卡洛模拟法,结合线性模型、广义线性模型、决策树等方法计算出来的预测值替换缺失值。
删除法
这里仅讲述删除法和替补法,先来看删除法,先建立一个6X4的矩阵数据并且把两个位置置为空
- dates = pd.date_range('', periods=6)
- df = pd.DataFrame(np.arange(24).reshape((6,4)),index=dates, columns=['A','B','C','D'])
- df.iloc[0,1] = np.nan
- df.iloc[1,2] = np.nan
我们可以结合sum函数和isnull函数来检测数据中含有多少缺失值
- for i in df.columns:
- print(sum(pd.isnull(df[i])))
也可以通过any来判断是否存在缺失值
- np.any(df.isnull()) == True
删除直接dropna就行了
- df.dropna(
- axis=0, # 0: 对行进行操作; 1: 对列进行操作 默认为0
- how='any' # 'any': 只要存在 NaN 就 drop 掉; 'all': 必须全部是 NaN 才 drop 默认为'any'
- )
填补法
简单粗暴的办法就是把所有的NaN用0代替
- df.fillna(value=0)
稍微好一点的方法,使用常量填充不同的列
- df.fillna({'B': 3,'C': 4})
还算好的方法,采用前项填充或后向填充
- df.fillna(method = 'ffill') #用前一个观测值填充
- df.fillna(method = 'bfill') #用后一个观测值填充
较好的方法,用均值或中位数填充各自的列
- df.fillna(df.median())
- df.fillna(df.mean())
很显然,在使用填充法时,相对于常数填充或前项、后项填充,使用各列的众数、均值或中位数填充要更加合理一点,这也是工作中常用的一个快捷手段。
注:使用fillna,dropna时,需要添加参数 inplace = True,如df.fillna(df.median(),inplace = True),以确认修改,否则实际的数据并不会有改动。
数据合并
concat
pandas 处理多组数据的时候往往会要用到数据的合并处理,使用 concat 是一种基本的合并方式.而且concat中有很多参数可以调整,合并成你想要的数据形式.
先创建数据集
- df1 = pd.DataFrame(np.ones((3,4))*0, columns=['a','b','c','d'])
- df2 = pd.DataFrame(np.ones((3,4))*1, columns=['a','b','c','d'])
- df3 = pd.DataFrame(np.ones((3,4))*2, columns=['a','b','c','d'])
concat合并
- pd.concat([df1, df2, df3], axis=0) #纵向合并
- pd.concat([df1, df2, df3], axis=1) #横向合并
这里观察下纵向合并的输出,会发现index的值为0,1,2,0,1,2,0,1,2,大部分情况下,这肯定不是我们想要的,我们可以通过一下方法来重置index
- pd.concat([df1, df2, df3], axis=0, ignore_index=True)
pandas中的数据结构是支持类似SQL的部分操作方式的,如添加新行新列、多表连接、聚合什么的。pandas有个join参数,用来定义连接方式的,默认为outer,此方式是依照column来做纵向合并有相同的column上下合并在一起,其他的独自成列,没有的值用NaN填充
- df1 = pd.DataFrame(np.ones((3,4))*0, columns=['a','b','c','d'], index=[1,2,3])
- df2 = pd.DataFrame(np.ones((3,4))*1, columns=['b','c','d','e'], index=[2,3,4])
- res = pd.concat([df1, df2], axis=0, join='outer')#纵向"外"合并df1与df2
参数:
- axis 表示行或列,0为行,1为列
- join 'inner':内连接,会产生NaN的列丢弃 ‘outer’:外连接,上面介绍过了
另外,还有join_axes也可以决定连接方式
- pd.concat([df1, df2], axis=1, join_axes=[df1.index])
- pd.concat([df1, df2], axis=1, join_axes=[df2.index])
运行上面两行代码,就会发现有所不同,第一行是以df1的index为依据,将df2中具有相同索引的行对应拼接上去,第二行同样的道理。
此外,还有append操作,该操作类似与axis=0,join='outer'时的操作,不过要注意的是append只有纵向合并。
merge
pandas中的合并操作除了concat之外,还有merge操作,主要用于两组有key column的数据,统一索引的数据. 通常也被用在Database的处理当中.
看个简单的,依据一组Key合并
- left = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'],
- 'A': ['A0', 'A1', 'A2', 'A3'],
- 'B': ['B0', 'B1', 'B2', 'B3']})
- right = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'],
- 'C': ['C0', 'C1', 'C2', 'C3'],
- 'D': ['D0', 'D1', 'D2', 'D3']})
- pd.merge(left, right, on='key')
稍微难一点就是依据两组Key合并,合并时有四种方法 how=['left','right','outer','inner'],默认为how='inner'
- left = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'],
- 'key2': ['K0', 'K1', 'K0', 'K1'],
- 'A': ['A0', 'A1', 'A2', 'A3'],
- 'B': ['B0', 'B1', 'B2', 'B3']})
- right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],
- 'key2': ['K0', 'K0', 'K0', 'K0'],
- 'C': ['C0', 'C1', 'C2', 'C3'],
- 'D': ['D0', 'D1', 'D2', 'D3']})
- res = pd.merge(left, right, on=['key1', 'key2'], how='inner')
- print(res)
- res = pd.merge(left, right, on=['key1', 'key2'], how='outer')
- print(res)
- res = pd.merge(left, right, on=['key1', 'key2'], how='left')
- print(res)
- res = pd.merge(left, right, on=['key1', 'key2'], how='right')
- print(res)
都试一试然后输出就知道是如何操作的了。
上面讲的是以列索引为标准进行合并,当然,我们还可以以index为标准进行合并
- left = pd.DataFrame({'A': ['A0', 'A1', 'A2'],
- 'B': ['B0', 'B1', 'B2']},
- index=['K0', 'K1', 'K2'])
- right = pd.DataFrame({'C': ['C0', 'C2', 'C3'],
- 'D': ['D0', 'D2', 'D3']},
- index=['K0', 'K2', 'K3'])
- res = pd.merge(left, right, left_index=True, right_index=True, how='outer')
- print(res)
- res = pd.merge(left, right, left_index=True, right_index=True, how='inner')
- print(res)
聚合和分组
pandas提供了一个灵活高效的groupby功能,它使你能以一种自然的方式对数据集进行切片、切块、摘要等操作。根据一个或多个键(可以是函数、数组或DataFrame列名)拆分pandas对象。计算分组摘要统计,如计数、平均值、标准差,或用户自定义函数。
根据列索引分组
- df = pd.DataFrame({'key1':['a', 'a', 'b', 'b', 'a'],
- 'key2':['one', 'two', 'one', 'two', 'one'],
- 'data1':np.random.randn(5),
- 'data2':np.random.randn(5)})
- df['data1'].groupby(df['key1']).mean()
这里我们按照key1将数据分组,然后计算分组后的data1的平均值。
我们也可以一次传入多个数组
- df['data1'].groupby([df['key1'], df['key2']]).mean()
此外,还可以将列名用作分组
- df.groupby('key1').mean()
- df.groupby(['key1', 'key2']).mean()
注:这里在执行df.groupby('key1').mean()时,结果中没有key2列。这是因为df['key2']不是数值数据,所以被从结果中排除了。默认情况下,所有数值列都会被聚合,虽然有时可能会被过滤为一个子集。
分组后可进行迭代
- for name, group in df.groupby('key1'):
- print(name)
- print(group)
对于多重键的情况
- for (k1, k2), group in df.groupby(['key1', 'key2']):
- print (k1, k2)
- print (group)
上面进行的group操作返回的类型都是Series,如果我们想返回DataFrame类型的结果,那么我们可以进行如下操作
- df[['data2']].groupby([df['key1']])
根据行类型进行分组
groupby默认是在axis=0上进行分组的,通过设置也可以在其他任何轴上进行分组。拿上面例子中的df来说,我们可以根据行类型(dtype)对列进行分组
- dict(list(df.groupby(df.dtypes,axis = 1)))
这方面还有蛮多内容,不过都还没接触过,只能暂时讲到这里了,如果要了解更多,可以访问这篇博客 ,我在后面也会逐渐完善这些方面的内容。
结尾
讲了这么多,相信你对pandas肯定有了一定的了解了,但由于个人接触不多,就暂时介绍到这里,pandas还有很多内容如数据透视表、多层索引的使用、数据清洗等,将在后面学到时再做补充
学机器学习,不会数据处理怎么行?—— 二、Pandas详解的更多相关文章
- 详解C#泛型(二) 获取C#中方法的执行时间及其代码注入 详解C#泛型(一) 详解C#委托和事件(二) 详解C#特性和反射(四) 记一次.net core调用SOAP接口遇到的问题 C# WebRequest.Create 锚点“#”字符问题 根据内容来产生一个二维码
详解C#泛型(二) 一.自定义泛型方法(Generic Method),将类型参数用作参数列表或返回值的类型: void MyFunc<T>() //声明具有一个类型参数的泛型方法 { ...
- Hexo系列(二) 配置文件详解
Hexo 是一款优秀的博客框架,在使用 Hexo 搭建一个属于自己的博客网站后,我们还需要对其进行配置,使得 Hexo 更能满足自己的需求 这里所说的配置文件,是位于站点根目录下的 _config.y ...
- ViewPager 详解(二)---详解四大函数
前言:上篇中我们讲解了如何快速实现了一个滑动页面,但问题在于,PageAdapter必须要重写的四个函数,它们都各有什么意义,在上节的函数内部为什么要这么实现,下面我们就结合Android的API说明 ...
- iOS 开发之照片框架详解之二 —— PhotoKit 详解(下)
本文链接:http://kayosite.com/ios-development-and-detail-of-photo-framework-part-three.html 这里接着前文<iOS ...
- iOS 开发之照片框架详解之二 —— PhotoKit 详解(上)
转载自:http://kayosite.com/ios-development-and-detail-of-photo-framework-part-two.html 一. 概况 本文接着 iOS 开 ...
- 【模型推理】量化实现分享二:详解 KL 对称量化算法实现
欢迎关注我的公众号 [极智视界],回复001获取Google编程规范 O_o >_< o_O O_o ~_~ o_O 大家好,我是极智视界,本文剖析一下 K ...
- Redis进阶实践之十四 Redis-cli命令行工具使用详解第一部分
一.介绍 redis学了有一段时间了,以前都是看视频,看教程,很少看官方的东西.现在redis的东西要看的都差不多看完了.网上的东西也不多了.剩下来就看看官网的东西吧,一遍翻译,一遍测试. ...
- Redis进阶实践之十四 Redis-cli命令行工具使用详解
转载来源:http://www.cnblogs.com/PatrickLiu/p/8508975.html 一.介绍 redis学了有一段时间了,以前都是看视频,看教程,很少看官方的东西.现在redi ...
- 【和我一起学python吧】Python安装、配置图文详解
Python安装.配置图文详解 目录: 一. Python简介 二. 安装python 1. 在windows下安装 2. 在Linux下安装 三. 在windows下配置python集成开发环境( ...
随机推荐
- redis实现消息队列&发布/订阅模式使用
在项目中用到了redis作为缓存,再学习了ActiveMq之后想着用redis实现简单的消息队列,下面做记录. Redis的列表类型键可以用来实现队列,并且支持阻塞式读取,可以很容易的实现一个高性 ...
- oracle新建对象 权限管理
代码 CREATE USER target IDENTIFIED BY target ; GRANT CONNECT, RESOURCE TO target; 刚刚创建的oracle实例中会内建两个用 ...
- ODPS
ODPS 功能之概述篇 原文 http://blog.aliyun.com/2962 主题 SQL 概述 ODPS是阿里云基于自有的云计算技术研发一套开放数据处理服务(Open Data Proce ...
- 北洋UAM-05LX(网口系列适用)ROS节点
参考创客智造ROS与激光雷达入门教程 说明: 介绍ROS如何接入Hokuyo网口的雷达及基本使用 测试雷达:UAM-05LX采用太网接口,如果型号是USB口的参考教程 ros wiki: http:/ ...
- LOJ 3093: 洛谷 P5323: 「BJOI2019」光线
题目传送门:LOJ #3093. 题意简述: 有 \(n\) 面玻璃,第 \(i\) 面的透光率为 \(a\),反射率为 \(b\). 问把这 \(n\) 面玻璃按顺序叠在一起后,\(n\) 层玻璃的 ...
- 如何交叉编译 linux kernel 内核
Compilation We first need to move the config file by running cp arch/arm/configs/bcmrpi_cutdown_defc ...
- art 校准时设备端操作
(1)准备所需文件art.ko 和 nart.out (2)配置设备的IP地址(例如:192.168.2.122),使之能与本地PC通信 (3)上传文件到设备 cd /tmp tftp -g -r ...
- Centos6.5使用ELK(Elasticsearch + Logstash + Kibana) 搭建日志集中分析平台实践
Centos6.5安装Logstash ELK stack 日志管理系统 概述: 日志主要包括系统日志.应用程序日志和安全日志.系统运维和开发人员可以通过日志了解服务器软硬件信息.检查配置过程中的 ...
- Android数据存储:SQLite
Android数据存储之SQLite SQLite:Android提供的一个标准的数据库,支持SQL语句.用来处理数据量较大的数据.△ SQLite特征:1.轻量性2.独立性3.隔离性4.跨平台性5. ...
- 同时装了Python3和Python2,怎么用pip
作者:匿名用户链接:https://www.zhihu.com/question/21653286/answer/95532074来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注 ...