对一个序列双重argsort的含义
学习笔记:由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\}\)中所有的元素进行排列所得到的所有序列的集合。
\\
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的含义的更多相关文章
- 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 ...
- Swift处理堆栈问题——给定两组序列,其中一个序列表示栈的push 顺序,判断另一个序列有没有可能是对应的pop 顺序
题目:输入两个整数序列.其中一个序列表示栈的push 顺序,判断另一个序列有没有可能是对应的pop 顺序.为了简单起见,我们假设push 序列的任意两个整数都是不相等的.比如输入的push 序列是1. ...
- SGU 179 Brackets light(生成字典序的下一个序列)
题目链接:http://acm.sgu.ru/problem.php?contest=0&problem=179 解题报告:输入一个合法的括号串,求出这个括号串的字典序的下一个串.(认为'(' ...
- 把一个序列转换成严格递增序列的最小花费 CF E - Sonya and Problem Wihtout a Legend
//把一个序列转换成严格递增序列的最小花费 CF E - Sonya and Problem Wihtout a Legend //dp[i][j]:把第i个数转成第j小的数,最小花费 //此题与po ...
- 把一个序列转换成非严格递增序列的最小花费 POJ 3666
//把一个序列转换成非严格递增序列的最小花费 POJ 3666 //dp[i][j]:把第i个数转成第j小的数,最小花费 #include <iostream> #include < ...
- 第29题:推断一个序列是否是还有一个push序列的pop序列
github:https://github.com/frank-cq/MyTest 第29题:输入两个整数序列,当中一个序列表示栈的push顺序,推断还有一个序列有没有可能是相应的pop顺序.为了简单 ...
- range([start], stop[, step]):产生一个序列,默认从0开始
range([start], stop[, step]):产生一个序列,默认从0开始 >>> l = range(10) >>> l [0, 1, 2, 3, 4, ...
- hdu 1394 求一个序列的最小逆序数 单点增 区间求和
题目的意思就好比给出一个序列 如:0 3 4 1 2 设逆序数初始n = 0: 由于0后面没有比它小的,n = 0 3后面有1,2 n = 2 4后面有1,2,n = 2+2 = 4: 所以该序列逆序 ...
- 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 ...
随机推荐
- C++面向对象编程之堆、栈和内存形式
1.stack 是存在与某个作用域的一块内存空间,当调用函数时,函数就会形成一个stack 存这它的一些参数.返回地址等,生闷气在函数执行完会自动消灭: 2.heap 是操作系统提供的全局的内存空间, ...
- P7113 [NOIP2020] 排水系统 (拓扑排序)
(不想打高精,也不想学习其他大佬的神仙写法,打了90分的错解). 本题容易想到用拓扑排序处理,涉及分数的加法,用long long会超时,不过通分时先除后乘卡一下也可以拿90分. 结构体真是个复杂的东 ...
- Request method ‘POST‘ not supported。 Failed to load resource: net::ERR_FAILED
1.问题描述 技术栈:前后端项目分离(Springboot+Vue+MybatisPlus) 前端报错信息: 后端报错信息: 2.问题分析 这里使用了ResultFul风格的接口设计方式.增删改查对应 ...
- 一天五道Java面试题----第八天(怎么处理慢查询--------->简述Myisam和innodb的区别)
这里是参考B站上的大佬做的面试题笔记.大家也可以去看视频讲解!!! 文章目录 1.怎么处理慢查询 2.ACID靠什么保证的 3.什么是MVCC 4.mysql主从同步原理 5.简述Myisam和inn ...
- 记录第一次在Linux环境编译第三方C++库
要使用clion编程,需要curl库,在官网下载源代码自己编译:https://curl.haxx.se/download.html 解压后进入路径,配置编译选项: 1 # ./configure - ...
- Java Stream流的使用
流相关的方法可以分为三种类型,分别是:获取Stream流.中间方法.终结方法.中间方法会返回当前流,可以方便的进行链式调用. 流不可重复使用,否则会报错: java.lang.IllegalState ...
- 河北首家城商行传统核心业务国产化,TDSQL突破三“最”为秦皇岛银行保驾护航
11 月 1 日,秦皇岛银行新一代分布式核心系统成功投产并稳定安全运行超过三个月,标志着秦皇岛银行数字化转型应用和服务水平登上了一个新台阶. 这是秦皇岛银行有史以来规模最大.范围最广.难度最高的一次系 ...
- "xxx cannot be cast to jakarta.servlet.Servlet "报错解决方式
在做jsp的上机时候同学出现了一个500错误:com.kailong.servlet.ComputeBill cannot be cast to jaka.servlet.Servlet 然后因为我用 ...
- python枚举类型 Enum
在python中枚举是一种类(Enum) 枚举类中不能存在相同的标签名 枚举是可迭代的 例: from enum import Enum class Vip(Enum): MONDAY = 0 TUE ...
- Vue3 企业级优雅实战 - 组件库框架 - 4 组件库的 CSS 架构
在前一篇文章中分享了搭建组件库的基本开发环境.创建了 foo 组件模块和组件库入口模块,本文分享组件库的样式架构设计. 1 常见的 CSS 架构模式 常见的 CSS 架构模式有很多:OOCSS.ACS ...