- 1.本系列基于新生大学课程《Python编程&数据科学入门》和公开的参考资料;
- 2.文章例子基于python3.6,使用Windows系统(除了安装,其余基本没有影响);
- 3.我是纯小白,所以,错误在所难免,体系会逐渐成熟,我会经常进行更新;如果您发现了错误,也烦请帮我指出来,在此先谢过了。
到了这一次课,python课程就进行了一半了。不知你跟上了没有?这一课讲的是python的一个重要组成部分——padas,这一次课解决我一些很长时间的疑惑,能做出初步的产品了,一起来看看吧。
padas的作者是Wes Mckinney,他创建了pandas项目,在离职的时候顺利说服老板将这个非常有用的包进行了开源,他本人也是《利用Python进行数据分析》的作者,而这本书正是这次培训唯一推荐购买的教程。
padas是panel data的意思,也就是多维结构化数据。根据课程安排,这一节课讲入门,下一次课讲进阶。
今天讲课的内容主要有五个部分:
- Series
- DataFrame
- 索引对象
- pandas的数据选择
- 案例讲解(鸢尾花数据)
一、Series
padas数据结构主要有两种:Series和DataFrame。另外,它们的索引与其他的类型不太一样,也是一种对象,拿出来单独讲讲。
series在英文中的意思是系列的意思。这是一种类似与一元数组的结构,注意,用做结构,它的名称是要大写的。
比如,我们下面就是一个Series:
0 4
1 5
2 9
3 9
它的组成和一维数组也是一样的,由一组数据和一组数据标签(索引)组成。
两者的区别在于,一维数组的索引只能是从0开始的整数,而Series的索引可以自己定义。
和Numpy一样,在使用padas之前,也要引入padas包。
from padas import Series, Dataframe
import padas as pd
因为Series和DataFrame使用的次数非常多,所以把它引入本地命名空间。
1.创建Series的方法有三种
- 用Series函数赋值
比如:
ser_1 = Series([4,5,9,9])
ser_1
输出的就是上面的那个Series
0 4
1 5
2 9
3 9
dtype: int64
最后把数据的格式也显示出来了。这个Series的索引是默认的,也就是从0到3。
- 在赋值的同时,定义索引的值
ser_2 = Series([5,6,7,8],index= ['a','b','c','d'])
ser_2
输出:
a 5
b 6
c 7
d 8
dtype: int64
索引被重新定义了。
这时,可以用这个索引来获取这个Series的值了。
ser_2['b']
out:6
ser_2[['a','d']]
输出:
a 5
d 8
dtype: int64
注意:
1.第二个操作是一个切片操作,需要用两个中括号。
2.虽然重新定义了索引,之前的0-3默认索引仍然是有效的。比如:
ser_2[2]
仍然输出正确的值:
6
- 用字典给Series赋值
这种方法把Series当做一个有序的字典。比如:
sdata = {'Monday':7, 'Tuesday':6, 'Wedsday':6, 'Thursday':7, 'Friday':5, 'Saturday':2 }
ser_3 = Series(sdata)
ser_3
输出:
Friday 5
Monday 7
Saturday 2
Thursday 7
Tuesday 6
Wedsday 6
dtype: int64
2.Series的属性
查看Series属性有values、index、name,分别代表值、索引和名字。
前面两者都好理解:
ser_3.values
ser_3.index
分别输出:
array([5, 7, 2, 7, 6, 6], dtype=int64
Index(['Friday', 'Monday', 'Saturday', 'Thursday', 'Tuesday', 'Wedsday'], dtype='object')
大家可以看到,Series的值是一个数组对象,而其索引是一个Index对象,在后面我们会讲到。这两者都有类型,前者是64位整数型,而索引是字符型。
索引可以通过赋值的形式进行修改:
ser_3.index = ['Mon','Tue','Wed','Thu','Fri','Sat']
ser_3
索引就改变了:
Mon 5
Tue 7
Wed 2
Thu 7
Fri 6
Sat 6
Name: hours, dtype: int64
需要注意的是:Index只能整体被修改,它不支持单个索引的修改。
name属性可以定义,也可以没有。
当没有定义的时候,输出就为空。
ser_3.name = 'hours'
ser_3.name
这时才会有输出:'hour'
二、DataFrame
这种数据类型是一种表格型的数据结构。可以把它理解为多个Series的组成的字典,它们共用一个索引。里面的内容可以是不同的类型。
1.创建DataFrame
- 用的最多的方法是用DataFrame函数直接传入一个等长的列表或Numpy数组组成的字典。
fdata = {'country':['United Satets', 'China', 'Japan', 'Germany', 'United Kingdom'],
'capital':['Washington', 'Beijing', 'Tokoy', 'Berlin', 'London'],
"population":[323, 1389, 127, 83, 66],
"gdp":[19.42, 11.8, 4.84, 3.42, 2.5],
"continent":["North America", "Asia", "Asia", "Europe", "Europe"]}
fram_1 = DataFrame(fdata)
会输出一个表格型的文件
字典的key就是每一列的索引。它的排序是按照字母排序的,如果你想要按照自己指定的顺序排列,可以用columns参数让它们重新排序。
DataFrame(fram_1,columnms = ['country', 'capital', 'population', 'gdp', 'continent'])
列就按照我们指定的顺序排列好了。
与Series一样,它也有一个默认的索引。与Series一样,我们也可以通过给其增加行标签(行索引)。
fram_2 = DataFrame(fdata, columns = ['country', 'capital', 'population','gdp', 'continent'], index = ['us', 'cn', 'jp', 'gm', 'uk'])
fram_2
2.从DataFrame获取一个Series
可以把Series视为DataFrame的子集,所以可以从DataFrame中获取一个Series
- 获取一列的Series
通过索引和属性的方式,可以将DataFrame的列获取为一个Series
比如:
fram_2['country']
fram_2.capital
分别得到的是两个Series:
注意两点:
1.返回的Series拥有原来DataFrame相同的索引。
2.DataFrame原来的列索引(columns)没有了,但增加了一个name属性。
- 获取一行的Series
采用索引字段ix的方式,后面马上会讲到。
fram_2.ix['cn']
因为Index对象之前没有被引用,所以用增加一个说明。
修改和增加DataFrame的值
- 增加一列:与赋值操作是一样的
fram_2['ar'] = (100,200,300,400,500)
fram_2['ka'] = 10
fram_2[]
- 第二种方法可以用Series给表格赋一个新列
赋值的过程会精确匹配DataFrame的索引,如果没有的话就会被填上缺失值
ser_4 = Series(['North Kereo', "Pingrang", 'Asia'],index = ['country','capital','continent'])
fram_2['nk'] = ser_4
fram_2
- 还可以用条件表达式给一个新列赋值
fram_2['eastern'] = fram_2.continent == 'Asia'
fram_2
- 用del可以删除一个列
del fram_2['eastern']
fram_2
- 用.drop()方法删除行
data = fram_2.drop([0,1])
删掉了第一和第二行,但fram_2这个DataFrame并没有变化。只有被赋值的data是去掉了第一和第二行。
fram_2.drop(fram_2.index[[0,1]],inplace=True)
这样来做,两行才在原来的DataFrame里同时被删除掉了。
修改行和列的标签(索引)
- 修改行标签
fram_2.index
Index(['us', 'cn', 'jp', 'gm', 'uk'], dtype='object')
这是原来的索引。
我们给变量赋一个新的行索引:
fram_2.index = ('US', 'CN', 'JP', 'GM', 'UK')
fram_2.index
Index(['US', 'CN', 'JP', 'GM', 'UK'], dtype='object')
标签已经被修改为大写的了。
行标签只能整体进行赋值,不能单个修改。这与Series是一样的。
- 修改列标签
fram_2.columns
Index(['country', 'capital', 'population', 'gdp', 'continent', 'ar', 'ka',
'nk', 'attr'],
dtype='object')
得到列的标签。将它的首字母全部改为大写:
fram_2.columns = ('Country', 'Capital', 'Population', 'Gdp', 'Continent', 'Ar', 'Ka',
'Nk', 'Attr')
Index(['Country', 'Capital', 'Population', 'Gdp', 'Continent', 'Ar', 'Ka',
'Nk', 'Attr'],
dtype='object')
三、索引对象
前面多次提到,Series和DataFrame的索引比较特殊,它们只能被整体替换,单个不能被修改。
这个对象的名称是Index,它是不可修改的(immutable)。这个不可修改非常重要,保证了index的对象能够在多个数据结构之间安全的共享。
所以,也可以把Index理解为一个一维数组。
index = fram_2.index
index
输出:
Index(['US', 'CN', 'JP', 'GM', 'UK'], dtype='object')
索引对象也可以进行索引和切片:
index[2]取到的是‘JP'
index[0:2]取到的是标签的第一个第二个值。
四、pandas的数据选择
1.对Series的索引和切片
Series 的索引类似于Numpy数组的索引,只是Series的索引可以自行进行定义。
我们先从fram_2中选取一个Series:
fram_3 = fram_2['Gdp']
fram_3
US 19.42
CN 11.80
JP 4.84
GM 3.42
UK 2.50
Name: Gdp, dtype: float64
fram_3['CN']
输出中国的GDP:11.800000000000001
用默认的索引同样也可以得到相同的结果:
fram_3[1]
切片操作也是类似的方法。
fram_3['CN':'UK']
fram_3[1:]
上面这两个命令得到的结果是一样的:
CN 11.80
JP 4.84
GM 3.42
UK 2.50
Name: Gdp, dtype: float64
注意:利用标签的切片的末端(end)是包含的。
fram_3[1:3]
fram_3['CN':'GM']
这两个命令所选取的数据并不一致。
前者不包含索引末端的值,而后一个命令是包含的。
2.对DataFrame索引和切片
要注意,对DataFrame的索引选取的是列,而切片选取的是行。
- 用DataFrame索引选取一个或多个列
比如:
fram_2['Population']
选择的就是面积这一列。输出的结果是:
US 323
CN 1389
JP 127
GM 83
UK 66
Name: Population, dtype: int64
得到的是一个Series数据。
通过索引,也可以选取多个列:
fram_2[['Gdp', 'Ar']]
注意:选多个列必须用两个方括号;而且这种方法得到的仍是一个DataFrame。
type(fram_2[['Gdp', 'Ar']])
得到它的格式为:
pandas.core.frame.DataFrame
是一个DataFrame。
- Dataframe的切片可以选取行数据
fram_2[:]
这种方法是选取所有的行。输出整个DataFrame:
选取一个或多个行,就是采用切片方式:
fram_2[1:3]
选择的就是第一列:
3.用布尔型数组选取DataFrame的行
就是将条件换成一个条件表达式,比如:
fram_2[fram_2['Ar'] > 200]
将Ar列中大于200的所有行选了出来:k//..,m,m
也可以将DataFrame视为一个数组进行处理:
fram_2 >= 10
将所有的值都转换成了数值型:
fram_4 = fram_2[['Ar','Ka','Gdp']]
fram_4
fram_4[fram_4 >=10 ] = 0
fram_4
数值型的数据还可以直接修改值。注意:fram_4这个变量的值都发生了改变。
也可以采用下面这种方式:
fram_2[fram_2.Gdp >= 10]
可以将Gdp大于10的行选取出来
或者用:
fram_2.loc[fram_2.Gdp >= 10]
也是一样的。loc方法后面马上会讲到。
4.可以用变量的属性来选取值
也就是采用句点的方式,比如:
fram_2.Ar
得到一列的数据,得到的也是一个Series:
US 100
CN 200
JP 300
GM 400
UK 500
Name: Ar, dtype: int32
5.用loc和iloc方法
- loc方法可以同时基于行和列选取数据。这种方法和数组的数据选择非常类似:
选择一行:
fram_2.loc['US']
选择多行:
fram_2.loc[['US','JP']]
可以同时选择列数据:
fram_2.loc[['US', 'JP'],['Gdp', 'Population']]
得到的是一列行和列的筛选后的数值。
如果只选择列数据,前面可以写为“:”。比如:
- iloc方法和loc方法类似,只是它使用的是默认的数值索引。
比如,上面也可以采用下面的这样的方式:
fram_2.iloc[[0,2],[3,2]]
结果是一样的:
注意:切片时,.loc()函数终索引的数值是包含在内的,而.iloc()的默认索引是不包含的。
案例讲解
我们通过一个具体的案例把前面的知识用起来。
比如:下面这个数据库。
数据一共5列,分别代表花萼长度、花萼宽度、花瓣长度、花瓣宽度、品种。
它一共有150行数据,每一个品种50行,前面3列数据如下:
5.1,3.5,1.4,0.2,Iris-setosa
4.9,3.0,1.4,0.2,Iris-setosa
4.7,3.2,1.3,0.2,Iris-setosa
如果需要,可以在UCI数据库中下载。
第一步:从文件中引入数据
col_names = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width', 'spices']
iris = pd.read_csv('iris.csv', names= col_names)
iris
显示出整个数据列表。因为数据非常大,显示了部分数据。
- 要显示前面的部分数据,可以使用.head()函数。
iris.head()
默认是5行数据,可以在括号内修改想要显示的行数。比如改为10:
iris.head(10)
就把前面的10行(数值索引0-9行)数据显示了出来。
- 也可以通过.tail()函数来显示最后的行数
默认的行数和使用方法也是一样的。
iris.head()
显示如下:
- 要了解整体的情况,可以使用.info()函数。
iris.info()
显示出整体的情况:
将表格类型、表格的行数、列数、各列数值的类型(其中多少非空的值、浮点型、字符型)、占用内存空间的大小。
- 用shape函数显示变量的形状
iris.shape
得到它的形状是一个列表:
(150, 5)
也就是150行、5列。
- 用.unique()函数来显示某一列的唯一值的数量
iris.spices.unique()
显示的是唯一的种类:
array(['Iris-setosa', 'Iris-versicolor', 'Iris-virginica'], dtype=object)
得到的是一个numpy数组的形式。
- 用.value_counts()函数来计算每一个唯一值的数量
iris.spices.value_counts()
得到如下值:
Iris-virginica 50
Iris-setosa 50
Iris-versicolor 50
Name: spices, dtype: int64
这种方法可以用来统计频率。
一个案例
鸢尾花数据分析是在大数据和机器学习领域经常采用的一个经典的数据集。
这个数据集是用来记录三种鸢尾花的花萼、花瓣的长度和宽度。
1.导入文件和检视数据
在分析之前,我们先把这个数据文件放在和py程序同一个目录下。而后导入这个文件:
col_names = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width', 'spices']
iris = pd.read_csv('iris.csv', names= col_names)
iris
导出的文件如下:
显示过多,系统自动将中间的内容进行了折叠。
- 我们可以使用.head()和.tail()方法显示前面和后面的若干行数据。
比如:
iris.head(10)
显示前面10行数据,如果括号内不填写的话,默认显示5行数据。
用iris.tail()来显示最后的5行数据。
- 用.info()方法来显示这个DataFrame的基本信息
iris有5个变量,150行数据,5个变量的类型有4个是float64型,1个字符型。
- 用.shape属性来查看iris的形状
输出为(150,50)
- 可以用unique()方法来查看某个变量的唯一值
比如:
iris.spices.unique()
得到如下结果:
array(['Iris-setosa', 'Iris-versicolor', 'Iris-virginica'], dtype=object)
一共3个结果,分别是3种鸢尾花的类型。
- 用.value_count方法可以统计各个唯一值的数量
iris.spices.value_counts()
得到详细的统计值:
Iris-virginica 50
Iris-setosa 50
Iris-versicolor 50
Name: spices, dtype: int64
2.选取数据
1)如果要选取花瓣的长度和宽度,也就是第2列和第3列。可以有三种方法:
- 第一种:索引值法
iris[['petal_width','petal_length']]
- 第二种:loc方法
iris.loc[:,['petal_width','petal_length']]
- 第三种:iloc方法
iris.iloc[:, [2,3]]
2)选取第6-第10列的内容。也有三种方法:
- 第一种:默认索引法
iris[6:11]
- 第二种:loc方法
iris.iloc[6:10,:]
- 第三种:iloc方法
iris.iloc[6:11,:]
3)选取品种是 Iris-versicolor 的数据。
使用布尔表达式:
iris[iris.spices == 'Iris-versicolor']
3.散点图
通过图形化,能够快速得出数据之间的相关关系。
在python中使用散点图之前,首先要进行简单的设置(使用%魔术关键字):
# 在Python中直接输出图形
%matplotlib inline
# 设置图形的清晰度
%config InlineBackend.figure_format = 'retina'
设置散点图的基本设置如下:
iris.plot(kind = 'scatter', x = 'sepal_length', y = 'sepal_width')
scatter代表散点图,x轴和y轴的值需要定义好。得到下面这张图:
我们可以将三个品种的散点图都画出来。
setosa = iris[iris.spices == 'Iris-setosa']
versicolor = iris[iris.spices == 'Iris-versicolor']
virginica = iris[iris.spices == 'Iris-virginica']
ax = setosa.plot(kind='scatter', x= 'sepal_length', y = 'sepal_width', label = 'Iris-setosa', color = 'Blue', figsize=(10,6))
versicolor.plot(kind = 'scatter', x= 'sepal_length', y = 'sepal_width', label= 'Iris-versicolor', color = 'Green', ax=ax)
virginica.plot(kind = 'scatter', x = 'sepal_length', y = 'sepal_width', label = 'Iris-virginica', color = 'Red', ax= ax)
得到下面的图形:
label是图形里的说明标签,color是散点的颜色。
4.箱图
这是计算一系列数据的统计值的方法。
- 我们可以用.describe()方法来查看能够统计的一些类型:
iris.describe()
得到下面这张表:
- 我们来画一个箱图,基本的语法与散点图类似:
iris.petal_length.plot(kind = 'box')
结果如下:
- 下面,我们来把三个品种的箱图放在一起。
iris[['petal_width', 'species']].boxplot(grid=False, by='species', figsize=(10, 6))
grid代表是否需要线段分隔,by之后的参数是根据这一列的分类数值进行分组,figsize是图形的大小。
知识本身不是力量,“知识+持续的行动”才是!
我是陶肚,每天陪你读点书。如果喜欢,请帮忙点赞或分享出去。
网友评论