所有的数据结构,不同的语言有不同的存在方式,但是原理本质是一样的,了解,语言的自带的数据结构和通过第三方包带有的数据结构,了解数据结构最基本的特性,和最基本的操作,算法就是用这些数据结构和相关的操作去解决特定的问题的方法而已。所以数据就够是基础也是必须掌握的本质。
本文是 《如何七周成为数据分析师》的第二十一篇教程,如果想要了解写作初衷,可以先行阅读七周指南。温馨提示:如果您已经熟悉Python,大可不必再看这篇文章,或只挑选部分。
今天开始进入Python数据分析工具的教程。
数据分析绝对绕不过的三个包是numpy、scipy和pandas。numpy是Python的数值计算扩展,专门用来处理矩阵,它的运算效率比列表更高效。scipy是基于numpy的科学计算包,包括统计、线性代数等工具。pandas是基于numpy的数据分析工具,能更方便的操作大型数据集。后续的章节主要围绕pandas讲解。
numpy和pandas
numpy的数据结构是n维的数组对象,叫做ndarray。Python的list虽然也能表示,但是不高效,随着列表数据的增加,效率会降低。
我们首先载入numpy包,因为它是第三方工具,所以每次使用前必须在代码中载入。as是命名为别名,方便调用,np是numpy约定俗成的简写。
![](https://i-blog.csdnimg.cn/blog_migrate/6fb570e32e3f3e1796114a26b5bc0afe.png)
![](https://i-blog.csdnimg.cn/blog_migrate/750fd7e8a51cf5f6d6f6a219bcfc6071.png)
创建数组使用numpy中的array函数,新手要记住加np。我们将系统自带的列表list转换成了numpy中的数组。
![](https://i-blog.csdnimg.cn/blog_migrate/f4d95eeba45f52accc9558bb6b60a7f1.png)
![](https://i-blog.csdnimg.cn/blog_migrate/b0e4cd11ab0d15cd42eff499eec1e0ba.png)
嵌套列表会被转换为一个多维数组,它也可以被称为矩阵。
array数组需要注意的是,它内部的元素必须为相同类型,比如数值或者字符串。可以用dtype查询其类型,不用加括号。
![](https://i-blog.csdnimg.cn/blog_migrate/ddfbae3b11a3210507517771ff1bb7fe.png)
![](https://i-blog.csdnimg.cn/blog_migrate/93c247b9b5fd6b6cfe713bc1a1e1f076.png)
numpy的数据类型比较丰富,包括int8,int16,int32等,不过这块更接近计算机底层,数据分析用不太到。当我们想转换数据格式时,可以用astype函数。
![](https://i-blog.csdnimg.cn/blog_migrate/a3a6c1fa295f50177790dfe802b37e19.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f8c5dec433f7d62ee72161b73a9217c1.png)
数组的计算非常方便,不要大量的循环即可批量运算。
![](https://i-blog.csdnimg.cn/blog_migrate/d4bde08795259530558d901a52fc8e28.png)
![](https://i-blog.csdnimg.cn/blog_migrate/51acb0186cebe851ac3cf0fb02e327d3.png)
数组索引和列表相同,通过方括号和数字即可选择,也可直接赋值。
![](https://i-blog.csdnimg.cn/blog_migrate/91ea8ff2f9e7650a10e5a26f1536d920.png)
![](https://i-blog.csdnimg.cn/blog_migrate/011ebc232fd06e53e0365d50ac565a12.png)
可以通过递归对多维数组进行筛选,如果省略了后面的索引,则返回次一级的维度,这一点和list一样。
![](https://i-blog.csdnimg.cn/blog_migrate/6c82a328f2eae2eb0de24424199dd4d2.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f28b7f20d223d0f74aa1fe908dfee9b5.png)
numpy除了上述的基础操作之外,还有reshape、T转置、ufunc、sort等函数,功能强大,大家可以自行查阅文档学习,这里我不再花费时间讲解。对于数据分析师,pandas是一个更常用的包,在抽象概念上它更接近我们熟悉的excel和sql,也是最主要的分析工具。
pandas有两个主要的数据结构,Series和DataFrame,记住大小写区分,后续使用中不多提醒。Series类似于一维数组,和numpy的array接近,由一组数据和数据标签组成。数据标签有索引的作用。
![](https://i-blog.csdnimg.cn/blog_migrate/f084ae1eae3c875c7f56f06422168c86.png)
![](https://i-blog.csdnimg.cn/blog_migrate/95cd6279860b55dc994ff0540d6ef1b3.png)
加载pandas包,通过Series函数生成一个对象。我们很明显地看到,在jupyter上它的样式不同于array,它是竖着的。右边是我们输入的一组数据,左边是数据的索引,即标签。数据标签是pandas区分于numpy的重要特征。
索引不一定是从0开始的数字,它可以被定义。
![](https://i-blog.csdnimg.cn/blog_migrate/814518b35add9e911a842fc95e1e2236.png)
![](https://i-blog.csdnimg.cn/blog_migrate/d1bc4b886496a2a7f08979bccdbaf8ff.png)
索引的概念有点像SQL的主键,不过它的功能更强大,分析师能够很轻松的通过索引选取一个数据或者一组数据。
![](https://i-blog.csdnimg.cn/blog_migrate/5d9ea8cfc33ddd52ed0a36eae9f80a8b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2bf9aebc9ee860f2d523780128b5a0ef.png)
index函数可以显示Series的索引。Series和array一样,通过方括号选取数据,当要选取多个数据时,应该用列表表示多个索引,所以第三个案例嵌套了两层方括号。
如果数据是一个字典,也能直接通过这个字典创建Series。
![](https://i-blog.csdnimg.cn/blog_migrate/dc7da8bad1f48d38d2e1155571c4a05f.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6818015b2c2bc272cc94f724472e829c.png)
此时,字典的key就是Series的索引。
![](https://i-blog.csdnimg.cn/blog_migrate/29fec3da64ba46e010e37a7e9fd4504e.png)
![](https://i-blog.csdnimg.cn/blog_migrate/40d19e941cbcdaeb5daf637f325c19f1.png)
Series有自动对齐索引的功能,当自定义的索引qinqin和字典队员不上时,会自动选择NaN,即结果为空,表示缺失。缺失值的处理会在后续讲解。
DataFrame
Series是一维的数据结构,DataFrame是一个表格型的数据结构,它含有不同的列,每列都是不同的数据类型。我们可以把DataFrame看作Series组成的字典,它既有行索引也有列索引。想象得更明白一点,它类似一张excel表格或者SQL,只是功能更强大。
构建DataFrame的方法有很多,最常用的是传入一个字典。
![](https://i-blog.csdnimg.cn/blog_migrate/24e780693ed531f05f7682ae795f8491.png)
![](https://i-blog.csdnimg.cn/blog_migrate/9256e9ada60b2d37cae409b388ff695f.png)
DataFrame会自动补充索引,并且将字典的key作为列标签,即column。在这里,dict的key顺序是DataFame的顺序,不再是无序的。
DataFrame中可以通过info函数直接查看数据类型和统计。
![](https://i-blog.csdnimg.cn/blog_migrate/cf0ac4c7e5f04c9e8b3fe6b144c015fa.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2b69b20bd7d794a7c7afb38d415e84b8.png)
列名后面是列的非空值统计量,以及数据类型,最后一行是DataFrame占用的内存大小,对于pandas来说,千万行几百兆的数据也是不再话下的。
![](https://i-blog.csdnimg.cn/blog_migrate/1d73ee1aebbb73748de4c49d9915864b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/b362a3d5d438f2a5aff20a3544745a53.png)
DataFrame的数据类型变更和numpy一样,用astype就行,记住要赋值。df.age = df.age.astype,图上只是举例,没有真的更改数据类型。
DataFrame的索引方式和Series一样,它选取的是列。
![](https://i-blog.csdnimg.cn/blog_migrate/ecf101706044f57c55f7b726b10c186a.png)
![](https://i-blog.csdnimg.cn/blog_migrate/54941d5c98d5379f675ac8f3e6106f65.png)
返回的是一组Series,索引和原DataFrame一致。除了方括号选取,DataFrame还有更简单的选取方法。
![](https://i-blog.csdnimg.cn/blog_migrate/86dad050d5241d13be373cef9d5e71c6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/c7ee81a3356c8ed272ef6d6ce1242f9f.png)
行也可以通过通过位置获取,用索引字段ix的方式。
![](https://i-blog.csdnimg.cn/blog_migrate/d8f1d2c3efd77714112d47987c674ae8.png)
![](https://i-blog.csdnimg.cn/blog_migrate/aa0c429c27a91292f75916d9ba5fc9bf.png)
第二个方法不需要调用ix,直接以切片的形式获取行,切片的用啊和数组一样。记住,切片无法用单独的数字选取,只能用冒号切选范围。
列可以通过赋值的方式修改和添加,当列的名称是全新,则会在DataFrame的最右边自动加上新的一列。
![](https://i-blog.csdnimg.cn/blog_migrate/0aa2380bc659541064ab373937353a6e.png)
![](https://i-blog.csdnimg.cn/blog_migrate/bb0be6b21c74630d572b5d64c3de6ec7.png)
列表和数组都可以赋值到列,长度必须匹配,列表是按照顺序,数组的话,可以按index参数设置的索引对应,若为空,则填上缺失值。
DataFrame的index不可更改,这是为了数据的安全性,但我们能通过index函数获取详情。
![](https://i-blog.csdnimg.cn/blog_migrate/cbfbba53961a3f8bc9ed8d73afe2feab.png)
![](https://i-blog.csdnimg.cn/blog_migrate/ecc9d397f594a36af1887ced46ecce58.png)
DataFrame在数据选取上面非常强大。
![](https://i-blog.csdnimg.cn/blog_migrate/3b74bc7b6c61f72ec9c34751f8ca50ad.png)
![](https://i-blog.csdnimg.cn/blog_migrate/56fb687de849881d5e46905457286a98.png)
它支持常用的逻辑判断,例子中,后两种数据选取是通过布尔数组过滤出我们想要的结果。
![](https://i-blog.csdnimg.cn/blog_migrate/c686ea40a8373a7cbcee3464a0369f12.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a06df1dcf1f7781f5a0e37b288988be1.png)
df.sex == '男'返回了一个布尔数组(记住,是两个等号,一个等号是赋值),然后通过布尔数组找出df中符合条件为true的结果。
现在我们希望找出年龄在20以下,且性别为男的人。
![](https://i-blog.csdnimg.cn/blog_migrate/f89fc5d4b4a135163cfa059bedacf559.png)
![](https://i-blog.csdnimg.cn/blog_migrate/b4fc73b3c63e041aa024ff27fa92a973.png)
这里用到布尔类型数据的计算公式,true and true 为true,false and true 为false。pandas中的逻辑符号,并且是&,或者是|。接下来过滤出性别为女,或者年龄为18的人。
![](https://i-blog.csdnimg.cn/blog_migrate/6917a1d00a451fc775a1c174eb912dbc.png)
![](https://i-blog.csdnimg.cn/blog_migrate/051cf499a089135edcefed54ec110fd1.png)
当逻辑条件复杂时,这种写法并不优雅,比如性别为男,且年龄在18岁,以及性别为女,且年龄在18岁以上的两类人群,这种过滤条件就比较复杂了。pandas中可以用query函数以类SQL语言执行查询。
![](https://i-blog.csdnimg.cn/blog_migrate/9137114d59c84c13a912f05f3cbed8d7.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e61eb2a59e4b5b52e0a01e7676ab7506.png)
query中可以直接使用列名,它的功能远不至于此,大家有兴趣可以深入学习。
![](https://i-blog.csdnimg.cn/blog_migrate/c9a759a3725d506f1ea5bcdd507cfa65.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2f43427cc4d922c3b7103517f9a04d8b.png)
DataFrame可以直接在列上进行运算,当DataFrame和DataFrame之间运算时,按索引进行加减乘除。
![](https://i-blog.csdnimg.cn/blog_migrate/640cc799b3126a2f8a3b0e703f38f6d3.png)
![](https://i-blog.csdnimg.cn/blog_migrate/748f799f4ba37ee4d69578e736ba699f.png)
如果直接用加法,若列名匹配不上,会产生NaN 的缺失值,我们可以在后续后续fillna函数填充。另外一种方法是add函数,它可以直接通过参数选择填充值。减乘除对应sub、mul、div。
DataFrame还有两个常用函数,又特别容易搞混的是,iloc和loc。
![](https://i-blog.csdnimg.cn/blog_migrate/0085e1d0ee7631e107d026f532220148.png)
![](https://i-blog.csdnimg.cn/blog_migrate/1c7b5571552c1e1154700d9343205e77.png)
它们都是通过索引选取行,iloc是通过所在行的数字为索引,loc是所在行的标签为索引,简单讲,iloc是第几行,loc是标签。当索引没有标签时,loc和iloc等价。两者支持冒号的范围选择。
上文提到的过的ix,则是两者的混合,即可以行号,也可以行索引。
当行和列需要同时选择的时候,用逗号分割,逗号前是想要选择的行,逗号后是想要选择的列。
![](https://i-blog.csdnimg.cn/blog_migrate/d237194ee94f99a3714d47dfea3e5997.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a7bcb290381177be34599c4c7cdffc02.png)
完整形式是ix[ 行1:行2, 列1:列2 ],iloc和loc也支持行列同时选择,方法一样。新人接触这几块比较容易混淆。后续联系即可掌握。
大家如果想加深掌握这块,除了敲一遍代码,可以阅读「利用Python进行数据分析」,很经典的入门书(部分内容有点老)。也可以多拿工作中的报表做练习。
到这里,numpy和pandas的基础就讲解的差不多了,更深入的应用,还是用实战解决吧!下一章,将会用大家已经很熟悉的练习数据,以实际操作的方式完成一次数据分析。
————
欢迎关注我的个人公众号:tracykanc