Pandas简介和使用
Pandas是基于NumPy的一个非常好用的库,正如名字一样,人见人爱。之所以如此,就在于不论是读取、处理数据,用它都非常简单。此前有一篇文章《别老扯什么Hadoop了,你的数据根本不够大》指出:只有在超过5TB数据量的规模下,Hadoop才是一个合理的技术选择。相对小一些的数据,我这两天发现使用Python + Pandas处理起来更加敏捷。
安装Pandas非常简单,只需要一行命令(当然你需要先安装pip):
1 | pip install pandas |
Pandas数据读取性能
Pandas提供了IO工具可以将大文件分块读取,测试了一下性能,完整加载9800万条数据也只需要263秒左右,还是相当不错了。
根据测试,对于不同数据量的数据读取时间如下:
1百万条 | 1千万条 | 1亿条 | |
---|---|---|---|
Data | 1s | 17s | 263s |
基本数据结构
Pandas有两种自己独有的基本数据结构。应该注意的是,它固然有着两种数据结构,因为它依然是python的一个库,所以,python中有的数据类型在这里依然适用,也同样还可以使用类自己定义数据类型。只不过,Pandas里面又定义了两种数据类型:Series和DataFrame,它们让数据操作更简单了。
以下操作都是基于:
1 | from pandas import Series, DataFrame |
Series
Series就如同列表一样,是一系列数据,每个数据对应一个索引值。比如这样一个列表:[9, 3, 8],如果跟索引值写到一起,就是:
data | 9 | 3 | 8 |
---|---|---|---|
index | 0 | 1 | 2 |
这种样式我们已经熟悉了,不过,在有些时候,需要把它竖过来表示:
index | data |
---|---|
0 | 9 |
1 | 3 |
2 | 8 |
上面两种,只是表现形式上的差别而已,而Series就是竖起来的list:
1 | 100, "PYTHON", "Soochow", "Qiwsir"]) s = Series([ |
另外一点也很像列表,就是里面的元素的类型,由你任意决定(其实是由需要来决定)。
这里,我们实质上创建了一个Series对象,这个对象当然就有其属性和方法了。比如,下面的两个属性依次可以显示Series对象的数据值和索引:
1 | s.values |
列表的索引只能是从0开始的整数,Series数据类型在默认情况下,其索引也是如此。不过,区别于列表的是,Series可以自定义索引:
1 | 100, "PYTHON", "Soochow", "Qiwsir"], \ s2 = Series([ |
每个元素都有了索引,就可以根据索引操作元素了。类似于list中的操作,根据索引查看其值和修改其值:
1 | "name"] s2[ |
某种程度上,还有些类似dict操作数据;如果对此不太理解,可以看下面的例子。
前面定义Series对象的时候,用的是列表,即Series()方法的参数中,第一个列表就是其数据值,如果需要定义index,放在后面,依然是一个列表。除了这种方法之外,还可以用下面的方法定义Series对象:
1 | "python":8000, "c++":8100, "c":4000} sd = { |
现在是否理解为什么前面那个类似dict了?因为本来就是可以这样定义的。
这时候,索引依然可以自定义。Pandas的优势在这里体现出来,如果自定义了索引,自定的索引会自动寻找原来的索引,如果一样的,就取原来索引对应的值,这个可以简称为“自动对齐”。
1 | "java", "python", "c++", "c"]) s6 = Series(sd, index=[ |
在sd中,只有'python':8000, 'c++':8100, 'c':4000
,没有"java"
,但是在索引参数中有,于是其它能够“自动对齐”的照搬原值,没有的那个"java"
,依然在新Series对象的索引中存在,并且自动为其赋值NaN
。在Pandas中,如果没有值,都对齐赋给NaN
。
1 | pd.isnull(s6) |
此外,Series对象也有同样的方法:
1 | s6.isnull() |
对于Series数据,也可以做类似下面的运算
1 | 3, 9, 4, 7], index=['a', 'b', 'c', 'd']) s3 = Series([ |
DataFrame
DataFrame是一种二维的数据结构,非常接近于电子表格或者类似mysql数据库的形式。它的竖行称之为columns,横行跟前面的Series一样,称之为index,也就是说可以通过columns和index来确定一个主句的位置。
1 | import pandas as pd |
这是定义一个DataFrame对象的常用方法——使用dict定义。字典的“键”(”name”,”marks”,”price”)就是DataFrame的columns的值(名称),字典中每个“键”的“值”是一个列表,它们就是那一竖列中的具体填充数据。上面的定义中没有确定索引,所以,按照惯例(Series中已经形成的惯例)就是从0开始的整数。从上面的结果中很明显表示出来,这就是一个二维的数据结构(类似excel或者mysql中的查看效果)。
上面的数据显示中,columns的顺序没有规定,就如同字典中键的顺序一样,但是在DataFrame中,columns跟字典键相比,有一个明显不同,就是其顺序可以被规定,像下面这样做:
1 | 'name','price','marks']) f2 = DataFrame(data, columns=[ |
跟Series类似的,DataFrame数据的索引也能够自定义。
1 | 'name', 'price', 'marks', 'debt'], index=['a','b','c']) f3 = DataFrame(data, columns=[ |
还要注意观察上面的显示结果。因为在定义f3的时候,columns的参数中,比以往多了一项(‘debt’),但是这项在data这个字典中并没有,所以debt这一竖列的值都是空的,在Pandas中,空就用NaN来代表了。
定义DataFrame的方法,除了上面的之外,还可以使用“字典套字典”的方式。
1 | "lang":{"firstline":"python","secondline":"java"}, "price":{"firstline":8000}} newdata = { |
在字典中就规定好数列名称(第一层键)和每横行索引(第二层字典键)以及对应的数据(第二层字典值),也就是在字典中规定好了每个数据格子中的数据,没有规定的都是空。
1 | "firstline","secondline","thirdline"]) DataFrame(newdata, index=[ |
如果额外确定了索引,就如同上面显示一样,除非在字典中有相应的索引内容,否则都是NaN。
前面定义了DataFrame数据(可以通过两种方法),它也是一种对象类型,比如变量f3引用了一个对象,它的类型是DataFrame。承接以前的思维方法:对象有属性和方法。
1 | f3.columns |
DataFrame对象的columns属性,能够显示现有的columns名称。并且,还能用下面类似字典的方式,得到某竖列的全部内容(当然包含索引):
1 | 'name'] f3[ |
这是什么?这其实就是一个Series,或者说,可以将DataFrame理解为是由一个一个的Series组成的。
对于没有数值的那一列,下面的操作是统一给那一列赋值:
1 | 'debt'] = 89.2 f3[ |
除了能够统一赋值之外,还能够“点对点”添加数值,结合前面的Series,既然DataFrame对象的每竖列都是一个Series对象,那么可以先定义一个Series对象,然后把它放到DataFrame对象中。如下:
1 | 2.2, 3.3], index=["a","c"]) #注意索引 sdebt = Series([ |
将Series对象(sdebt变量所引用) 赋给f3[‘debt’]列,Pandas的一个重要特性——自动对齐——在这里起做用了,在Series中,只有两个索引(”a”,”c”),它们将和DataFrame中的索引自动对齐。于是有:
1 | f3 |
自动对齐之后,没有被复制的依然保持NaN。
Pandas使用
由于篇幅限制,不能讲pandas所有内容完全详尽描述,只是做一个简单的介绍,在实践中使用如果遇到问题,建议参考相关文档或者google来解决(不要用baidu)。
读取csv文件
普通办法读取
最简单、最直接的就是open()打开文件:
1 | with open("./marks.csv") as f: |
此方法可以,但略显麻烦。python中还有一个csv的标准库:
1 | import csv |
从上面结果可以看出,csv模块提供的属性和方法。仅仅就读取本例子中的文件:
1 | import csv |
算是稍有改善。
用Pandas读取
我们来看一下pandas的效果:
1 | import pandas as pd |
以上结果就是一个DataFrame数据对象。
还有另外一种方法:
1 | "./marks.csv", sep=",") pd.read_table( |
如果你有足够的好奇心来研究这个名叫DataFrame的对象,可以这样:
1 | dir(marks) |
一个一个浏览一下,通过名字可以直到那个方法或者属性的大概,然后就可以根据你的喜好和需要,试一试:
1 | marks.index |
下面几个操作,也是常用到的,并且秉承了python的一贯方法:
1 | 1] marks[: |
可以说,当你已经掌握了通过dir()和help()查看对象的方法和属性时,就已经掌握了pandas的用法,其实何止pandas,其它对象都是如此。
一个pandas实例
上周一个朋友提出了一个简单的需求:对于百万条数量级的csv文件做一个简单的数据分析,在此非常感谢他让我有机会接触到了pandas,话不多说,上代码:
1 | import pandas as pd |