DataFrame—数据汇总8

文章最前: 我是Octopus,这个名字来源于我的中文名--章鱼;我热爱编程、热爱算法、热爱开源。所有源码在我的个人github ;这博客是记录我学习的点点滴滴,如果您对 Python、Java、AI、算法有兴趣,可以关注我的动态,一起学习,共同进步。 

#示例数据
df = pd.read_csv("pokemon_data.csv",encoding="gbk")
df.head(10)

一.数据选取

Q1:选取第1行的数据(选取单行数据)

(1)按索引标签选取(loc做法)

df.loc[0]   #返回的是Series
df.loc[[0]]  #如果在里面多加一个方括号,那么返回的是DataFrame

(2)按索引位置选取(iloc做法)

df.iloc[0]      #返回的是Series
df.iloc[[0]]  #如果在里面多加一个方括号,那么返回的是DataFrame

相信你一定会很好奇:为什么在这里loc和iloc得到的结果是一样的?

下面会来解释

Q2:选取第2到第5行的数据(选取连续行的数据)

(1)按索引标签选取(loc做法)

df.loc[1:4]

你可能产生了一个疑问:不是说切片的末端是取不到的吗,也就是4这个索引所指向的第5行应该是取不到的

这是因为loc是按照索引标签来选取数据的,而不是根据位置来选取,举个例子:

#以姓名这一列作为索引列
df_name = df.set_index("姓名")
df_name

如果我要返回第2行到第5行的数据,该怎么做呢?

#如果按照刚刚的写法,就会出错
df_name.loc[1:4]
#因为loc是按照索引标签选取的,按照下面这种写法就对了
df_name.loc["Ivysaur":"Charmander"]

 (2)按索引位置选取(iloc做法)

df.iloc[1:5]

我们需要返回的是第2行到第5行,因此对应的索引位置是1:4,但是由于iloc是按照位置来选取数据的,因此末端索引是取不到的,那么末端就需要再加1,这样就能确保第5行能取到了,而取不到第6行

为了能更直观地体现出loc和iloc的区别,接下来以df_name为示例数据

#示例数据
df_name.head(10)

Q3:选取第2行,第4行,第7行,第10行的数据(选取特定行的数据)

(1)按索引标签选取(loc做法)

df_name.loc[["Ivysaur","VenusaurMega Venusaur","Charizard","Squirtle"]]

(2)按索引位置选取(iloc做法)

df_name.iloc[[1,3,6,9]]

Q4:选取攻击力列(选取单列的数据)

(1)直接方括号+列名

#直接方括号输入列名即可,推荐这种方法
df_name["攻击力"]
#返回的是一个Series
df_name[["攻击力"]]
#返回的是一个DataFrame

(2)按索引标签选取(loc做法)

#虽然用loc也能提取单列,但是显得不够简洁
df_name.loc[:,["攻击力"]]

(3)按索引位置选取(iloc做法)

df_name.iloc[:,[4]]

4)点号选取法

#也可以通过点号选取列
df_name.攻击力

点号提取列的这种方法的优点是:写法比较简洁快速,缺点是如果列名和关键字重复了就无法提取了,因为点号调用的是对象,python无法判断出名字一样的列名和关键字

#新增一列class,值为1
df_name["class"] = 1
df_name

由于class是python的关键字,而点号选取列实质上是在调用对象,本身列名class和关键字class重叠了,导致无法调用成功 

df_name.class

Q5:选取类型1列到攻击力列的所有数据(选取连续列的数据)

(1)按索引标签选取(loc做法)

df_name.loc[:,"类型1":"攻击力"]

 (2)按索引位置选取(iloc做法)

df_name.iloc[:,:5]

Q6:选取“类型2”列,攻击力列,防御力列的所有数据(选取特定列的数据)(

(1)方括号+列名

#用方括号+列名来直接提取,这种方式比较简洁
df_name[["类型2","攻击力","防御力"]]

(2)按索引标签选取(loc做法)

df_name.loc[:,["类型2","攻击力","防御力"]]

(3)按索引位置选取(iloc做法)

df_name.iloc[:,[1,4,5]]

Q7:选取第3行到第8行,类型1列到攻击力列(选取部分行部分列的数据)

(1)按索引标签选取(loc做法)

df_name.head(10)
df_name.loc["Venusaur":"CharizardMega Charizard X","类型1":"攻击力"]

(2)按索引位置选取(iloc做法)

df_name.iloc[2:8,:5]

ix选取数据的做法

#示例数据,在这里索引为整数标签
df_1 = df.head(10)
df_1
#选出第2到第4行的数据
df_1.ix[1:3]
#选出类型1列到攻击力列的数据
df_1.ix[:,"类型1":"攻击力"]
#列也能通过位置选出
df_1.ix[:,1:6]
#选出第2行到第5行,第2列到第4列的数据
df.ix[1:4,"类型1":"总计"]
#或者列是通过位置选出
df.ix[1:4,1:4]
#示例数据,在这里索引为非整数标签
df_2 = df_1.set_index("姓名")
df_2
#选取第2行到第4行的数据
df_2.ix[1:4]
#选取第2列到第5列的数据
df_2.ix[:,1:5]
#选取第2行到第6行,第2列到第5列的数据
df_2.ix[1:6,1:5]
#也可以用索引标签选取
df_2.ix["Ivysaur":"Charmeleon","类型2":"攻击力"]

ix的工作原理:根据索引的类型分2种情况:

1.索引为整数标签,那么按照索引标签选取行数据,不能按照索引位置选取行数据,列数据既能通过标签选取也能通过位置选取。

2.当索引为非整数标签(如字符串标签),那么可以用索引标签选取行数据,也可以按照索引位置选取行数据,列数据既能通过标签选取也能通过位置选取。

用两个例子说明ix的工作原理,并且说明下ix和loc和iloc的区别

例子1,索引为整数标签

df_number = pd.DataFrame({"id":list("abcdefghij"),"score":range(10,20)},index=[27,26,25,24,23,1,2,3,4,5])
df_number

第一种情况,用在索引内的整数标签来测试(例如[:2])

df_number.loc[:2]
#loc按照索引标签选取数据,因此返回了第1行到第7行的数据
df_number.iloc[:2]
#iloc按照索引位置选取数据,因此返回了前2行的数据
df_number.ix[:2]
#返回了第1行到第7行的数据,说明ix是优先按照索引标签选取数据
第二种情况,用不在索引内的整数标签来测试(例如6)
df_number.loc[:6]
df_number.iloc[:6]
#因为是按照位置选取,所以返回了前6行数据
df_number.ix[:6]

第2个例子,索引为非整数标签类型,以字符串标签为例

df_str = df_number.set_index("id")
df_str
df_str.ix[:2]

说明了当标签为字符串标签时,即使:2不在索引标签内,ix也能按照位置选取数据

个人建议:还是使用loc和iloc来选取数据较好,因为分工明确,loc通过索引标签选取数据,iloc通过索引位置选取数据,所以你会很清除地知道你是在索引标签上操作还是在索引位置上操作,不会觉得混乱。我并不是特别建议使用ix,ix会让你觉得很混乱,也会让别人看你的代码时会在想:到底现在是在索引标签上操作还是位置上操作?这就增加了一个判断的过程。

二.数据筛选

#示例数据
df.head()

Q1:选取出攻击力大于100的所有数据

1.loc筛选
df.loc[df["攻击力"] > 100]

2.query筛选

df.query("攻击力 > 100")

Q2:选出攻击力大于100且防御力大于100的数据,并且列只要姓名、攻击力、防御力

1.loc筛选

#做法1
df.loc[df["类型1"] == "Grass"]
df.loc[(df["攻击力"] > 100) & (df["防御力"] > 100),["姓名","攻击力","防御力"]]

2.query筛选

df.query("攻击力 > 100 & 防御力 > 100")[["姓名","攻击力","防御力"]]

但是query的参数中不能引用变量,而loc可以

Q3:选出类型1为Grass的所有数据

1.loc筛选

#做法2
df.loc[df["类型1"].isin(["Grass"])]

2.query筛选

df.query("类型1 == 'Grass'")

三.多重索引

Q1:什么是多重索引

2层或2层以上的索引

为什么会用到多重索引呢?

因为有时候需要通过多个维度来查看数据

Q2:如何创建多重索引

#当我们要以字符串列作为索引列时,要保证这列为字符串格式
df[["类型1","类型2"]] = df[["类型1","类型2"]].astype("str")
#创建一个具有2重索引的数据作示例
df_pokemon = df.set_index(["类型1","类型2"])
df_pokemon

参数介绍

drop:是指该列被指定为索引后,是否删除该列,默认为True,即删除该列。如果改成False,则多重索引在数据集的列中也会保留

append:指定是否保留原索引,默认为False,即不保留,如果改成True,则保留原索引

inplace:指是否在源数据的基础上修改,默认为False,即不修改,返回一个新的数据框,如果改成True,则直接在源数据上修改

level介绍

#获取第一层索引
df_pokemon.index.get_level_values(0)
#获取第二层索引
df_pokemon.index.get_level_values(1)
#交换level
df_pokemon.swaplevel()

Q3:如何通过多重索引选取数据

df_pokemon.head(10)

先对数据源的索引进行升序排序

df_pokemon.sort_index(inplace=True)
df_pokemon

为什么要对索引升序排序?

因为如果没有对索引进行升序排序的话,在多重索引选取数据的过程中无法通过切片选取数据,切片是由小到大取的,例如字符串a→z,数字0→100,所以在对索引进行升序后,才能正确地切片选取数据

接下来根据需求通过多重索引选取数据

#取出第一索引列中值为Bug的所有数据
df_pokemon.loc["Bug"]
#取出第一索引列为Bug,第二索引列为Poison的所有数据
df_pokemon.loc[("Bug","Poison")]
#选出第一索引列为Bug到Grass的所有数据
df_pokemon.loc[slice("Bug","Grass")]
#选出第一索引列为Bug到Grass,且第二索引列为Electric的所有数据
df_pokemon.loc[(slice("Bug","Grass"),"Electric"),:]

 当想要取某一列索引下的全部数据时就需要用slice(None)

#取第二索引列为Electric的所有数据
df_pokemon.loc[(slice(None),"Electric"),:]
#取第二索引列为Electric和Fire,且列为姓名到攻击力的所有数据
df_pokemon.loc[(slice(None),["Electric","Fire"]),"姓名":"攻击力"]

前面的做法有点繁琐,还有更简洁的做法,可以不用去写slice

idx = pd.IndexSlice
#取第二索引列为Electric和Fire,且列为姓名到攻击力的所有数据
df_pokemon.loc[idx[:,["Electric","Fire"]],"姓名":"攻击力"]
#取第二索引为Electric到Fire的所有数据
df_pokemon.loc[idx[:,"Electric":"Fire"],:]
#取第一索引为Bug到Grass,且第二索引为Electric到Fire的所有数据
df_pokemon.loc[idx["Bug":"Grass","Electric":"Fire"],:]
#选取第一索引列即类型1为Bug的所有数据
df_pokemon.xs("Bug",level=0)
#选取第二索引列为Electric的所有数据
df_pokemon.xs("Electric",level=1)
#选取第二索引列为Electric的所有数据,并且保留第二索引列
df_pokemon.xs("Electric",level=1,drop_level=False)
#选取第一索引列为Bug,第二索引列为Electric的所有数据
df_pokemon.xs(("Bug","Electric"),level=(0,1))
#level也可以是索引列名
df_pokemon.xs(("Bug","Electric"),level=(["类型1","类型2"]))

xs在每个索引列上选择的标签只能是一个,所以做不到切片标签的选取

  • 14
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值