学习笔记:由numpy.argsort()引发的思考

一、numpy.argsort() 函数定义

函数的定义

首先函数的定义比较简洁:

argsort()函数是将x中的元素从小到大排列,提取其对应的index(索引),然后输出到y。

实例解析

我将用一个例子来直观示意:

首先导入numpy和pandas,并随机定义一个序列变量\(a\):

import numpy as np
import pandas as pd
# 首先定义一个序列 a
a = pd.Series(np.random.choice(10,5, replace=False))

序列\(a\)输出结果如下:

0    7
1 1
2 6
3 4
4 8
dtype: int32

接着我对其使用一次argsort()函数后输出结果如下:

a.argsort()

0    1
1 3
2 2
3 0
4 4
dtype: int64

可以发现,原序列\(a\)中最小的数为1且其index为1,因此根据argsort()的定义,其index值被排在了最前面即,a.argsort()序列的index = 0处;与此同时,原序列中最大的值(8)所对应的index值(4)也在a.argsort()序列中被相应地排在了末尾(即index = 4)处。相信这个例子已经能够使读者清晰地明白argsort()函数的定义了。

  • 值得一提的是:原序列\(a\)和变化后序列a.argsort()的输出类型是不一样的。这是因为,两者形成机制是不一样的,原序列由np.choice生成的,而a.argsort()则是由pandas序列的index所生成的序列。

二、numpy.argsort()函数与最大最小值

我们在数据处理的时候时常会碰到一些需要得到一个序列中最大值或最小值的问题,或者我们有时候希望能够得到序列中第\(k\)大的值或第\(k\)小的值。可以考虑这样一个匹配问题:在一个由\(n\)位参与者构成的网络中,所有人都希望能够和能力更强的参与者匹配,且每个人最多只能与一位参与者进行匹配,这时会用到一个经典的匹配算法。即将参与者能力按照从小到大进行排序,最最强的参与者开始依次开始进行选取匹配的对象。在这样的算法中,我们很自然的就需要考虑上述的问题,最强的参与者的编号是多少?或者第\(k\)强的参与者编号是多少?numpy.argsort()函数为此类问题提供了一种便捷的解决方法。

这部分我参考了[月夜汐枫的文章](浅述python中argsort()函数的用法 - 2师兄不会胖 - 博客园 (cnblogs.com),我认为他在文章中的分析是很有启发性的。

下述代码可以直接得到序列\(a\)中最大值所对应的序号:

a.argsort()[len(a)-1] # a中最大值的序号

4

在本例中,最大值为8所对应的序号即为4,因此很自然可以通过下述代码得到序列中的最大值:

a[a.argsort()[len(a)-1]] # a中最大值

8

可以将这一写法进一步推广,假设要得到序列中第\(k\)大的值及其序号,只需要修改索引即可:

k =2

a.argsort()[len(a)-k] # a中第k大的值的序号

0

a[a.argsort()[len(a)-k]] # a中第k大值

7

上述代码演示了访问序列\(a\)中第二大的值及其索引。

三、函数双重引用的性质a.argsort().argsort()

一个双重引用的问题

之所以要研究这个问题是因为本人曾经参加过某985金融职业社团的选拔,尽管选拔结果不尽如人意,但其中笔试中所提到的这个问题激发了本人的研究兴趣,故而在此稍作讨论。

原题如图所示:

我依然沿用上述的例子,先看代码结果:

a.argsort().argsort()

0    3
1 0
2 2
3 1
4 4
dtype: int64

上述提到的题目中要求阐述该写法的含义,并提供等价写法。囿于本人眼拙,我实在无法一眼看出该序列与原序列之间存在怎样精巧的数学联系。只有在电脑上通过多个例的方式来寻找规律。

当函数迭代次数大于等于一次时的规律——理论推导

很快我发现,当我继续往后加argsort()时,所生成的新序列好像是有规律的。具体而言,从a.argsort()开始,每次在后面多加两个argsort(),输出的序列结果不变。

a.argsort().argsort().argsort()

0    1
1 3
2 2
3 0
4 4
dtype: int64 a.argsort().argsort().argsort().argsort() 0 3
1 0
2 2
3 1
4 4
dtype: int64

下面我将从理论上证明该结论。

设\(\{a_n^o\}\)为一个序列,\(\mu(\{a_n\})={b_n}\)为一种变换,记作\(\{b_n\}=\{a_n\}^1\),它将原序列按照从小到大的方式进行排序,并提取其原索引值生成一个新的序列. 令\(\{a_n^1\}=\{a_n^o\}^1\),则易知\(\{a_n^1\}\)为集合\(\{0,1,\dots,n-1\}\)的一个排列. 令\(\{a_n^{k}\}=\{a_n^1\}^{k}\),代表对\(\{a_n^{o}\}\)做\(k\)次\(\mu\)变换后的序列,可知\(\forall k \in N^+, \{a_n^{k}\} \in A(n)\),其中\(A(n)\)代表由集合\(\{0,1,\dots,n-1\}\)中所有的元素进行排列所得到的所有序列的集合。

\[\forall k \in N^+ and\space\space\forall l,m \in[0,n)\cap N^+,
\\
a_l^{k+1}=m\space\space if \space and \space only \space if \space a_m^k = l,
\\
a_m^{k+2}=l\space\space if \space and \space only \space if \space a_l^{k+1} = m,
\\
\Rightarrow a_m^{k+2}=l\iff a_l^{k+1} = m \iff a_m^k = l,
\\
\Rightarrow \forall k \in N^+ and\space\space\forall m \in[0,n)\cap N^+,a_m^{k+2}=a_m^k,
\\
\Rightarrow \forall k \in N^+,\{a_n^{k+2}\}=\{a_n^{k}\}
\\
\Rightarrow \forall k \in N^+, \{a_n^{2k+1}\}=\{a_n^{1}\},\{a_n^{2k}\}=\{a_n^{2}\}
\]

函数迭代两次后的序列与原序列的关系

因此,我在理论上证明了上述结论是正确的。所以到这里,我至少有一种写法与a.argsort().argsort()等价,即在后面加上\(2k\)个argsort()。但对于这个”伤敌一千,自损一千二“的方法,我并不是很满意,因为尽管,我已经把使用一次argsort()后,继续迭代的所有情况都已经分析得十分透彻了,但我依然没能找到两次argsort()后的序列与原序列之间的关系,即上述定义下的\(\{a_n^2\}\)与\(\{a_n^o\}\)的关系。

由于\(\{a_n^2\}\)和\(\{a_n^1\}\)之间关系我已经十分清楚了,即\(a_m^{2}=l\iff a_l^{1} = m\),因此问题的关键在于如何数量化\(\{a_n^1\}\)与\(\{a_n^o\}\)之间的关系。在第一节的例子中我已经提到了原序列中最大值的序号将被安置在一次argsort()变换后序列的末尾,而最小值的序号将被排列在变换后序列的开头。因此我得到了这样的数量关系:如果原序列\(\{a_n^o\}\)的索引为\(m\)的值在原序列中是第\(l\)小,其中\(m\in[0,n-1]\cap N^+\),且第0小为最小,那么\(a_l^1=m, a_m^2=l\). 即\(\{a_n^2\}\)的各个索引所对应的值为原序列相同索引所对应的值的从小到大位次。

接下来我只需要知道如何得到原序列各个值的从小到大位次即可。我只需要通过两次对值排序便可以达到这一目的,代码如下:

b = pd.Series(pd.Series(a.sort_values().index).sort_values().index)
b 0 3
1 0
2 2
3 1
4 4
dtype: int64

非常可惜,我是在面试之后才彻底想清楚这一变化的含义,即\(\{a_n^2\}\)的各个索引所对应的值为原序列相同索引所对应的值的从小到大位次。不过也不亏啦,学会了一种函数,对今后的学习工作都有很大的帮助。

四、总结

本文简要分析了numpy.argsort()函数的定义和用途,并较为深入的探讨了一些简单的用法,其中包含最大值、最小值访问问题、以及双重调用、多重迭代问题。总体来说,argsort()函数的功能是十分强大的,它成为了沟通序列值和其序号之间的一道桥梁,使得一些对序列索引的调用得以简化。

对一个序列双重argsort的含义的更多相关文章

  1. Gym 101064 D Black Hills golden jewels 【二分套二分/给定一个序列,从序列中任意取两个数形成一个和,两个数不可相同,要求求出第k小的组合】

    D. Black Hills golden jewels time limit per test 2 seconds memory limit per test 256 megabytes input ...

  2. Swift处理堆栈问题——给定两组序列,其中一个序列表示栈的push 顺序,判断另一个序列有没有可能是对应的pop 顺序

    题目:输入两个整数序列.其中一个序列表示栈的push 顺序,判断另一个序列有没有可能是对应的pop 顺序.为了简单起见,我们假设push 序列的任意两个整数都是不相等的.比如输入的push 序列是1. ...

  3. SGU 179 Brackets light(生成字典序的下一个序列)

    题目链接:http://acm.sgu.ru/problem.php?contest=0&problem=179 解题报告:输入一个合法的括号串,求出这个括号串的字典序的下一个串.(认为'(' ...

  4. 把一个序列转换成严格递增序列的最小花费 CF E - Sonya and Problem Wihtout a Legend

    //把一个序列转换成严格递增序列的最小花费 CF E - Sonya and Problem Wihtout a Legend //dp[i][j]:把第i个数转成第j小的数,最小花费 //此题与po ...

  5. 把一个序列转换成非严格递增序列的最小花费 POJ 3666

    //把一个序列转换成非严格递增序列的最小花费 POJ 3666 //dp[i][j]:把第i个数转成第j小的数,最小花费 #include <iostream> #include < ...

  6. 第29题:推断一个序列是否是还有一个push序列的pop序列

    github:https://github.com/frank-cq/MyTest 第29题:输入两个整数序列,当中一个序列表示栈的push顺序,推断还有一个序列有没有可能是相应的pop顺序.为了简单 ...

  7. range([start], stop[, step]):产生一个序列,默认从0开始

    range([start], stop[, step]):产生一个序列,默认从0开始 >>> l = range(10) >>> l [0, 1, 2, 3, 4, ...

  8. hdu 1394 求一个序列的最小逆序数 单点增 区间求和

    题目的意思就好比给出一个序列 如:0 3 4 1 2 设逆序数初始n = 0: 由于0后面没有比它小的,n = 0 3后面有1,2 n = 2 4后面有1,2,n = 2+2 = 4: 所以该序列逆序 ...

  9. python的reduce函数的使用方法详解以及使用案例,相加,相乘(处理一个序列,然后把序列进程合并操作)

    1.求列表的数字相加之和,还是之前的习惯,写for循环来实现 num_1=[1,2,3,4,5,6,7,8,9] a=0 for n in num_1: #a=a+n a+=n print (a) C ...

随机推荐

  1. Podman容器基础(二)

    Podman容器技术基础(二) 目录 Podman容器技术基础(二) 容器的使用 用户操作 用户配置文件 容器卷 容器的使用 运行一个容器 [root@cent1 ~]# podman pull ht ...

  2. Oracle 同义词详解(synonym)

    Oracle 同义词详解(synonym) 一.Oracle同义词概念 Oracle 数据库中提供了同义词管理的功能.同义词是数据库方案对象的一个别名,经常用于简化对象访问和提高对象访问的安全性.在使 ...

  3. MySQL之安装(linux两种版本版本安装)

    LinuxMySQL安装(Mysql5.5版本) 第一种 有安装包的安装方式 1.下载地址: http://dev.mysql.com/downloads/mysql 2.检查当前系统是否安装过mys ...

  4. 『现学现忘』Git基础 — 37、标签tag(二)

    目录 5.共享标签 6.删除标签 7.修改标签指定提交的代码 8.标签在.git目录中的位置 9.本文中所使用到的命令 提示:接上一篇文章内容. 5.共享标签 默认情况下,git push 命令并不会 ...

  5. 齐博x1文本代码标签的使用

    文本标签虽然简单,但是使用的地方确实非常多的. {qb:tag name="XXXX" type="text"}推荐新闻{/qb:tag} 类似这种使用的频率是 ...

  6. 齐博x1第三季《模板风格的制作》系列009-自定义区块代码

    本节来说明如何自定义区块代码,不再继承上层模板,实现个性模板 上一节因为我们继承了layout布局模版,所以我们自定义的代码就无效了 如果我们继承了上层模板,那么相当于我们复制了一份上层模板的结构,也 ...

  7. (数据科学学习手札145)在Python中利用yarl轻松操作url

    本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 大家好我是费老师,在诸如网络爬虫.web应用开发 ...

  8. 基于BP神经网络的手MNIST写数字识别

    import numpy import math import scipy.special#特殊函数模块 import matplotlib.pyplot as plt #创建神经网络类,以便于实例化 ...

  9. Hadoop集群简单入门

    Hadoop集群搭建 自己配置Hadoop的话太过复杂了,因为自己着急学习,就使用了黑马的快照.如果小伙伴们也想的话可以直接看黑马的课程,快照的话关注黑马程序员公众号,输入Hadoop就能获取资料,到 ...

  10. springboot整合mybatis步骤以及错误集合

    1.首先在springboot项目中的pomx文件引入官方的依赖 <groupId>org.mybatis.spring.boot</groupId> <artifact ...