pandas库的DataFrame,作为一种非常强大的数据处理手段,一直以来无论是从整个库的API设计和性能,都给我非常大的惊喜,但是,在由生疏到慢慢熟练的过程中,发现在利用DataFrame时,一个最大的问题就是,如何高效优雅地选取到自己需要的数据,毕竟大部分时候我们是不需要整个DataFrame中的所有数据的。而为了遵循python语言本身的设计哲学,这些操作几乎都是利用原有的运算符,pandas只是进行了覆写,因而这些技能都像是隐藏的大招,难以发现和掌握,故特意花时间研究了一下官方文档,现总结如下,见笑。

1.属性选取

属性选取,顾名思义,也就是直接使用面向对象思想中对象的属性这一特性,以进行数据的选取,这里我们先创建一个示例的数据

In [1]: import pandas as pd

In [2]: import numpy as np

In [3]: df = pd.DataFrame(np.random.randn(6, 6),

...: index=[1, 2, 'C', 'D', '5', '6'],

...: columns=['A', 'B', '3', '4', 5, 6])

注意,这里我们构建了一个非常特殊的DataFrame,特别是在index和columns这两个参数,我们使用了三种分别明显的index,有int型的,字符串型两种,字符型里面又有数字和字母不一,且两者是没有冲突的,下面会演示这些index和columns都有啥坑(以下可能将index称为行名,columns称为列名)。

正常情况下,使用属性选取方式是非常简单的,直接访问对象属性即可

In [4]: df.A

Out[4]:

1 0.124010

2 -1.520924

C -1.941521

D -0.613758

5 0.788941

6 0.894871

Name: A, dtype: float64

而如果我们访问不存在的列,将会抛出AttributeError异常(为节约篇幅,以下错误演示去除了堆栈信息,仅保留异常信息,下同)

In [5]: df.G

AttributeError: 'DataFrame' object has no attribute 'G'

当然,属性选取有非常大的局限性,首先,这种方法不能选取到行,只能选取到列

In [6]: df.C

AttributeError: 'DataFrame' object has no attribute 'C'

其次就是其对于列名也有非常严格的要求,首先就是如果列名与Dataframe自带的方法、属性名一致的列都不能使用属性选取

In [7]: df.min

Out[7]:

5 6

1 0.124010 -1.160599 -1.236521 -2.356423 0.089117 1.090875

2 -1.520924 -0.285893 0.918261 1.250223 2.028298 -0.007042

C -1.941521 0.716184 0.318086 -0.540593 -2.408134 0.526977

D -0.613758 0.718741 -1.420655 -0.182436 0.333909 -1.608134

5 0.788941 -0.541419 -1.195019 -0.924797 -0.261171 1.078212

6 0.894871 0.454283 -0.763443 0.065712 -0.336119 0.182736>

再次就是由于Python的命名规则,开头是数字的,或者带有其他非法符号的显然也不能使用属性选取

In [8]: df.3

SyntaxError: invalid syntax

最后,由于Python对象的动态特性,如果希望通过属性的方式添加一列,也是错误的

In [9]: df.G = np.arange(6)

In [10]: df

Out[10]:

A B 3 4 5 6

1 0.124010 -1.160599 -1.236521 -2.356423 0.089117 1.090875

2 -1.520924 -0.285893 0.918261 1.250223 2.028298 -0.007042

C -1.941521 0.716184 0.318086 -0.540593 -2.408134 0.526977

D -0.613758 0.718741 -1.420655 -0.182436 0.333909 -1.608134

5 0.788941 -0.541419 -1.195019 -0.924797 -0.261171 1.078212

6 0.894871 0.454283 -0.763443 0.065712 -0.336119 0.182736

In [11]: df.G

Out[11]: array([0, 1, 2, 3, 4, 5])

可以看到,我们只是动态地给DataFrame的实例对象加入了一个属性,而如果该列已经存在,是可以对该列进行更改的

In [12]: df.A = np.arange(6)

In [13]: df

Out[13]:

A B 3 4 5 6

1 0 -1.160599 -1.236521 -2.356423 0.089117 1.090875

2 1 -0.285893 0.918261 1.250223 2.028298 -0.007042

C 2 0.716184 0.318086 -0.540593 -2.408134 0.526977

D 3 0.718741 -1.420655 -0.182436 0.333909 -1.608134

5 4 -0.541419 -1.195019 -0.924797 -0.261171 1.078212

6 5 0.454283 -0.763443 0.065712 -0.336119 0.182736

所以,以上就是属性选取方法,可见,由于各种限制,属性选取有着非常大的局限,同时,这种操作还很可能得到意想不到的结果,所以我个人并不推介使用这种选取的方法。

2.基础选取

官方文档称这种方式为Basic Selecte,所以这里我也称之为基础选取方式,这种方式就是直接对DataFrame对象使用[]运算符,其实现方式是实现类的__getitem__魔术方法。

使用这种选取方法,非常简单,直接将需要选取的列名放入中括号中即可

In [14]: df['A']

Out[14]:

1 0

2 1

C 2

D 3

5 4

6 5

Name: A, dtype: int32

可以看到,这种方法可以非常方便地选取到一列数据,而当我们访问不存在的列时,将会抛出KeyError,这与Python的魔术方法协议是一致的,这点也是我喜欢Python的原因之一,通过各种类似协议的魔术方法,使得类似的操作能得到同样的结果,比如求长度我就立刻知道应该使用len()而不需要去猜是.length()还是.size()

In [15]: df['G']

KeyError: 'G'

其次就是,这种方法只能选取一列,不可以同时选取到多个列

In [16]: df[('A', 'B')]

KeyError: ('A', 'B')

同时需要注意的是,我们传入的列名,其类型也必须和列名的类型相同

In [17]: df[3]

KeyError: 3

In [18]: df['3']

Out[18]:

1 -1.236521

2 0.918261

C 0.318086

D -1.420655

5 -1.195019

6 -0.763443

Name: 3, dtype: float64

最后,这种方法还可以对DataFrame进行切片,但此时是对行进行切片

In [19]: df[:'B']

KeyError: 'B'

In [20]: df[:3]

Out[20]:

A B 3 4 5 6

1 0 -1.160599 -1.236521 -2.356423 0.089117 1.090875

2 1 -0.285893 0.918261 1.250223 2.028298 -0.007042

C 2 0.716184 0.318086 -0.540593 -2.408134 0.526977

In [21]: df[:'D':-1]

Out[21]:

A B 3 4 5 6

6 5 0.454283 -0.763443 0.065712 -0.336119 0.182736

5 4 -0.541419 -1.195019 -0.924797 -0.261171 1.078212

D 3 0.718741 -1.420655 -0.182436 0.333909 -1.608134

可以看到,此时我们可以使用坐标进行切片,也可以输入行名,同时切片的第三个参数也是可以使用的,但如果我们尝试对列进行切片,则会抛出KeyError。

3.标签选取

标签选取,即严格使用行列名(index)进行选取的方法,其需要使用.loc属性

In [22]: df.loc['C']

Out[22]:

A 2.000000

B 0.716184

3 0.318086

4 -0.540593

5 -2.408134

6 0.526977

Name: C, dtype: float64

可以看到,这种方法其能够快速选定一行,而事实上,该方法可以同时定位行和列或者多行多列,此时只需要默念,先行后列,先行后列,先行后列,并使用逗号分隔

In [23]: df.loc['C', 'A']

Out[23]: 2.0

In [24]: df.loc[('C', 'D'), ('A', 'B')]

Out[24]:

A B

C 2 0.716184

D 3 0.718741

同时,该方法可以进行切片,并且可以行列同时进行,需要说明的是,这里只能接受两个参数,即行和列的切片,不能使用第三个参数

In [25]: df.loc['C':'6', '3':]

Out[25]:

3 4 5 6

C 0.318086 -0.540593 -2.408134 0.526977

D -1.420655 -0.182436 0.333909 -1.608134

5 -1.195019 -0.924797 -0.261171 1.078212

6 -0.763443 0.065712 -0.336119 0.182736

In [26]: df.loc['C':'6', '3':, -1]

IndexingError: Too many indexers

如果需要表示全部选中,比如选中所有的行,则必须要写出:表示全部选中,即可以省略后面的参数,默认选中所有的列,但是,需要选中所有的行时,行参数不可以省略

In [27]: df.loc[:, 5]

Out[27]:

1 0.089117

2 2.028298

C -2.408134

D 0.333909

5 -0.261171

6 -0.336119

Name: 5, dtype: float64

如果我们选择不存在的位置,将会抛出KeyError

In [28]: df.loc['G']

KeyError: 'the label [G] is not in the [index]'

值得注意的是,该方法要求非常严格,其要求输入的行列名必须与DataFrame的行列名类型一致,否则抛出KeyError

In [29]: df.loc[6]

KeyError: 'the label [6] is not in the [index]'

4.坐标选取

大多数刚刚开始使用DataFrame的童鞋可能都非常喜欢使用坐标来选取数据,毕竟如果我们将DataFrame理解为一个二维的数组,那么使用坐标来选取就显得非常的浑然天成,但是这时候,我们会发现前面说到的方法多大都需要时行名列名且要确保其类型也是一致的,这时候传统的直接使用坐标进行选取就会失效。

如果我们仍然需要使用坐标进行数据选取,此时就需要使用.iloc属性

In [30]: df.iloc[0]

Out[30]:

A 0.000000

B -1.160599

3 -1.236521

4 -2.356423

5 0.089117

6 1.090875

Name: 1, dtype: float64

与标签选取方法类似,这种方法也可以同时定位行和列、多行和多列,同样是先行后列,逗号分隔

In [31]: df.iloc[0, 5]

Out[31]: 1.0908752302725568

In [32]: df.iloc[(0, 2), (2, 3)]

Out[32]:

3 4

1 -1.236521 -2.356423

C 0.318086 -0.540593

同样的,也支持切片,使用:表示全部选中,不可以有第三个参数

In [33]: df.iloc[:, :3]

Out[33]:

A B 3

1 0 -1.160599 -1.236521

2 1 -0.285893 0.918261

C 2 0.716184 0.318086

D 3 0.718741 -1.420655

5 4 -0.541419 -1.195019

6 5 0.454283 -0.763443

可以说,这个方法和标签选取的方法,其实是两兄弟,一个是使用标签,一个是使用坐标进行选取,当然,如果我们选取不存在的位置,其也会非常合理地抛出IndexError

In [34]: df.iloc[7]

IndexError: single positional indexer is out-of-bounds

而如果我们输入的参数不是整数,此时将会抛出TypeError

In [35]: df.iloc['C']

TypeError: cannot do positional indexing with these indexers [C] of

最后需要注意的是,这里说的坐标都是实时的,所以,我们需要注意,不要与标签选取的方法混淆,标签选取无论该数据在表格的什么位置都能够选取到,而定位选取则有可能给我们不一样的结果

In [36]: df.sort_values('B').iloc[1]

Out[35]:

A 4.000000

B -0.541419

3 -1.195019

4 -0.924797

5 -0.261171

6 1.078212

Name: 5, dtype: float64

In [37]: df.sort_values('B').loc[1]

Out[37]:

A 0.000000

B -1.160599

3 -1.236521

4 -2.356423

5 0.089117

6 1.090875

Name: 1, dtype: float64

可以看到,即使顺序打乱了,我们仍能根据行名准确得到对应的行,而如果是是用坐标,那么我们得到的就是B列最小的那一行即这里的行名为5的行,所以在选择使用标签选取或者是定位选取的时候,一定要明确自己的需求。

5.条件筛选

当我们需要按列筛选行的时候,根据上面所说的方法,直接使用[],这里是一致的

In [38]: df[df['B'] > 0]

Out[38]:

A B 3 4 5 6

C 2 0.716184 0.318086 -0.540593 -2.408134 0.526977

D 3 0.718741 -1.420655 -0.182436 0.333909 -1.608134

6 5 0.454283 -0.763443 0.065712 -0.336119 0.182736

而按行筛选列时,则有一点不同,正确的方法是

In [39]: df.loc[:, df.loc['C'] > 0]

Out[39]:

A B 3 6

1 0 -1.160599 -1.236521 1.090875

2 1 -0.285893 0.918261 -0.007042

C 2 0.716184 0.318086 0.526977

D 3 0.718741 -1.420655 -1.608134

5 4 -0.541419 -1.195019 1.078212

6 5 0.454283 -0.763443 0.182736

是否觉得很诡异,这里我们可以探究一下pandas是如何实现这个筛选逻辑的

In [40]: df['B'] > 0

Out[40]:

1 False

2 False

C True

D True

5 False

6 True

Name: B, dtype: bool

In [41]: df.loc['C'] > 0

Out[41]:

A True

B True

3 True

4 False

5 False

6 True

Name: C, dtype: bool

可以看到,当我们取出一列进行大小判断时,其返回的是所有的行的判断结果(Series对象),而如果我们对一行进行判断,则返回的是各个列的判断结果,即pandas通过覆写大小判断运算符将判断操作自动扩展至对象中的每个元素,这点和R的逻辑是契合的。而上面我们也说到过,当我们使用的是[]进行切片时,我们是对行进行切片,而这里,我们刚好就填入了行的判断结果(In [40]),所以,如果我们输入的切片参数是Series对象时,pandas将切出被判断为True的行。对列进行筛选的操作也是同样的,只不过先行后列,所以前面我们需要:来表示我们选中所有的行,同时也就意味着,使用.loc时,可以同时对行和列进行筛选,只需要同时给出判断结果即可

In [42]: df.loc[df['B'] > 0, df.loc['C'] > 0]

Out[42]:

A B 3 6

C 2 0.716184 0.318086 0.526977

D 3 0.718741 -1.420655 -1.608134

6 5 0.454283 -0.763443 0.182736

到这里,相信这个筛选操作就比较好理解了,但是有一点需要注意的是,我们不能使用定位方法进行筛选

In [43]: df.iloc[1] > 0

Out[43]:

A True

B False

3 True

4 True

5 True

6 False

Name: 2, dtype: bool

可以看到,即使我们使用定位方法选中的行列并进行判断后,其仍然使用标签进行定位,所以我们可以知道,在pandas的设计当中,标签定位的优先级是大于坐标定位的,因而在使用pandas库时,应该转变思想,要将理念从二维数组中跳脱出来,将pandas理解为一个更像数据库的存在。

最后,也就是多条件联合筛选,由于python内置的布尔运算符and和or不可以进行覆写,而此时又需要将布尔运算扩展至每个元素,因而pandas覆写了&和|这两个运算符,写过其他语言的小伙伴应该不陌生,要注意的是,这里只需要写一次,不像Java等需要写两次。

In [44]: df[(df['B'] > 0) & (df['3'] > 0)]

Out[44]:

A B 3 4 5 6

C 2 0.716184 0.318086 -0.540593 -2.408134 0.526977

In [45]: df.loc[:, (df.loc['C'] > 0) | (df.loc['5'] > 0)]

Out[45]:

A B 3 6

1 0 -1.160599 -1.236521 1.090875

2 1 -0.285893 0.918261 -0.007042

C 2 0.716184 0.318086 0.526977

D 3 0.718741 -1.420655 -1.608134

5 4 -0.541419 -1.195019 1.078212

6 5 0.454283 -0.763443 0.182736

需要注意的是,由于只有进行判断结束返回的Series对象,才可以进行布尔运算,所以这里需要给每个判断条件加上小括号以提高运算优先级。

6.总结

最后,结合上述内容和我个人的使用经验,总结一些我个人最佳实践

数据在读取时就需要进行处理,首先一点就是应该将每一行作为一个样本,一列作为一个特征,由于大多数时候是根据属性对样本进行筛选,所以此时筛选起来就会更加的便捷。(df.T可以获得经过转置的DataFrame即行列交换)

每一个样本即每一行都必须使用唯一的index(行名),这一点有点数据库的主键的意思,这样就能保证我们能准确选到我们需要的数据,至于列名,如果根据前面的规则,则应该不会存在相同的特征,且全部行名和列名统一为一种类型,推介字符串类型。

当需要选中一列时,直接使用df[col]的方法选中一列,而需要选中一行的时候,直接使用df.loc[row]来选中一行。

在任何操作中尽可能避免使用坐标进行定位。

当需要同时对行列进行操作时,使用df.loc[row, loc]并在心里默念先行后列,同时,这种方式的参数比较多样,可以输入判断结果,也可输入单个行列名或者包含多个行列名的列表,可以按需选择。

更多待补充。

dateframe取某列数据_DataFrame数据选取全攻略相关推荐

  1. Python语言学习之pandas:DataFrame二维表的简介、常用函数、常用案例(增删改查排序之选择指定列、根据条件选择特定数据、赋值、列名重命名、修改列数据、处理缺失值、列合并、分组之详细攻略

    Python语言学习之pandas:DataFrame二维表的简介.常用函数.常用案例(增删改查排序之选择指定列.根据条件选择特定数据.赋值.列名重命名.修改列数据.处理缺失值.列合并.分组之详细攻略 ...

  2. MySQL与优化有关的命令_MySQL优化全攻略-相关数据库命令

    MySQL优化全攻略-相关数据库命令 更新时间:2006年11月25日 00:00:00   作者: 接下来我们要讨论的是数据库性能优化的另一方面,即运用数据库服务器内建的工具辅助性能分析和优化. ▲ ...

  3. 通过数据:提升用户转化与留存全攻略

    如何想要产品收益最大化?就应该这样做--提升用户转化与留存全攻略 首先我们看一下提升用户转化的运营价值.如图1所示,先引入两个概念--用户生命周期与用户价值(LTV).如果将用户在一款产品中的行为轨迹 ...

  4. 大数据工程师职场面试攻略技巧有哪些?

    面试是一个双向选择的过程,面试官在选人,面试者在选公司.而面试者了解这家公司最直接的途径就是通过面试官.如果面试者是个到处抢着要的高手,那你有水平的提问会给这个面试者留下深刻印象,毕竟大家都是喜欢和厉 ...

  5. 元旦假期,去哪里旅游好呢?Python爬取元旦旅游最全攻略!

    2020还有最后几天就就结束了,您考虑好2021的第一天去哪里旅游了吗,不如来看看使用Python爬取最全攻略!受益的朋友给个三连. 转发请求声明. 一.实现思路 首先我们爬取的网站是一个穷游网站: ...

  6. Python编程语言学习:python中与数字相关的函数(取整等)、案例应用之详细攻略

    Python编程语言学习:python中与数字相关的函数(取整等).案例应用之详细攻略 目录 python中与数字相关的函数 1.对小数进行向上取整 1.1.利用numpy库 1.2.利用math库

  7. Python抓取全国旅游景点以及小吃数据,想做旅游攻略?Python助你事半功倍。

    前言 疫情自从来了之后已经很久没有出去旅游过了,蹭着这段疫情好转,那肯定是要出去走一走的,这一篇其实是全国旅游中的一站,因为每个城市能玩的地方太多了,一篇文章下来肯定是写不了的,所以今天就抓取一下-- ...

  8. 最全攻略:数据分析师必备Python编程基础知识

    导读:本文主要介绍使用Python进行数据分析时必备的编程基础知识,主要涉及Python的基本数据类型.数据结构.程序控制.读写数据等内容. Python编写代码时,是以缩进作为代码块的标识,而不是使 ...

  9. python怎么清洗数据_Python分析数据之:清洗数据全攻略

    前两天翻了翻数据分析的招聘简历,看到好多公司在招聘数据分析师的时候,不管前面要求什么,都会在最后加一句:能够会Python是加分项.那Python是有多好用?今儿一篇文章教会你用Python来分析数据 ...

最新文章

  1. excel随机数_Excel使用函数生成1100的不重复随机数 2种方法
  2. Dapr + .NET 实战(十四)虚拟机集群部署 mDNS + Consul
  3. Mac zsh: command not found zsh 所有命令在终端失效
  4. jQuery 学习-样式篇(四):jQuery 设置和删除元素的属性
  5. L3-013 非常弹的球 (30 分)
  6. 电脑修改服务器时间怎么改,修改服务器时间_如何修改服务器时间 做到同步?...
  7. 【建模算法】基于粒子群算法求解TSP问题(Python实现)
  8. 网络规划 网络工程 用户需求分析 网络结构设计
  9. Java POI word常用方法 在Cell插入子表格
  10. 微信多开无法连接服务器,ios丨微信多开联网失败解决方法
  11. 首度亮相服贸会,亚马逊云科技如何演绎“大象起舞”?
  12. 关于 pace 有意思的一篇文章
  13. 用友NC 漏洞汇总(转载)
  14. 2022-2028全球与中国篮球计时系统市场现状及未来发展趋势
  15. 计算机本地连接没有有效ip配置,本地连接没有有效的ip配置?教您怎么解决
  16. 【ZOJ 4062】Plants vs. Zombies
  17. 为什么成立计算机维修社团,张家口煤矿机械制造高级技工学校学生计算机维修社团成立...
  18. 随滚动条移动的图片代码
  19. 2023美赛数学建模思路获取/2023美赛思路ABCDEF题/美赛数学建模
  20. 揭秘 HAP 激光雷达上“车”之路

热门文章

  1. Educational Codeforces Round 49 (Rated for Div. 2)切题报告
  2. 程序逸的Java项目之旅-图书管理系统之后端接口的快速实现
  3. PROCAST-重力铸造分析流程
  4. flappy bird java源码_android高仿flappy bird源码
  5. CREO5.0.6.0基本操作与导出常用图保姆级教程
  6. 苹果7系统更新后信号无服务器,最全iPhone7手机无服务故障解决办法分享,成功拯救苹果7无信号...
  7. Ubuntu20.4终端指令 Linux安装WPS2019
  8. 迦瓦栈队 团队第一周项目总结
  9. Relax中的量化管理
  10. 计算机二级在线模考,计算机二级模拟考试题2016