对于生成的dDataFrame,下一步进行的是对他的基本操作,增、减、改、查。
一. 数据选取
从已有的DataFrame中取出其中一列或几列,并对其进行操作。
Pandas取出DataFrame的列有两种方式,两个方式没有好与坏之分,还是看个人喜欢用哪个
#-*- coding:utf-8 -*-
import pandas as pd
df = pd.DataFrame({'goods':['coke cola', 'eggplant','condom'], 'quantity':[12,3,1], 'price':[20,12,80]})
df['goods'] #选择df的goods这一列
df.goods #同上,是选择列的第二种方法 需要注意的是,第一种方法看似像是一种列表形式,但是如果像是如下方式书写代码会报错
df['goods','quantity'] #会报错,不要妄想通过这种方式获取多列。 上方的形式会引发一个KeyError的错误。如果想通过第一种形式获取多列,正确的形式如下
df[['goods','quantity']] 将多列的列名按照一个list的形式传入,就可以获取一个DataFrame的多列。
二. 数据筛选
往往选取出几个DataFrame的列并不能满足筛选,DataFrame的筛选的形式比较特殊,对列进行筛选时用到的是之前所讲的第二种选取列的形式,有点像是把列名视为一个DataFrame的属性。
#-*- coding:utf-8 -*-
import pandas as pd
df = pd.DataFrame({'goods':['coke cola', 'eggplant','condom'], 'quantity':[12,3,1], 'price':[20,12,80]})
print df[df.goods =='eggplant'] # goods price quantity
# 1 eggplant 12 3 上面代码的意思是选取DataFrame中,goods列的值为'eggplant‘的所有行。DataFrame中也支持多条件筛选,与Python的判断语句相同,and、or、not 和 xor分别代表 和、或、非、抑或。也可以用符号代替 &、|、~、^。每个判断条件要用圆括号括起来,否则会报错
df[(df.goods =='eggplant') & (df.quantity == 12)] 选取df中 goods列值为 eggplant且 对应的 quantity值为12的所有列。
在筛选数据时候也可以使用loc和iloc函数实现子集的选取,意思并不是说上方的筛选语句不对,亲测同样很好用,而且代码简单了点。loc和iloc进行数据筛选的格式如下:
df = df.loc[df.goods=='eggplant', :].loc[]相当于是把想要筛选的列通过 ':'全部选出来。loc方法同样支持多条件筛选。
df = df.loc[(df.goods =='eggplant') & (df.quantity == 12), :] loc形式的多条件筛选,条件与条件之间同样要使用括号分割开。这两行loc方法筛选的结果与之前没用loc方法写的代码效果是一样的,格式规范而言肯定是有loc的更容易让人理解。但是如果只是给自己写脚本完全可以用前一种,必要时候做个注释即可。
条件筛选的另一种形式,就是选取一个DataFrame中满足条件的行的某几列(并不是全部列)。此时只需将上面的代码做一小点改变即可。
df = df.loc[(df.goods =='eggplant') & (df.quantity == 12), ['goods', 'price']] 此时亲测使用loc方式会比较好一些,因为之前loc形式后方的 ':' 代表的是满足条件的全部行的所有列的数据,一个冒号囊括了所有列。此时要是指定其中的某几列,通过list的形式,list的元素是DataFrame的列名,元素类型是字符串。上方的代码所表达的是满足条件的所有行的 goods 和 price 两列。
三. 数据的修改
数据的修改往往有这几种形式 ① 针对某个值或者某个范围的值的修改。 ② 增加列、删除列 ③ 增加行、删除行 ④修改索引 ⑤修改列名
数据值的修改常见于分类的问题中,比如将一个列作为分类的列,有时候往往该列的值不是想要的数字表示的不同分类,或者更复杂是一个连续变量,此时针对DataFrame的修改就格外重要。
添加列
df['price'][df.price > 15] = 'expensive' 通过这一行代码,就将df的 price 一列的大于15的商品定义为 ‘expensive’。分类问题中不同的类常常用不同的数字来表示,而不同类之间的转换需要的就是这样的筛选与修改。
增加列的方法很简单,而且很常用,比如想要在之前的df中添加一个叫‘remain’的列,记录是否有货,可以直接使用下面的代码:
df['remain'] = 'yes'这样就在之前的df后面又加了一列‘remain’,但是这一整列的值为‘yes’。如果不想在末尾加列,而是想在某列之间添加一列,那么就需要使用insert方法。
df.insert(int=0, column = 'remain', value='yes') int参数传入的是一个整数,这个整数是插入列所在的位置,0代表列的索引为0的位置,也就是第一列。 column参数是设置列名。 value值是给这列赋值,可以是字符串,如果是字符串,那么这一列的值都会是这个字符串;也可以是Pandas的Series,或者是Python的list。这样可以使得这一整列不是同一个值。
删除列
列的删除使用Pandas模块中的drop()方法最为高效。假如要删除刚才添加的remain列。
df.drop(labels='remain', axis=1, inplace=True)上方这行代码会成功删除DataFrame中的‘remain’列,注意:如果inplace参数不指定为True,只会在内部删除,df并不会被真正改变。axis参数默认是0,也就是代表着行,所以删除列时要把axis改为1。
如果想删除df中多个列,drop()方法也是可以的。
df.drop(labels=['remain', 'quantity'], axis=1, inplace=True)将想删除的多个列名以Python的列表形式传给labels参数,就可以在该数据框中删除列表中的列。
添加行
Pandas的添加行方式有很多种不过最为直观的方式是这样的
df.loc[3]={'goods':'shampoo','quantity':13, 'price':50} loc又出现,在索引为3的行(第四行)插入一组数据。数据的形式按照字典的形式传入。还有一种方法是通过append方法。
df = df.append({'goods':'shampoo','quantity':13, 'price':50}, ignore_index=True) 也是使用dict形式传入。
删除行
df.drop(labels = 1, axis=0,inplace = True)删除索引为1的行,axis=0表示横向删除行。删除多行时,传入labels的参数是一个list,元素是列的索引值。
df.drop(labels = [1, 4, 6], axis=0,inplace = True)删除df中的索引为1,4,6的行。
修改索引
修改索引有两种情况,改变索引和不改变索引。
① 不改变索引,可以看做是将原始数据按照索引顺序排序
df.sort_index(axis=1,ascending=False) axis表示所有列都随着索引一起变位置,ascending是降序的意思,默认是False。
② 改变索引
set_index()方法
df.set_index(keys='goods',inplace=True) 将df的goods这一列设置成索引,在原数据框中改。这个方法感觉更适合之前没有索引的情况下。当之前设置了索引的情况下需要的是reindex方法。
df.reindex(new_index,axis=0)
new_index可以是Python列表,元素是现在已有的索引的一部分值,这个方法常常用于保留想留下的行。
修改列名
修改列名需要用到的是rename()方法。
dynamic_RNApol.rename(columns={'d0': 'rnapol_d0', 'd1': 'rnapol_d1', 'd3': 'rnapol_d3', 'd5': 'rnapol_d5', 'd7': 'rnapol_d7','d11': 'rnapol_d11', 'd15': 'rnapol_d15', 'd18': 'rnapol_d18', 'ipsc': 'rnapol_ipsc'}, inplace=True)
数据类型转化
dataframe中的astype()方法是对数据类型进行转换的函数。以一个例子进行说明
df = pd.DataFrame({'id': range(4), 'age': ['13', '34', '23'], 'weight': ['45.7', '60.9', '55.5']})
df.dtypes dtype的结果会显示出,id列的数据类型是 int, 而age和weight列的数据类型都是 object。现在将age转化为 int类型,weight转化为float类型。此时astype函数的作用就有所体现。
df.astype({'age':'int', 'weight':'float'})
valid['distance'] = valid['distance'].astype('int')
通过字典的形式传入,将两列转换成了想要的数据类型。
数据排序
dataframe中索引排序用到的是sort_index方法,相似的列数值排序运用的是sort_values()方法。
df.sort_values( by=['age'], ascending=False, inplace=True) #只通过age进行排序;升序;如有缺失值放在最后。
df.sort_values(by=['age', 'weight'], ascending=True, inplace=True, na_position='first') #先通过age排序,在其基础上通过weight排序;降序,缺失值放在最前方。 数据的排序在实际问题中很有用,比如找出聚类中得分最高的几个项等等。
数据去重
在dataframe中去除重复,使用drop_duplicates()方法。而只是检查dataframe中是否出现重复有的是duplicated方法,如果只是想检查某列中是否存在重复的值可以通过subset参数将列传入到duplicated()方法中。
df.duplicated() #检查整个dataframe中是否出现重复
df.duplicated(subset='age') #检查age这列是否出现重复数据
df.drop_duplicates() #删除dataframe中的重复 其中,subset参数传入的可以是单一的列名;同时也可以是多个列名组成的list。
四. dataframe基本操作
数据抽样
dataframe的抽样直接使用sample()方法进行,抽样在涉及到统计学算法的时候很有用,所以先了解一下这个方法的参数。
df.sample(n=5, replace=False)
df.sample(frac=0.2, replace=True) 这两种是最常用的形式,n参数是直接指定抽多少个样本,frac参数则是一个0到1之间的浮点数,指定的是抽取的样本占多大比例。replace表示是否是有放回的抽取,默认是FALSE。weight参数在这里没体现,这个参数是当样本具有权重时候所用的,weight参数后面加的是列名,未赋值则每列的权重默认为0,如果要赋值权重,所有权重的和为1,如果和不为1,则自动进行归一化处理。
频率统计
dataframe中,统计某列不同的值出现的次数使用value_counts()方法。
df = pd.DataFrame({'id': range(4), 'name': ['Jack', 'Craig', 'Chuck', 'Jack'],'gender': ['M', 'M', 'M', 'F'] , 'age': ['13', '34', '23','4'], 'weight': ['45', '60', '55', '30']}) 可以看到上面的dataframe中,name列有重名的,现在要统计不同的名字出现的次数。
df.name.value_counts() 上面的代码反悔的结果是在这个dataframe中,不同的名字出现的次数。
value_counts()方法的一个妙用是用于求占比,假如现在要求的是性别的占比。
df.gender.value_counts()/ sum(df.gender.value_counts) 这行代码返回的是不同性别人数除以总人数所得到的个性别的占比。但是value_counts()方法只能是单变量的计数。如果想设置一个条件后在进行计数,可以使用的是crosstab()方法。
pd.crosstab(index=df.name, columns=df.gender) 这行代码,记录的是不同名字出现的次数,但是将性别分开讨论。columns参数可以传入多个列,传入形式是list,元素是列名。注意:columns传入的列必须是离散型变量,用途是用于分类。
缺失值处理
① 缺失值的检查
检查缺失值所用的函数是isnull(),这看起来和MySQL中的差不多。
print any(df.isnull(), '\n') 检查整个dataframe中是否存在缺失值。
is_null = []
for col in df.columns:
is_null.append(any(pd.isnull(df.col)))
这是检查dataframe每行是否有缺失值。
is_null = []
for index in list(df.index):
is_null.append(any(pd.isnull(df.loc[index, :])))
同理。is_null方法也可以对每列进行缺失值检查。is_null方法返回的是一个布尔值,True表示有缺失值,False表示没有缺失值。
② 缺失值的删除
这是一种比较极端的方法,通过dropna()方法,这个方法的使用有两种形式。
df.dropna('all') 这个是第二种形式,‘all’指明了删除的行是所有值都为缺失值的情况,因为数据中缺失一些数据是很常见的,只删除全部字段都为空的变量才能真正的保留更多的数据。
③ 缺失值的填补
使用fillna()方法可以对dataframe进行缺失值的填补。
df.fillna(0, inplace=True) #最简单的一种方式,缺失值统一以一个值进行填补
df.fillna(value={'id': 0, 'name': 'No', 'gender': 'unknown', 'age':'unknown', 'weight': 0}, inplace=True) #针对不同的列设置不同的缺失填补值
df.fillna(method='ffill', inplace=True) #用上一行的值对自身进行填补
df.fillna(method='bfill', inplace=True) #用后一行的值对自身进行填补
df.fillna({'age': df.age.mean(), 'weight': df.weight.max()}, inplace=True) #用不同列的极值,均值,中位数等进行缺失值填补。
数据映射
看见映射,想到的首先是Python中的map()函数,相比于一般的for循环,map函数具有极高的效率。在日常的Python编程中,map()方法所传入的是一个函数和一个序列,这个函数会相继作用于序列中的每一个元素。得到的是一个新的序列。dataframe也是一个特殊的可遍历序列,但是dataframe的映射所用的是apply()方法。
is_null = []
for index in list(df.index):
is_null.append(any(pd.isnull(df.loc[index])))现在要挑战for循环,将原本的检查每行是否有缺失值的for循环改成apply()形式。
isnull = lambda x : any(pd.isnull(df.loc[x,:]))
is_null = df.apply(func=isnull, axis=1)func参数是所用的方法,这里的方法是之前设定的lambda函数。axis参数0代表映射到各列,而1代表着映射到每行。
numpy的某些方法也能通过apply()形式作用于dataframe上,比如说现在有一个dataframe里面记录的是学生的各科成绩(第一列到第五列),现在要计算每个学生的均分,和每个科目的中位数。
df['average'] = df.iloc[:, 0:5].apply(func=np.mean, axis=1)
df.iloc[:, 0:5].apply(func=np.median, axis=0)