抖音滑块验证码 captchaBody 逆向分析,JSVMP 纯算法还原
本文已收到抖音的律师函,CSDN 和本站的文章都已经做下架处理。 欢迎加入爬虫逆向微信交流群:添加微信 IT-BOB(备注交流群)
本文已收到抖音的律师函,CSDN 和本站的文章都已经做下架处理。 欢迎加入爬虫逆向微信交流群:添加微信 IT-BOB(备注交流群)
文章目录 栈的概念 栈的特点 栈的操作 Python 实现栈 栈的简单应用:括号匹配问题 栈的简单应用:倒序输出一组元素 栈的概念 栈(stack)又名堆栈,栈是一种线性数据结构,用先进后出或者是后进先出的方式存储数据,栈中数据的插入删除操作都是在栈的顶端进行,这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。 栈的特点 元素后进先出(Last in First Out,LIFO) 栈的操作 push(item):进栈(向栈顶添加元素) pop():出栈(删除栈顶元素) top():查看栈顶元素 empty():判断栈是否为空 Python 实现栈 栈并不是 Python 的内建类型,在必要的时候可以使用列表来模拟基于数组的栈。如果将列表的末尾看作是栈的顶,列表方法 append() 就是将元素压入到栈中(进栈),而列表方法 pop() 会删除并返回栈顶的元素(出栈),列表索引的方式 arr[-1] 可以查看栈顶元素。具体代码实现如下: class Stack: def __init__(self): self.stack = [] def push(self, item): self.stack.append(item) def pop(self): if self.empty(): return None else: return self.stack.pop() def top(self): if self.empty(): return None else: return self.stack[-1] def empty(self): return len(self.stack) == 0 栈的简单应用:括号匹配问题 问题描述: 给定一个字符串,字符串中只包含小括号 ()、中括号 []、大括号 {},求该字符串中的括号是否匹配。匹配规则:成对出现或者左右对称出现,例如: ()[]{}:匹配;{[()]}:匹配;({}]:不匹配;()]:不匹配;({)}:不匹配 通过栈来解决: 有字符串 ()[{}],依次取每个括号,只要是左括号就进栈,只要是右括号就判断栈顶是否为对应的左括号,具体步骤如下: ① 遇到左小括号 (,执行进栈操作; ② 遇到右小括号 ),判断此时栈顶是否为左小括号 (,是则让左小括号 ( 出栈,此时栈为空; ③ 遇到左中括号 [,执行进栈操作; ④ 遇到左大括号 {,执行进栈操作; ⑤ 遇到右大括号 },判断此时栈顶是否为左大括号 {,是则让左大括号 { 出栈,此时栈为空; ⑥ 遇到右中括号 ],判断此时栈顶是否为左中括号 [,是则让左中括号 [ 出栈,此时栈为空; ⑦ 判断最终的栈是否为空,是则表示匹配,不是则表示不匹配。其中第 ② ⑤ ⑥ 步中,若判断为不是,则直接表示不匹配。 Python 代码实现: class Stack: def __init__(self): self.stack = [] def push(self, item): self.stack.append(item) def pop(self): if self.empty(): return None else: return self.stack.pop() def top(self): if self.empty(): return None else: return self.stack[-1] def empty(self): return len(self.stack) == 0def brackets_match(s): match_dict = {'}': '{', ']': "[", ')': '('} stack = Stack() for ch in s: if ch in ['(', '[', '{']: # 如果为左括号,则执行进栈操作 stack.push(ch) else: # 如果为右括号 if stack.empty(): # 如果栈为空,则不匹配,即多了一个右括号,没有左括号匹配 return False elif stack.top() == match_dict[ch]: # 如果栈顶的元素为对应的左括号,则让栈顶出栈 stack.pop() else: # 如果栈顶元素不是对应的左括号,则不匹配 return False if stack.empty(): # 最后的栈如果为空,则匹配,否则不匹配 return True else: return Falseprint(brackets_match('[{()}(){()}[]({}){}]'))print(brackets_match('()[{}]'))print(brackets_match('({)}'))print(brackets_match('[]}')) 输出结果: TrueTrueFalseFalse 栈的简单应用:倒序输出一组元素 把元素存入栈,再顺序取出: class Stack: def __init__(self): self.stack = [] def push(self, item): self.stack.append(item) def pop(self): if self.empty(): return None else: return self.stack.pop() def top(self): if self.empty(): return None else: return self.stack[-1] def empty(self): return len(self.stack) == 0def reverse_list(s): stack = Stack() for ch in s: stack.push(ch) new_list = [] while not stack.empty(): new_list.append(stack.pop()) return new_listprint(reverse_list(['A', 'B', 'C', 'D', 'E'])) 输出结果: ['E', 'D', 'C', 'B', 'A']
文章目录 递归概念 递归要素 递归与迭代的区别 示例一:阶乘 示例二:斐波那契数列 示例三:汉诺塔问题 尾递归 Python 中尾递归的解决方案 递归概念 递归:程序调用自身的编程技巧称为递归( recursion)。用一种通俗的话来说就是自己调用自己,它通常把一个大型复杂的问题层层转化为一个与原问题相似的、但是规模较小的问题来求解,当问题小到一定规模的时候,需要一个递归出口返回。递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。 递归函数:在编程语言中,函数直接或间接调用函数本身,则该函数称为递归函数;在数学上的定义如下:对于某一函数 f(x)f(x)f(x),其定义域是集合 A,那么若对于 A 集合中的某一个值 X0X_0X0,其函数值 f(x0)f(x_0)f(x0) 由 f(f(x0))f(f(x_0))f(f(x0)) 决定,那么就称 f(x)f(x)f(x) 为递归函数。 递归要素 递归必须包含一个基本的出口(结束条件),否则就会无限递归,最终导致栈溢出; 递归必须包含一个可以分解的问题,例如要想求得 fact(n)fact(n)fact(n),就需要用 n∗fact(n−1)n * fact(n-1)n∗fact(n−1); 递归必须必须要向着递归出口靠近,例如每次递归调用都会 n−1n-1n−1,向着递归出口 n==0n == 0n==0 靠近。 递归与迭代的区别 递归(recursion):递归则是一步一步往前递推,直到递归基础,寻找一条路径, 然后再由前向后计算。(A调用A) 迭代(iteration):迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果。每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值,因此迭代是从前往后计算的。(A重复调用B) 示例一:阶乘 一个正整数的阶乘(factorial)是所有小于及等于该数的正整数的积,并且 0 的阶乘为 1。即 n!=1×2×3×...×(n−1)×nn!=1×2×3×...×(n-1)×nn!=1×2×3×...×(n−1)×n,以递归方式定义:n!=(n−1)!×nn!=(n-1)!×nn!=(n−1)!×n def factorial(n): if n == 0: return 1 else: return n * factorial(n-1) 示例二:斐波那契数列 斐波那契数列(Fibonacci sequence),又称黄金分割数列、因数学家莱昂纳多·斐波那契以兔子繁殖为例子而引入,故又称为“兔子数列”。 有一个数列:0、1、1、2、3、5、8、13、21、34、55、89…,这个数列从第3项开始,每一项都等于前两项之和。以递推的方法定义:F(n)=F(n−1)+F(n−2)(n≥3,n∈N∗)F(n)=F(n - 1)+F(n - 2) (n ≥ 3, n ∈ N^*)F(n)=F(n−1)+F(n−2)(n≥3,n∈N∗) def fibonacc(n): if n == 1 or n == 2: return 1 else: return fibonacc(n-1) + fibonacc(n-2) 以上方法的时间复杂度为O(2n)O(2^n)O(2n),稍微大一点的数都会算很久,有一个简单的解决方案,使用 lru_cache 缓存装饰器,缓存一些中间结果: from functools import lru_cache# 缓存斐波那契函数已经计算出的结果,最多占用1024字节内存@lru_cache(maxsize=1024)def fibonacc(n): if n == 1 or n == 2: return 1 else: return fibonacc(n-1) + fibonacc(n-2) 另外还有更加节省时间和空间的方法: def fibonacc(n, current=0, next=1): if n == 0: return current else: return fibonacc(n-1, next, current+next) 示例三:汉诺塔问题 汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。64片黄金圆盘移动完毕之日,就是世界毁灭之时。 对于 n 个盘子,移动步骤如下: 把 n-1 个盘子由 A 经过 C 移动到 B 把最后一个盘子移动到 C 把 n-1 个盘子由 B 经过 A 移动到 C 递归代码实现: def hanoi(n, a, b, c): # n 个盘子,a,b,c三个柱子 if n > 0: hanoi(n-1, a, c, b) # 把 n-1 个盘子由 a 经过 c 移动到 b print('moving from {0} to {1}'.format(a, c)) # 把最后一个盘子移动到 c hanoi(n-1, b, a, c) # 把 n-1 个盘子由 b 经过 a 移动到 c 示例: def hanoi(n, a, b, c): if n > 0: hanoi(n-1, a, c, b) print('moving from {0} to {1}'.format(a, c)) hanoi(n-1, b, a, c)hanoi(3, 'A', 'B', 'C') moving from A to Cmoving from A to Bmoving from C to Bmoving from A to Cmoving from B to Amoving from B to Cmoving from A to C 尾递归 如果一个函数中所有递归形式的调用都出现在函数的末尾,我们称这个递归函数是尾递归的。通俗来讲就是递归调用放在了函数的最后。 # 一般递归def func(n): if n > 0: func(n-1) print(n)# 一般递归def func(n): if n > 0: return func(n-1) + n# 尾递归def func(n): a = n if n > 0: a += 1 print(a, n) return func(n-1) 对于普通的递归,每一级递归都产生了新的局部变量,必须创建新的调用栈,随着递归深度的增加,创建的栈越来越多,容易造成爆栈。 def normal_recursion(n): if n == 1: return 1 else: return n + normal_recursion(n-1) normal_recursion(5) 执行: normal_recursion(5)5 + normal_recursion(4)5 + 4 + normal_recursion(3)5 + 4 + 3 + normal_recursion(2)5 + 4 + 3 + 2 + normal_recursion(1)5 + 4 + 3 + 35 + 4 + 65 + 1015 尾递归基于函数的尾调用,每一级调用直接返回递归函数更新调用栈,没有新局部变量的产生,类似迭代的实现。 def tail_recursion(n, total=0): if n == 0: return total else: return tail_recursion(n-1, total+n) normal_recursion(5) 执行: tail_recursion(5, 0)tail_recursion(4, 5)tail_recursion(3, 9)tail_recursion(2, 12)tail_recursion(1, 14)tail_recursion(0, 15)15 在 Python,Java,Pascal 等语言中是无法实现尾递归优化的,所以采用了 for,while,goto 等特殊结构以迭代的方式来代替尾递归。 Python 中尾递归的解决方案 使用普通的递归来实现斐波那契数列的计算,代码段如下: def fibonacc(n, current=0, next=1): if n == 0: return current else: return fibonacc(n-1, next, current+next)a = fibonacc(1000)print(a) 此时会报错,因为超过了最大递归深度(默认深度900-1000左右): Traceback (most recent call last): File "F:/PycharmProjects/algorithm/fibonacc_test.py", line 57, in <module> a = fibonacc(1000) File "F:/PycharmProjects/algorithm/fibonacc_test.py", line 47, in fibonacc return fibonacc(n-1, next, current+next) File "F:/PycharmProjects/algorithm/fibonacc_test.py", line 47, in fibonacc return fibonacc(n-1, next, current+next) File "F:/PycharmProjects/algorithm/fibonacc_test.py", line 47, in fibonacc return fibonacc(n-1, next, current+next) [Previous line repeated 995 more times] File "F:/PycharmProjects/algorithm/fibonacc_test.py", line 44, in fibonacc if n == 0:RecursionError: maximum recursion depth exceeded in comparison 如果是递归深度不是很大的情况,可以手动重设递归深度来解决: import syssys.setrecursionlimit(10000) # 递归深度设置为 10000 如果递归深度非常大,那么就可以采用尾递归优化,但是 Python 官方是并不支持尾递归的(不知道为啥),然而这难不到广大的程序员们,早在 2006 年 Crutcher Dunnavant 就想出了一个解决办法,实现一个 tail_call_optimized 装饰器,原文链接:https://code.activestate.com/recipes/474088/,原代码是 Python 2.4 实现的,用 Python 3.x 实现如下: # This program shows off a python decorator# which implements tail call optimization. It# does this by throwing an exception if it is# it's own grandparent, and catching such# exceptions to recall the stack.import sysclass TailRecurseException(BaseException): def __init__(self, args, kwargs): self.args = args self.kwargs = kwargsdef tail_call_optimized(g): """ This function decorates a function with tail call optimization. It does this by throwing an exception if it is it's own grandparent, and catching such exceptions to fake the tail call optimization. This function fails if the decorated5 function recurses in a non-tail context. """ def func(*args, **kwargs): f = sys._getframe() if f.f_back and f.f_back.f_back and f.f_back.f_back.f_code == f.f_code: raise TailRecurseException(args, kwargs) else: while 1: try: return g(*args, **kwargs) except TailRecurseException as e: args = e.args kwargs = e.kwargs func.__doc__ = g.__doc__ return func 使用该装饰器再来实现比较大的斐波那契数列的计算: @tail_call_optimizeddef fibonacc(n, current=0, next=1): if n == 0: return current else: return fibonacc(n-1, next, current+next)a = fibonacc(1000)print(a) 输出结果: 43466557686937456435688527675040625802564660517371780402481729089536555417949051890403879840079255169295922593080322634775209689623239873322471161642996440906533187938298969649928516003704476137795166849228875 tail_call_optimized 实现尾递归优化的原理:当递归函数被该装饰器修饰后,递归调用在装饰器while循环内部进行,每当产生新的递归调用栈帧时,f.f_back.f_back.f_code == f.f_code: 就捕获当前尾调用函数的参数,并抛出异常,从而销毁递归栈并使用捕获的参数手动调用递归函数,所以递归的过程中始终只存在一个栈帧对象,达到优化的目的。 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 TRHX•鲍勃。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/109322815未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 排序算法分类 一、冒泡排序(Bubble Sort) 1、原理 2、步骤 3、动画演示 4、代码实现 5、具体示例 二、选择排序(Selection Sort) 1、原理 2、步骤 3、动画演示 4、代码实现 5、具体示例 三、插入排序(Insertion Sort) 1、原理 2、步骤 3、动画演示 4、代码实现 5、具体示例 四、希尔排序(Shell Sort) 1、原理 2、步骤 3、动画演示 4、代码实现 5、具体示例 五、归并排序(Merge Sort) 1、原理 2、步骤 3、动画演示 4、代码实现 5、具体示例 六、快速排序(Quick Sort) 1、原理 2、步骤 3、动画演示 4、代码实现 5、具体示例 七、堆排序(Heap Sort) 1、原理 2、步骤 3、动画演示 4、代码实现 5、具体示例 八、计数排序(Counting Sort) 1、原理 2、步骤 3、动画演示 4、代码实现 5、具体示例 九、桶排序(Bucket Sort) 1、原理 2、步骤 3、动画演示 4、代码实现 5、具体示例 十、基数排序(Radix Sort) 1、原理 2、步骤 3、动画演示 4、代码实现 5、具体示例 参考资料:https://www.bilibili.com/video/BV1mp4y1D7UP 本文动图演示来源:https://visualgo.net/ 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/108987300未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 排序算法分类 内部排序:指在排序期间,元素全部存放在内存中的排序,常见的内部排序算法有:冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序、堆排序、基数排序等。 外部排序:指在排序期间,元素无法完全全部同时存放在内存中,必须在排序的过程中根据要求不断地在内、外存之间移动的排序; 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。 非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。 常见的非比较类排序算法有:基数排序、计数排序、桶排序等 一般情况下,内部排序算法在执行过程中都要进行两种操作:比较和移动。通过比较两个关键字的大小,确定对应元素的前后关系,然后通过移动元素以达到有序。但是,并非所有的内部排序算法都要基于比较操作。 每种排序算法都有各自的优缺点,适合在不同的环境下使用,就其全面性能而言,很难提出一种被认为是最好的算法。通常可以将排序算法分为插入排序、交换排序、选择排序、归并排序和基数排序五大类,内部排序算法的性能取决于算法的时间复杂度和空间复杂度,而时间复杂度一般是由比较和移动的次数决定的。 排序算法时间复杂度(平均)时间复杂度(最好)时间复杂度(最坏)空间复杂度稳定性 冒泡排序O(n2)O(n^2)O(n2)O(n)O(n)O(n)O(n2)O(n^2)O(n2)O(1)O(1)O(1)稳定 选择排序O(n2)O(n^2)O(n2)O(n2)O(n^2)O(n2)O(n2)O(n^2)O(n2)O(1)O(1)O(1)不稳定 插入排序O(n2)O(n^2)O(n2)O(n)O(n)O(n)O(n2)O(n^2)O(n2)O(1)O(1)O(1)稳定 希尔排序O(nlogn)O(nlogn)O(nlogn)O(nlog2n)O(nlog^2n)O(nlog2n)O(nlog2n)O(nlog^2n)O(nlog2n)O(1)O(1)O(1)不稳定 归并排序O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(n)O(n)O(n)稳定 快速排序O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(n2)O(n^2)O(n2)O(logn)O(logn)O(logn)不稳定 堆排序O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(1)O(1)O(1)不稳定 计数排序O(n+k)O(n+k)O(n+k)O(n+k)O(n+k)O(n+k)O(n+k)O(n+k)O(n+k)O(k)O(k)O(k)稳定 桶排序O(n+k)O(n+k)O(n+k)O(n+k)O(n+k)O(n+k)O(n2)O(n^2)O(n2)O(n+k)O(n+k)O(n+k)稳定 基数排序O(n∗k)O(n*k)O(n∗k)O(n∗k)O(n*k)O(n∗k)O(n∗k)O(n*k)O(n∗k)O(n+k)O(n+k)O(n+k)稳定 稳定性:排序后 2 个相等键值的顺序和排序之前它们的顺序是否相同。例:如果 a 原本在 b 前面,且 a=b,排序之后 a 仍然在 b 的前面,则表示具有稳定性。 常见时间复杂度大小比较: O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<...<O(2n)<O(n!)O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) <...< O(2^n)<O (n!)O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<...<O(2n)<O(n!) 一、冒泡排序(Bubble Sort) 1、原理 重复地走访要排序的元素,依次比较两个相邻的元素,如果顺序(如从大到小)错误就把他们交换过来。走访元素的工作是重复地进行,直到没有相邻元素需要交换,也就是说该元素列已经排序完成。冒泡的意思其实就是每一轮冒泡一个最大的元素就会通过不断比较和交换相邻元素使它转移到最右边。 假如有 10 个小盆友从左到右站成一排,个头不等。老师想让他们按照个头从低到高站好,于是他开始喊口号。 每喊一次,从第一个小盆友开始,相邻的小朋友如果身高不是正序就会两两调换,就这样第一轮个头最高的排到了最右边(冒泡到最右边),第二轮依次这么来,从第一个小朋友开始两两交换,这样次高的小盆友又排到了倒数第二个位置。依次类推。 2、步骤 ① 比较相邻的元素。如果第一个比第二个大,就交换它们两个; ② 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数; ③ 针对所有的元素重复步骤 ① ~ ②,除了最后一个元素,直到排序完成。 3、动画演示 4、代码实现 def bubbleSort(arr): for i in range(len(arr)-1): # 循环第 i 趟 for j in range(len(arr)-i-1): # j 为下标 if arr[j] > arr[j+1]: # 如果这个数大于后面的数就交换两者的位置 arr[j], arr[j+1] = arr[j+1], arr[j] return arr 冒泡排序还有一种优化算法,就是立一个 flag,当某一趟序列遍历中元素没有发生交换,则证明该序列已经有序,就不再进行后续的排序。动画演示里就是改进后的算法,改进后的代码如下: def bubbleSort(arr): for i in range(len(arr)-1): # 循环第 i 趟 flag = False for j in range(len(arr)-i-1): # j 为下标 if arr[j] > arr[j+1]: # 如果这个数大于后面的数就交换两者的位置 arr[j], arr[j+1] = arr[j+1], arr[j] flag = True if not flag: return return arr 冒泡排序最快的情况:当输入的数据是正序时;最慢的情况:当输入的数据是反序时。 5、具体示例 未改进版本: def bubble_sort(arr): for i in range(len(arr)-1): # 循环第 i 趟 for j in range(len(arr)-i-1): # j 为下标 if arr[j] > arr[j+1]: # 如果这个数大于后面的数就交换两者的位置 arr[j], arr[j+1] = arr[j+1], arr[j] print(arr) # 每一趟比较完了就打印一次arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]bubble_sort(arr) [3, 38, 5, 44, 15, 36, 26, 27, 2, 46, 4, 19, 47, 48, 50][3, 5, 38, 15, 36, 26, 27, 2, 44, 4, 19, 46, 47, 48, 50][3, 5, 15, 36, 26, 27, 2, 38, 4, 19, 44, 46, 47, 48, 50][3, 5, 15, 26, 27, 2, 36, 4, 19, 38, 44, 46, 47, 48, 50][3, 5, 15, 26, 2, 27, 4, 19, 36, 38, 44, 46, 47, 48, 50][3, 5, 15, 2, 26, 4, 19, 27, 36, 38, 44, 46, 47, 48, 50][3, 5, 2, 15, 4, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50][3, 2, 5, 4, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50][2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50][2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50][2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50][2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50][2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50][2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50] 改进版本: def bubble_sort(arr): for i in range(len(arr)-1): # 循环第 i 趟 flag = False for j in range(len(arr)-i-1): # j 为下标 if arr[j] > arr[j+1]: # 如果这个数大于后面的数就交换两者的位置 arr[j], arr[j+1] = arr[j+1], arr[j] flag = True if not flag: return print(arr) # 每一趟比较完了就打印一次arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]bubble_sort(arr) [3, 38, 5, 44, 15, 36, 26, 27, 2, 46, 4, 19, 47, 48, 50][3, 5, 38, 15, 36, 26, 27, 2, 44, 4, 19, 46, 47, 48, 50][3, 5, 15, 36, 26, 27, 2, 38, 4, 19, 44, 46, 47, 48, 50][3, 5, 15, 26, 27, 2, 36, 4, 19, 38, 44, 46, 47, 48, 50][3, 5, 15, 26, 2, 27, 4, 19, 36, 38, 44, 46, 47, 48, 50][3, 5, 15, 2, 26, 4, 19, 27, 36, 38, 44, 46, 47, 48, 50][3, 5, 2, 15, 4, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50][3, 2, 5, 4, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50][2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50] 二、选择排序(Selection Sort) 1、原理 第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。可以理解为 一个 0 到 n-1 的迭代,每次向后查找选择一个最小的元素。选择排序是不稳定的排序方法。 假如有 10 个小盆友从左到右站成一排,个头不等。老师想让他们按照个头从低到高站好,我们从第一个开始,从头到尾找一个个头最小的小盆友,然后把它和第一个小盆友交换。 然后从第二个小盆友开始采取同样的策略,这样一圈下来小盆友就是有序的了。 2、步骤 ① 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置; ② 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾; ③ 重复步骤 ②,直到所有元素均排序完毕。 3、动画演示 4、代码实现 Python 代码: def selection_sort(arr): for i in range(len(arr)-1): # 循环第 i 趟 min_index = i # 记录最小数的下标 for j in range(i+1, len(arr)): # j 为下标 if arr[j] < arr[min_index]: # 如果这个数小于记录的最小数,则更新最小数的下标 min_index = j arr[i], arr[min_index] = arr[min_index], arr[i] # 将 i 位置的数(已排序序列的末尾的数)和最小数进行交换 return arr 5、具体示例 def selection_sort(arr): for i in range(len(arr)-1): # 循环第 i 趟 min_index = i # 记录最小数的下标 for j in range(i+1, len(arr)): # j 为下标 if arr[j] < arr[min_index]: # 如果这个数小于记录的最小数,则更新最小数的下标 min_index = j arr[i], arr[min_index] = arr[min_index], arr[i] # 将 i 位置的数(已排序序列的末尾的数)和最小数进行交换 print(arr) # 每一趟比较完了就打印一次arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]selection_sort(arr) [2, 44, 38, 5, 47, 15, 36, 26, 27, 3, 46, 4, 19, 50, 48][2, 3, 38, 5, 47, 15, 36, 26, 27, 44, 46, 4, 19, 50, 48][2, 3, 4, 5, 47, 15, 36, 26, 27, 44, 46, 38, 19, 50, 48][2, 3, 4, 5, 47, 15, 36, 26, 27, 44, 46, 38, 19, 50, 48][2, 3, 4, 5, 15, 47, 36, 26, 27, 44, 46, 38, 19, 50, 48][2, 3, 4, 5, 15, 19, 36, 26, 27, 44, 46, 38, 47, 50, 48][2, 3, 4, 5, 15, 19, 26, 36, 27, 44, 46, 38, 47, 50, 48][2, 3, 4, 5, 15, 19, 26, 27, 36, 44, 46, 38, 47, 50, 48][2, 3, 4, 5, 15, 19, 26, 27, 36, 44, 46, 38, 47, 50, 48][2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 46, 44, 47, 50, 48][2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 50, 48][2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 50, 48][2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 50, 48][2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50] 三、插入排序(Insertion Sort) 1、原理 插入排序一般也被称为直接插入排序。对于少量元素的排序,它是一个有效的算法。它的基本思想是将一个记录插入到已经排好序的有序表中,从而形成一个新的有序表。在其实现过程使用双层循环,外层循环对除了第一个元素之外的所有元素进行遍历,内层循环对当前元素前面有序表进行待插入位置查找,并进行移动。 插入排序的工作方式像许多人排序一手扑克牌。开始时,我们的左手为空并且桌子上的牌面向下。然后,我们每次从桌子上拿走一张牌并将它插入左手中正确的位置。为了找到一张牌的正确位置,我们从右到左将它与已在手中的每张牌进行比较。拿在左手上的牌总是排序好的,原来这些牌是桌子上牌堆中顶部的牌。 2、步骤 ① 从第一个元素开始,该元素可以认为已经被排序; ② 取出下一个元素,在已经排序的元素序列中从后向前扫描; ③ 如果该元素(已排序的)大于新元素,将该元素往右移到下一位置,重复该步骤,直到找到已排序的元素小于或者等于新元素的位置; ④ 将新元素插入到步骤 ③ 找到的位置的后面; ⑤ 重复步骤 ② ~ ④。 3、动画演示 4、代码实现 def insertion_sort(arr): for i in range(1, len(arr)): # 将 i 看做摸到的牌的下标 tmp = arr[i] # 将摸到的牌储存到 tmp j = i-1 # 将 j 看做手里的牌的下标 while j >= 0 and arr[j] > tmp: # 如果手里的牌大于摸到的牌 arr[j+1] = arr[j] # 将手里的牌往右移一个位置(将手里的牌赋值给下一个位置) j -= 1 # 将手里的牌的下标减 1,再次准备与摸到的牌进行比较 arr[j+1] = tmp # 将摸到的牌插入到 j+1 位置 return arr 5、具体示例 def insertion_sort(arr): for i in range(1, len(arr)): # 将 i 看做摸到的牌的下标 tmp = arr[i] # 将摸到的牌储存到 tmp j = i-1 # 将 j 看做手里的牌的下标 while j >= 0 and arr[j] > tmp: # 如果手里的牌大于摸到的牌 arr[j+1] = arr[j] # 将手里的牌往右移一个位置(将手里的牌赋值给下一个位置) j -= 1 # 将手里的牌的下标减 1,再次准备与摸到的牌进行比较 arr[j+1] = tmp # 将摸到的牌插入到 j+1 位置 print(arr) # 每一趟比较完了就打印一次arr = [0, 9, 8, 7, 1, 2, 3, 4, 5, 6]insertion_sort(arr) [0, 9, 8, 7, 1, 2, 3, 4, 5, 6] # 手里第一张牌为 0,摸到 9,此时 i=1,j=0,0 比 9 小,将 9 插到索引 j+1=1 处。[0, 8, 9, 7, 1, 2, 3, 4, 5, 6] # 手里的牌为 0,9,摸到 8,此时 i=2,j=1,9 比 8 大,将 9 右移一个位置,j-1=0,将 8 插到 j+1=1 处[0, 7, 8, 9, 1, 2, 3, 4, 5, 6][0, 1, 7, 8, 9, 2, 3, 4, 5, 6][0, 1, 2, 7, 8, 9, 3, 4, 5, 6][0, 1, 2, 3, 7, 8, 9, 4, 5, 6][0, 1, 2, 3, 4, 7, 8, 9, 5, 6][0, 1, 2, 3, 4, 5, 7, 8, 9, 6][0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 四、希尔排序(Shell Sort) 1、原理 希尔排序是插入排序的一种更高效的改进版本,是一种分组插入排序算法,又称缩小增量排序(Diminishing Increment Sort),希尔排序是非稳定排序算法。该方法因 D.L.Shell 于 1959 年提出而得名。 希尔排序是基于插入排序的以下两点性质而提出改进方法的: 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率; 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位; 希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。 2、步骤 ① n 为数组长度,首先取一个整数 d1=n/2,将元素分为 d1 个组,每组相邻量元素之间距离为 d1-1,在各组内进行直接插入排序; ② 取第二个整数 d2=d1/2,重复步骤 ① 分组排序过程,直到 di=1,即所有元素在同一组内进行直接插入排序。 PS:希尔排序每趟并不使某些元素有序,而是使整体数据越来越接近有序;最后一趟排序使得所有数据有序。 3、动画演示 4、代码实现 def insertion_sort_gap(arr, gap): # 将 gap 看做隔 gap 个距离摸一张牌,而不是依次按照顺序摸牌 for i in range(gap, len(arr)): # 将 i 看做摸到的牌的下标 tmp = arr[i] # 将摸到的牌储存到 tmp j = i-gap # 将 j 看做手里的牌的下标 while j >= 0 and arr[j] > tmp: # 如果手里的牌大于摸到的牌 arr[j+gap] = arr[j] # 将手里的牌往右移一个位置(将手里的牌赋值给下一个位置) j -= gap # 将手里的牌的下标减 gap,再次准备与摸到的牌进行比较 arr[j+gap] = tmp # 将摸到的牌插入到 j+gap 位置def shell_sort(arr): d = len(arr) // 2 # 第一次分组 while d >= 1: insertion_sort_gap(arr, d) # 调用插入排序 d //= 2 # 整除 2 后再次分组 return arr 也可以不使用两个函数,写在一起即可: def shell_sort(arr): d = len(arr) // 2 # 第一次分组 while d >= 1: # 将 d 看做隔 d 个距离摸一张牌,而不是依次按照顺序摸牌 for i in range(d, len(arr)): # 将 i 看做摸到的牌的下标 tmp = arr[i] # 将摸到的牌储存到 tmp j = i - d # 将 j 看做手里的牌的下标 while j >= 0 and arr[j] > tmp: # 如果手里的牌大于摸到的牌 arr[j + d] = arr[j] # 将手里的牌往右移一个位置(将手里的牌赋值给下一个位置) j -= d # 将手里的牌的下标减 d,再次准备与摸到的牌进行比较 arr[j + d] = tmp # 将摸到的牌插入到 j+d 位置 d //= 2 # 整除 2 后再次分组 return arr 5、具体示例 def insertion_sort_gap(arr, gap): # 将 gap 看做隔 gap 个距离摸一张牌,而不是依次按照顺序摸牌 for i in range(gap, len(arr)): # 将 i 看做摸到的牌的下标 tmp = arr[i] # 将摸到的牌储存到 tmp j = i-gap # 将 j 看做手里的牌的下标 while j >= 0 and arr[j] > tmp: # 如果手里的牌大于摸到的牌 arr[j+gap] = arr[j] # 将手里的牌往右移一个位置(将手里的牌赋值给下一个位置) j -= gap # 将手里的牌的下标减 gap,再次准备与摸到的牌进行比较 arr[j+gap] = tmp # 将摸到的牌插入到 j+gap 位置def shell_sort(arr): d = len(arr) // 2 # 第一次分组 while d >= 1: insertion_sort_gap(arr, d) # 调用插入排序 print(arr) # 每一轮排序后打印一次 d //= 2 # 整除 2 后再次分组arr = [5, 7, 4, 6, 3, 1, 2, 9, 8]shell_sort(arr) [3, 1, 2, 6, 5, 7, 4, 9, 8][2, 1, 3, 6, 4, 7, 5, 9, 8][1, 2, 3, 4, 5, 6, 7, 8, 9] def shell_sort(arr): d = len(arr) // 2 # 第一次分组 while d >= 1: # 将 d 看做隔 d 个距离摸一张牌,而不是依次按照顺序摸牌 for i in range(d, len(arr)): # 将 i 看做摸到的牌的下标 tmp = arr[i] # 将摸到的牌储存到 tmp j = i - d # 将 j 看做手里的牌的下标 while j >= 0 and arr[j] > tmp: # 如果手里的牌大于摸到的牌 arr[j + d] = arr[j] # 将手里的牌往右移一个位置(将手里的牌赋值给下一个位置) j -= d # 将手里的牌的下标减 d,再次准备与摸到的牌进行比较 arr[j + d] = tmp # 将摸到的牌插入到 j+d 位置 print(arr) # 每一轮排序后打印一次 d //= 2 # 整除 2 后再次分组arr = [5, 7, 4, 6, 3, 1, 2, 9, 8]shell_sort(arr) [3, 1, 2, 6, 5, 7, 4, 9, 8][2, 1, 3, 6, 4, 7, 5, 9, 8][1, 2, 3, 4, 5, 6, 7, 8, 9] 五、归并排序(Merge Sort) 1、原理 归并的概念:假设一个列表分为两段,其中每一段都是有序列表,现在将该两段合并为一个有序列表,这种操作称为一次归并。 归并排序是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。 2、步骤 归并的基本步骤: ① 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列; ② 设定两个指针,最初位置分别为两个已经排序序列的起始位置; ③ 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置; ④ 重复步骤 ③ 直到某一指针达到序列尾; ⑤ 将另一序列剩下的所有元素直接复制到合并序列尾。 归并排序的步骤: ① 分解:将列表越分越小,直至分成一个元素,终止条件:一个元素是有序的。 ② 合并:不断将两个有序列表进行归并,列表越来越大,直到所有序列归并完毕。 3、动画演示 4、代码实现 def merge(arr, low, mid, high): # low 和 high 为整个数组的第一个和最后一个位置索引,mid 为中间位置索引 # i 和 j 为指针,最初位置分别为两个有序序列的起始位置 # ltmp 用来存放合并后的序列 i = low j = mid+1 ltmp = [] while i <= mid and j <= high: # 只要左右两边都有数 if arr[i] < arr[j]: # 当左边的数小于右边的数 ltmp.append(arr[i]) # 将左边的数存入 ltmp i += 1 # 左边的指针往右移一位 else: # 当右边的数小于左边的数 ltmp.append(arr[j]) # 将右边的数存入 ltmp j += 1 # 右边的指针往右移一位 # 上面的 while 语句执行完后,左边或者右边没有数了 while i <= mid: # 当左边还有数的时候 ltmp.append(arr[i]) # 将左边剩下的数全部存入 ltmp i += 1 while j <= high: # 当右边还有数的时候 ltmp.append(arr[j]) # 将右边剩下的数全部存入 ltmp j += 1 arr[low:high+1] = ltmp # 将排序后的数组写回原数组def merge_sort(arr, low, high): # low 和 high 为整个数组的第一个和最后一个位置索引 if low < high: # 至少有两个元素 mid = (low + high) // 2 merge_sort(arr, low, mid) # 把左边递归分解 merge_sort(arr, mid+1, high) # 把右边递归分解 merge(arr, low, mid, high) # 做归并 5、具体示例 def merge(arr, low, mid, high): # low 和 high 为整个数组的第一个和最后一个位置索引,mid 为中间位置索引 # i 和 j 为指针,最初位置分别为两个有序序列的起始位置 # ltmp 用来存放合并后的序列 i = low j = mid+1 ltmp = [] while i <= mid and j <= high: # 只要左右两边都有数 if arr[i] < arr[j]: # 当左边的数小于右边的数 ltmp.append(arr[i]) # 将左边的数存入 ltmp i += 1 # 左边的指针往右移一位 else: # 当右边的数小于左边的数 ltmp.append(arr[j]) # 将右边的数存入 ltmp j += 1 # 右边的指针往右移一位 # 上面的 while 语句执行完后,左边或者右边没有数了 while i <= mid: # 当左边还有数的时候 ltmp.append(arr[i]) # 将左边剩下的数全部存入 ltmp i += 1 while j <= high: # 当右边还有数的时候 ltmp.append(arr[j]) # 将右边剩下的数全部存入 ltmp j += 1 arr[low:high+1] = ltmp # 将排序后的数组写回原数组def merge_sort(arr, low, high): # low 和 high 为整个数组的第一个和最后一个位置索引 if low < high: # 至少有两个元素 mid = (low + high) // 2 merge_sort(arr, low, mid) # 把左边递归分解 merge_sort(arr, mid+1, high) # 把右边递归分解 merge(arr, low, mid, high) # 做归并 print(arr) # 每一次归并打印一次arr = [7, 1, 3, 2, 6, 9, 4]merge_sort(arr, 0, len(arr)-1) [1, 7, 3, 2, 6, 9, 4][1, 7, 2, 3, 6, 9, 4][1, 2, 3, 7, 6, 9, 4][1, 2, 3, 7, 6, 9, 4][1, 2, 3, 7, 4, 6, 9][1, 2, 3, 4, 6, 7, 9] 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/108987300未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 六、快速排序(Quick Sort) 1、原理 快速排序是对冒泡排序的一种改进。顾名思义快速排序就是快,而且效率高!它是处理大数据最快的排序算法之一了。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。 2、步骤 ① 从数列中挑出一个元素,称为 “基准值”; ② 重新排序数列,所有元素比基准值小的放在基准值的左边,比基准值大的放在基准值的右边(相同的数可以到任一边)。在这个分区退出之后,该基准值就处于数列的中间位置。这个称为分区(partition)操作,也可以称为一次归位操作,归位操作的过程见下动图; ③ 递归地把小于基准值元素的子数列和大于基准值元素的子数列按照步骤 ① ② 排序。 3、动画演示 4、代码实现 def partition(arr, left, right): # 归位操作,left,right 分别为数组左边和右边的位置索引 tmp = arr[left] while left < right: while left < right and arr[right] >= tmp: # 从右边找比 tmp 小的数,如果比 tmp 大,则移动指针 right -= 1 # 将指针左移一个位置 arr[left] = arr[right] # 将右边的值写到左边的空位上 while left < right and arr[left] <= tmp: # 从左边找比 tmp 大的数,如果比 tmp 小,则移动指针 left += 1 # 将指针右移一个位置 arr[right] = arr[left] # 将左边的值写到右边的空位上 arr[left] = tmp # 把 tmp 归位 return left # 返回 left,right 都可以,目的是便于后面的递归操作对左右两部分进行排序def quick_sort(arr, left, right): # 快速排序 if left < right: mid = partition(arr, left, right) quick_sort(arr, left, mid-1) # 对左半部分进行归位操作 quick_sort(arr, mid+1, right) # 对右半部分进行归位操作 return arr 5、具体示例 def partition(arr, left, right): # 归位操作,left,right 分别为数组左边和右边的位置索引 tmp = arr[left] while left < right: while left < right and arr[right] >= tmp: # 从右边找比 tmp 小的数,如果比 tmp 大,则移动指针 right -= 1 # 将指针左移一个位置 arr[left] = arr[right] # 将右边的值写到左边的空位上 while left < right and arr[left] <= tmp: # 从左边找比 tmp 大的数,如果比 tmp 小,则移动指针 left += 1 # 将指针右移一个位置 arr[right] = arr[left] # 将左边的值写到右边的空位上 arr[left] = tmp # 把 tmp 归位 return left # 返回 left,right 都可以,目的是便于后面的递归操作对左右两部分进行排序def quick_sort(arr, left, right): if left < right: mid = partition(arr, left, right) print(arr) # 每次归位后打印一次 quick_sort(arr, left, mid-1) # 对左半部分进行归位操作 quick_sort(arr, mid+1, right) # 对右半部分进行归位操作arr = [5, 7, 4, 6, 3, 1, 2, 9, 8]quick_sort(arr, 0, len(arr)-1) [2, 1, 4, 3, 5, 6, 7, 9, 8][1, 2, 4, 3, 5, 6, 7, 9, 8][1, 2, 3, 4, 5, 6, 7, 9, 8][1, 2, 3, 4, 5, 6, 7, 9, 8][1, 2, 3, 4, 5, 6, 7, 9, 8][1, 2, 3, 4, 5, 6, 7, 8, 9] 七、堆排序(Heap Sort) 1、原理 堆排序是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。 堆:一种特殊的完全二叉树结构 大根堆:一棵完全二叉树,满足任一节点都比其孩子节点大 小根堆:一棵完全二叉树,满足任一节点都比其孩子节点小 2、步骤 ① 构建堆:将待排序序列构建成一个堆 H[0……n-1],从最后一个非叶子结点开始,从左至右,从下至上进行调整。根据升序或降序需求选择大顶堆或小顶堆; ② 此时的堆顶元素,为最大或者最小元素; ③ 把堆顶元素和堆尾元素互换,调整堆,重新使堆有序; ④ 此时堆顶元素为第二大元素; ⑤ 重复以上步骤,直到堆变空。 3、动画演示 堆构建完成后再进行推排序: 4、代码实现 def sift(arr, low, high): """ :param li: 列表 :param low: 堆的根节点位置 :param high: 堆的最后一个元素的位置 """ i = low # i最开始指向根节点 j = 2 * i + 1 # j开始是左孩子 tmp = arr[low] # 把堆顶存起来 while j <= high: # 只要j位置有数 if j + 1 <= high and arr[j+1] > arr[j]: # 如果右孩子有并且比较大 j = j + 1 # j指向右孩子 if arr[j] > tmp: arr[i] = arr[j] i = j # 往下看一层 j = 2 * i + 1 else: # tmp更大,把tmp放到i的位置上 arr[i] = tmp # 把tmp放到某一级领导位置上 break else: arr[i] = tmp # 把tmp放到叶子节点上def heap_sort(arr): n = len(arr) for i in range((n-2)//2, -1, -1): # i表示建堆的时候调整的部分的根的下标 sift(arr, i, n-1) # 建堆完成 for i in range(n-1, -1, -1): # i 指向当前堆的最后一个元素 arr[0], arr[i] = arr[i], arr[0] sift(arr, 0, i - 1) # i-1是新的high return arr 5、具体示例 def sift(arr, low, high): """ :param li: 列表 :param low: 堆的根节点位置 :param high: 堆的最后一个元素的位置 """ i = low # i最开始指向根节点 j = 2 * i + 1 # j开始是左孩子 tmp = arr[low] # 把堆顶存起来 while j <= high: # 只要j位置有数 if j + 1 <= high and arr[j+1] > arr[j]: # 如果右孩子有并且比较大 j = j + 1 # j指向右孩子 if arr[j] > tmp: arr[i] = arr[j] i = j # 往下看一层 j = 2 * i + 1 else: # tmp更大,把tmp放到i的位置上 arr[i] = tmp # 把tmp放到某一级领导位置上 break else: arr[i] = tmp # 把tmp放到叶子节点上def heap_sort(arr): n = len(arr) print('建堆过程:') print(arr) for i in range((n-2)//2, -1, -1): # i表示建堆的时候调整的部分的根的下标 sift(arr, i, n-1) print(arr) # 建堆完成 print('堆排序过程:') print(arr) for i in range(n-1, -1, -1): # i 指向当前堆的最后一个元素 arr[0], arr[i] = arr[i], arr[0] sift(arr, 0, i - 1) # i-1是新的high print(arr)arr = [2, 7, 26, 25, 19, 17, 1, 90, 3, 36]heap_sort(arr) 建堆过程:[2, 7, 26, 25, 19, 17, 1, 90, 3, 36][2, 7, 26, 25, 36, 17, 1, 90, 3, 19][2, 7, 26, 90, 36, 17, 1, 25, 3, 19][2, 7, 26, 90, 36, 17, 1, 25, 3, 19][2, 90, 26, 25, 36, 17, 1, 7, 3, 19][90, 36, 26, 25, 19, 17, 1, 7, 3, 2]堆排序过程:[90, 36, 26, 25, 19, 17, 1, 7, 3, 2][36, 25, 26, 7, 19, 17, 1, 2, 3, 90][26, 25, 17, 7, 19, 3, 1, 2, 36, 90][25, 19, 17, 7, 2, 3, 1, 26, 36, 90][19, 7, 17, 1, 2, 3, 25, 26, 36, 90][17, 7, 3, 1, 2, 19, 25, 26, 36, 90][7, 2, 3, 1, 17, 19, 25, 26, 36, 90][3, 2, 1, 7, 17, 19, 25, 26, 36, 90][2, 1, 3, 7, 17, 19, 25, 26, 36, 90][1, 2, 3, 7, 17, 19, 25, 26, 36, 90][1, 2, 3, 7, 17, 19, 25, 26, 36, 90] 八、计数排序(Counting Sort) 1、原理 计数排序是一个非基于比较的排序算法,它的优势在于在对一定范围内的整数排序时,它的复杂度为 Ο(n+k),其中 k 是整数的范围,快于任何比较排序算法。计数排序是一种牺牲空间换取时间的做法。计数排序的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。 2、步骤 ① 找到待排序列表中的最大值 k,开辟一个长度为 k+1 的计数列表,计数列表中的值都为 0。 ② 遍历待排序列表,如果遍历到的元素值为 i,则计数列表中索引 i 的值加1。 ③ 遍历完整个待排序列表,计数列表中索引 i 的值 j 表示 i 的个数为 j,统计出待排序列表中每个值的数量。 ④ 创建一个新列表(也可以清空原列表,在原列表中添加),遍历计数列表,依次在新列表中添加 j 个 i,新列表就是排好序后的列表,整个过程没有比较待排序列表中的数据大小。 3、动画演示 4、代码实现 def count_sort(arr): if len(arr) < 2: # 如果数组长度小于 2 则直接返回 return arr max_num = max(arr) count = [0 for _ in range(max_num+1)] # 开辟一个计数列表 for val in arr: count[val] += 1 arr.clear() # 原数组清空 for ind, val in enumerate(count): # 遍历值和下标(值的数量) for i in range(val): arr.append(ind) return arr 5、具体示例 def count_sort(arr): if len(arr) < 2: # 如果数组长度小于 2 则直接返回 return arr max_num = max(arr) count = [0 for _ in range(max_num+1)] # 开辟一个计数列表 for val in arr: count[val] += 1 arr.clear() # 原数组清空 for ind, val in enumerate(count): # 遍历值和下标(值的数量) for i in range(val): arr.append(ind) return arrarr = [2, 3, 8, 7, 1, 2, 2, 2, 7, 3, 9, 8, 2, 1, 4, 2, 4, 6, 9, 2]sorted_arr = count_sort(arr)print(sorted_arr) [1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4, 6, 7, 7, 8, 8, 9, 9] 九、桶排序(Bucket Sort) 1、原理 桶排序又叫箱排序,工作的原理是将数组分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序)。桶排序是鸽巢排序的一种归纳结果。 桶排序也是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。为了使桶排序更加高效,我们需要做到这两点: 在额外空间充足的情况下,尽量增大桶的数量; 使用的映射函数能够将输入的 N 个数据均匀的分配到 K 个桶中。 同时,对于桶中元素的排序,选择何种比较排序算法对于性能的影响至关重要。 最快情况:当输入的数据可以均匀的分配到每一个桶中; 最慢情况:当输入的数据被分配到了同一个桶中。 2、步骤 ① 创建一个定量的数组当作空桶子; ② 遍历序列,把元素一个一个放到对应的桶子去; ③ 对每个不是空的桶子进行排序; ④ 从不是空的桶子里把元素再放回原来的序列中。 3、动画演示 (动图来源于@五分钟学算法,侵删) 4、代码实现 def bucket_sort(arr): max_num = max(arr) n = len(arr) buckets = [[] for _ in range(n)] # 创建桶 for var in arr: i = min(var // (max_num // n), n-1) # i 表示 var 放到几号桶里 buckets[i].append(var) # 把 var 加到桶里边 # 保持桶内的顺序 for j in range(len(buckets[i])-1, 0, -1): if buckets[i][j] < buckets[i][j-1]: buckets[i][j], buckets[i][j-1] = buckets[i][j-1], buckets[i][j] else: break sorted_arr = [] for buc in buckets: sorted_arr.extend(buc) return sorted_arr 5、具体示例 def bucket_sort(arr): max_num = max(arr) n = len(arr) buckets = [[] for _ in range(n)] # 创建桶 for var in arr: i = min(var // (max_num // n), n-1) # i 表示 var 放到几号桶里 buckets[i].append(var) # 把 var 加到桶里边 # 保持桶内的顺序 for j in range(len(buckets[i])-1, 0, -1): if buckets[i][j] < buckets[i][j-1]: buckets[i][j], buckets[i][j-1] = buckets[i][j-1], buckets[i][j] else: break sorted_arr = [] for buc in buckets: sorted_arr.extend(buc) return sorted_arrarr = [7, 12, 56, 23, 19, 33, 35, 42, 42, 2, 8, 22, 39, 26, 17]sorted_arr = bucket_sort(arr)print(sorted_arr) [2, 7, 8, 12, 17, 19, 22, 23, 26, 33, 35, 39, 42, 42, 56] 十、基数排序(Radix Sort) 1、原理 基数排序属于分配式排序,是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。 基数排序、计数排序、桶排序三种排序算法都利用了桶的概念,但对桶的使用方法上是有明显差异的: 基数排序:根据键值的每位数字来分配桶; 计数排序:每个桶只存储单一键值; 桶排序:每个桶存储一定范围的数值。 2、步骤 ① 取数组中的最大数,并取得位数; ② 从最低位开始,依次进行一次排序; ③ 从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。 3、动画演示 4、代码实现 def radix_sort(li): max_num = max(li) # 最大值 9->1次循环, 99->2次循环, 888->3次循环, 10000->5次循环 it = 0 while 10 ** it <= max_num: buckets = [[] for _ in range(10)] for var in li: # var=987, it=1, 987//10->98, 98%10->8; it=2, 987//100->9, 9%10=9 digit = (var // 10 ** it) % 10 # 依次取一位数 buckets[digit].append(var) # 分桶完成 li.clear() for buc in buckets: li.extend(buc) it += 1 # 把数重新写回 li return arr 5、具体示例 def radix_sort(li): max_num = max(li) # 最大值 9->1次循环, 99->2次循环, 888->3次循环, 10000->5次循环 it = 0 while 10 ** it <= max_num: buckets = [[] for _ in range(10)] for var in li: # var=987, it=1, 987//10->98, 98%10->8; it=2, 987//100->9, 9%10=9 digit = (var // 10 ** it) % 10 # 依次取一位数 buckets[digit].append(var) # 分桶完成 li.clear() for buc in buckets: li.extend(buc) it += 1 # 把数重新写回 li return arrarr = [3221, 1, 10, 9680, 577, 9420, 7, 5622, 4793, 2030, 3138, 82, 2599, 743, 4127]sorted_arr = radix_sort(arr)print(sorted_arr) [1, 7, 10, 82, 577, 743, 2030, 2599, 3138, 3221, 4127, 4793, 5622, 9420, 9680] 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/108987300未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
欢迎加入爬虫逆向微信交流群:添加微信 IT-BOB(备注交流群) 文章目录 【1x00】前言 【2x00】思维导图 【3x00】数据结构分析 【4x00】主函数 main() 【5x00】数据获取模块 data_get 【5x01】初始化函数 init() 【5x02】中国总数据 china_total_data() 【5x03】全球总数据 global_total_data() 【5x04】中国每日数据 china_daily_data() 【5x05】境外每日数据 foreign_daily_data() 【6x00】词云图绘制模块 data_wordcloud 【6x01】中国累计确诊词云图 foreign_daily_data() 【6x02】全球累计确诊词云图 foreign_daily_data() 【7x00】地图绘制模块 data_map 【7x01】中国累计确诊地图 china_total_map() 【7x02】全球累计确诊地图 global_total_map() 【7x03】中国每日数据折线图 china_daily_map() 【7x04】境外每日数据折线图 foreign_daily_map() 【8x00】结果截图 【8x01】数据储存 Excel 【8x02】词云图 【8x03】地图 + 折线图 【9x00】完整代码 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/107140534未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【1x00】前言 本来两三个月之前就想搞个疫情数据实时数据展示的,由于各种不可抗拒因素一而再再而三的鸽了,最近终于抽空写了一个,数据是用 Python 爬取的百度疫情实时大数据报告,请求库用的 requests,解析用的 Xpath 语法,词云用的 wordcloud 库,数据可视化用 pyecharts 绘制的地图和折线图,数据储存在 Excel 表格里面,使用 openpyxl 对表格进行处理。 本程序实现了累计确诊地图展示和每日数据变化折线图展示,其他更多数据的获取和展示均可在程序中进行拓展,可以将程序部署在服务器上,设置定时运行,即可实时展示数据,pyecharts 绘图模块也可以整合到 Web 框架(Django、Flask等)中使用。 在获取数据时有全球和境外两个概念,全球包含中国,境外不包含中国,后期绘制的四个图:中国累计确诊地图、全球累计确诊地图(包含中国)、中国每日数据折线图、境外每日数据折线图(不包含中国)。 注意项:直接向该网页发送请求获取的响应中,没有每个国家的每日数据,该数据获取的地址是:https://voice.baidu.com/newpneumonia/get?target=trend&isCaseIn=1&stage=publish 预览地址:http://cov.itrhx.com/(已失效) 数据来源:https://voice.baidu.com/act/newpneumonia/newpneumonia/ pyecharts 文档:https://pyecharts.org/ openpyxl 文档:https://openpyxl.readthedocs.io/ wordcloud 文档:http://amueller.github.io/word_cloud/ 【2x00】思维导图 【3x00】数据结构分析 通过查看百度的疫情数据页面,可以看到很多整齐的数据,猜测就是疫情相关的数据,保存该页面,对其进行格式化,很容易可以分析出所有的数据都在 <script type="application/json" id="captain-config"></script> 里面,其中 title 里面是一些 Unicode 编码,将其转为中文后更容易得到不同的分类数据。 由于数据繁多,可以将数据主体部分提取出来,删除一些重复项和其他杂项,留下数据大体位置并分析数据结构,便于后期的数据提取,经过处理后的数据大致结构如下: <script type="application/json" id="captain-config"> { "component": [ { "mapLastUpdatedTime": "2020.07.05 16:13", // 国内疫情数据最后更新时间 "caseList": [ // caseList 列表,每一个元素是一个字典 { "confirmed": "1", // 每个字典包含中国每个省的每一项疫情数据 "died": "0", "crued": "1", "relativeTime": "1593792000", "confirmedRelative": "0", "diedRelative": "0", "curedRelative": "0", "curConfirm": "0", "curConfirmRelative": "0", "icuDisable": "1", "area": "西藏", "subList": [ // subList 列表,每一个元素是一个字典 { "city": "拉萨", // 每个字典包含该省份对应的每个城市疫情数据 "confirmed": "1", "died": "0", "crued": "1", "confirmedRelative": "0", "curConfirm": "0", "cityCode": "100" } ] } ], "caseOutsideList": [ // caseOutsideList 列表,每一个元素是一个字典 { "confirmed": "241419", // 每个字典包含各国的每一项疫情数据 "died": "34854", "crued": "191944", "relativeTime": "1593792000", "confirmedRelative": "223", "curConfirm": "14621", "icuDisable": "1", "area": "意大利", "subList": [ // subList 列表,每一个元素是一个字典 { "city": "伦巴第", // 每个字典包含每个国家对应的每个城市疫情数据 "confirmed": "94318", "died": "16691", "crued": "68201", "curConfirm": "9426" } ] } ], "summaryDataIn": { // summaryDataIn 国内总的疫情数据 "confirmed": "85307", "died": "4648", "cured": "80144", "asymptomatic": "99", "asymptomaticRelative": "7", "unconfirmed": "7", "relativeTime": "1593792000", "confirmedRelative": "19", "unconfirmedRelative": "1", "curedRelative": "27", "diedRelative": "0", "icu": "6", "icuRelative": "0", "overseasInput": "1931", "unOverseasInputCumulative": "83375", "overseasInputRelative": "6", "unOverseasInputNewAdd": "13", "curConfirm": "515", "curConfirmRelative": "-8", "icuDisable": "1" }, "summaryDataOut": { // summaryDataOut 国外总的疫情数据 "confirmed": "11302569", "died": "528977", "curConfirm": "4410601", "cured": "6362991", "confirmedRelative": "206165", "curedRelative": "190018", "diedRelative": "4876", "curConfirmRelative": "11271", "relativeTime": "1593792000" }, "trend": { // trend 字典,包含国内每日的疫情数据 "updateDate": [], // 日期 "list": [ // list 列表,每项数据及其对应的值 { "name": "确诊", "data": [] }, { "name": "疑似", "data": [] }, { "name": "治愈", "data": [] }, { "name": "死亡", "data": [] }, { "name": "新增确诊", "data": [] }, { "name": "新增疑似", "data": [] }, { "name": "新增治愈", "data": [] }, { "name": "新增死亡", "data": [] }, { "name": "累计境外输入", "data": [] }, { "name": "新增境外输入", "data": [] } ] }, "foreignLastUpdatedTime": "2020.07.05 16:13", // 国外疫情数据最后更新时间 "globalList": [ // globalList 列表,每一个元素是一个字典 { "area": "亚洲", // 按照不同洲进行分类 "subList": [ // subList 列表,每个洲各个国家的疫情数据 { "died": "52", "confirmed": "6159", "crued": "4809", "curConfirm": "1298", "confirmedRelative": "0", "relativeTime": "1593792000", "country": "塔吉克斯坦" } ], "died": "56556", // 每个洲总的疫情数据 "crued": "1625562", "confirmed": "2447873", "curConfirm": "765755", "confirmedRelative": "60574" }, { "area": "其他", // 其他特殊区域疫情数据 "subList": [ { "died": "13", "confirmed": "712", "crued": "651", "curConfirm": "48", "confirmedRelative": "0", "relativeTime": "1593792000", "country": "钻石公主号邮轮" } ], "died": "13", // 其他特殊区域疫情总的数据 "crued": "651", "confirmed": "712", "curConfirm": "48", "confirmedRelative": "0" }, { "area": "热门", // 热门国家疫情数据 "subList": [ { "died": "5206", "confirmed": "204610", "crued": "179492", "curConfirm": "19912", "confirmedRelative": "1172", "relativeTime": "1593792000", "country": "土耳其" } ], "died": "528967", // 热门国家疫情总的数据 "crued": "6362924", "confirmed": "11302357", "confirmedRelative": "216478", "curConfirm": "4410466" }], "allForeignTrend": { // allForeignTrend 字典,包含国外每日的疫情数据 "updateDate": [], // 日期 "list": [ // list 列表,每项数据及其对应的值 { "name": "累计确诊", "data": [] }, { "name": "治愈", "data": [] }, { "name": "死亡", "data": [] }, { "name": "现有确诊", "data": [] }, { "name": "新增确诊", "data": [] } ] }, "topAddCountry": [ // 确诊增量最高的国家 { "name": "美国", "value": 53162 } ], "topOverseasInput": [ // 境外输入最多的省份 { "name": "黑龙江", "value": 386 } ] } ] }</script> 【4x00】主函数 main() 分别将数据获取、词云图绘制、地图绘制写入三个文件:data_get()、data_wordcloud()、data_map(),然后使用一个主函数文件 main.py 来调用这三个文件里面的函数。 import data_getimport data_wordcloudimport data_mapdata_dict = data_get.init()data_get.china_total_data(data_dict)data_get.global_total_data(data_dict)data_get.china_daily_data(data_dict)data_get.foreign_daily_data(data_dict)data_wordcloud.china_wordcloud()data_wordcloud.global_wordcloud()data_map.all_map() 【5x00】数据获取模块 data_get 【5x01】初始化函数 init() 使用 xpath 语法 //script[@id="captain-config"]/text() 提取里面的值,利用 json.loads 方法将其转换为字典对象,以便后续的其他函数调用。 def init(): headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.13 Safari/537.36' } url = 'https://voice.baidu.com/act/newpneumonia/newpneumonia/' response = requests.get(url=url, headers=headers) tree = etree.HTML(response.text) dict1 = tree.xpath('//script[@id="captain-config"]/text()') print(type(dict1[0])) dict2 = json.loads(dict1[0]) return dict2 【5x02】中国总数据 china_total_data() def china_total_data(data): """ 1、中国省/直辖市/自治区/行政区疫情数据 省/直辖市/自治区/行政区:area 现有确诊: curConfirm 累计确诊: confirmed 累计治愈: crued 累计死亡: died 现有确诊增量: curConfirmRelative 累计确诊增量: confirmedRelative 累计治愈增量: curedRelative 累计死亡增量: diedRelative """ wb = openpyxl.Workbook() # 创建工作簿 ws_china = wb.active # 获取工作表 ws_china.title = "中国省份疫情数据" # 命名工作表 ws_china.append(['省/直辖市/自治区/行政区', '现有确诊', '累计确诊', '累计治愈', '累计死亡', '现有确诊增量', '累计确诊增量', '累计治愈增量', '累计死亡增量']) china = data['component'][0]['caseList'] for province in china: ws_china.append([province['area'], province['curConfirm'], province['confirmed'], province['crued'], province['died'], province['curConfirmRelative'], province['confirmedRelative'], province['curedRelative'], province['diedRelative']]) """ 2、中国城市疫情数据 城市:city 现有确诊:curConfirm 累计确诊:confirmed 累计治愈:crued 累计死亡:died 累计确诊增量:confirmedRelative """ ws_city = wb.create_sheet('中国城市疫情数据') ws_city.append(['城市', '现有确诊', '累计确诊', '累计治愈', '累计死亡', '累计确诊增量']) for province in china: for city in province['subList']: # 某些城市没有 curConfirm 数据,则将其设置为 0,crued 和 died 为空时,替换成 0 if 'curConfirm' not in city: city['curConfirm'] = '0' if city['crued'] == '': city['crued'] = '0' if city['died'] == '': city['died'] = '0' ws_city.append([city['city'], '0', city['confirmed'], city['crued'], city['died'], city['confirmedRelative']]) """ 3、中国疫情数据更新时间:mapLastUpdatedTime """ time_domestic = data['component'][0]['mapLastUpdatedTime'] ws_time = wb.create_sheet('中国疫情数据更新时间') ws_time.column_dimensions['A'].width = 22 # 调整列宽 ws_time.append(['中国疫情数据更新时间']) ws_time.append([time_domestic]) wb.save('COVID-19-China.xlsx') print('中国疫情数据已保存至 COVID-19-China.xlsx!') 【5x03】全球总数据 global_total_data() 全球总数据在提取完成后,进行地图绘制时发现并没有中国的数据,因此在写入全球数据时注意要单独将中国的数据插入 Excel 中。 def global_total_data(data): """ 1、全球各国疫情数据 国家:country 现有确诊:curConfirm 累计确诊:confirmed 累计治愈:crued 累计死亡:died 累计确诊增量:confirmedRelative """ wb = openpyxl.Workbook() ws_global = wb.active ws_global.title = "全球各国疫情数据" # 按照国家保存数据 countries = data['component'][0]['caseOutsideList'] ws_global.append(['国家', '现有确诊', '累计确诊', '累计治愈', '累计死亡', '累计确诊增量']) for country in countries: ws_global.append([country['area'], country['curConfirm'], country['confirmed'], country['crued'], country['died'], country['confirmedRelative']]) # 按照洲保存数据 continent = data['component'][0]['globalList'] for area in continent: ws_foreign = wb.create_sheet(area['area'] + '疫情数据') ws_foreign.append(['国家', '现有确诊', '累计确诊', '累计治愈', '累计死亡', '累计确诊增量']) for country in area['subList']: ws_foreign.append([country['country'], country['curConfirm'], country['confirmed'], country['crued'], country['died'], country['confirmedRelative']]) # 在“全球各国疫情数据”和“亚洲疫情数据”两张表中写入中国疫情数据 ws1, ws2 = wb['全球各国疫情数据'], wb['亚洲疫情数据'] original_data = data['component'][0]['summaryDataIn'] add_china_data = ['中国', original_data['curConfirm'], original_data['confirmed'], original_data['cured'], original_data['died'], original_data['confirmedRelative']] ws1.append(add_china_data) ws2.append(add_china_data) """ 2、全球疫情数据更新时间:foreignLastUpdatedTime """ time_foreign = data['component'][0]['foreignLastUpdatedTime'] ws_time = wb.create_sheet('全球疫情数据更新时间') ws_time.column_dimensions['A'].width = 22 # 调整列宽 ws_time.append(['全球疫情数据更新时间']) ws_time.append([time_foreign]) wb.save('COVID-19-Global.xlsx') print('全球疫情数据已保存至 COVID-19-Global.xlsx!') 【5x04】中国每日数据 china_daily_data() def china_daily_data(data): """ i_dict = data['component'][0]['trend'] i_dict['updateDate']:日期 i_dict['list'][0]:确诊 i_dict['list'][1]:疑似 i_dict['list'][2]:治愈 i_dict['list'][3]:死亡 i_dict['list'][4]:新增确诊 i_dict['list'][5]:新增疑似 i_dict['list'][6]:新增治愈 i_dict['list'][7]:新增死亡 i_dict['list'][8]:累计境外输入 i_dict['list'][9]:新增境外输入 """ ccd_dict = data['component'][0]['trend'] update_date = ccd_dict['updateDate'] # 日期 china_confirmed = ccd_dict['list'][0]['data'] # 每日累计确诊数据 china_crued = ccd_dict['list'][2]['data'] # 每日累计治愈数据 china_died = ccd_dict['list'][3]['data'] # 每日累计死亡数据 wb = openpyxl.load_workbook('COVID-19-China.xlsx') # 写入每日累计确诊数据 ws_china_confirmed = wb.create_sheet('中国每日累计确诊数据') ws_china_confirmed.append(['日期', '数据']) for data in zip(update_date, china_confirmed): ws_china_confirmed.append(data) # 写入每日累计治愈数据 ws_china_crued = wb.create_sheet('中国每日累计治愈数据') ws_china_crued.append(['日期', '数据']) for data in zip(update_date, china_crued): ws_china_crued.append(data) # 写入每日累计死亡数据 ws_china_died = wb.create_sheet('中国每日累计死亡数据') ws_china_died.append(['日期', '数据']) for data in zip(update_date, china_died): ws_china_died.append(data) wb.save('COVID-19-China.xlsx') print('中国每日累计确诊/治愈/死亡数据已保存至 COVID-19-China.xlsx!') 【5x05】境外每日数据 foreign_daily_data() def foreign_daily_data(data): """ te_dict = data['component'][0]['allForeignTrend'] te_dict['updateDate']:日期 te_dict['list'][0]:累计确诊 te_dict['list'][1]:治愈 te_dict['list'][2]:死亡 te_dict['list'][3]:现有确诊 te_dict['list'][4]:新增确诊 """ te_dict = data['component'][0]['allForeignTrend'] update_date = te_dict['updateDate'] # 日期 foreign_confirmed = te_dict['list'][0]['data'] # 每日累计确诊数据 foreign_crued = te_dict['list'][1]['data'] # 每日累计治愈数据 foreign_died = te_dict['list'][2]['data'] # 每日累计死亡数据 wb = openpyxl.load_workbook('COVID-19-Global.xlsx') # 写入每日累计确诊数据 ws_foreign_confirmed = wb.create_sheet('境外每日累计确诊数据') ws_foreign_confirmed.append(['日期', '数据']) for data in zip(update_date, foreign_confirmed): ws_foreign_confirmed.append(data) # 写入累计治愈数据 ws_foreign_crued = wb.create_sheet('境外每日累计治愈数据') ws_foreign_crued.append(['日期', '数据']) for data in zip(update_date, foreign_crued): ws_foreign_crued.append(data) # 写入累计死亡数据 ws_foreign_died = wb.create_sheet('境外每日累计死亡数据') ws_foreign_died.append(['日期', '数据']) for data in zip(update_date, foreign_died): ws_foreign_died.append(data) wb.save('COVID-19-Global.xlsx') print('境外每日累计确诊/治愈/死亡数据已保存至 COVID-19-Global.xlsx!') 【6x00】词云图绘制模块 data_wordcloud 【6x01】中国累计确诊词云图 foreign_daily_data() def china_wordcloud(): wb = openpyxl.load_workbook('COVID-19-China.xlsx') # 获取已有的xlsx文件 ws_china = wb['中国省份疫情数据'] # 获取中国省份疫情数据表 ws_china.delete_rows(1) # 删除第一行 china_dict = {} # 将省份及其累计确诊按照键值对形式储存在字典中 for data in ws_china.values: china_dict[data[0]] = int(data[2]) word_cloud = wordcloud.WordCloud(font_path='C:/Windows/Fonts/simsun.ttc', background_color='#CDC9C9', min_font_size=15, width=900, height=500) word_cloud.generate_from_frequencies(china_dict) word_cloud.to_file('WordCloud-China.png') print('中国省份疫情词云图绘制完毕!') 【6x02】全球累计确诊词云图 foreign_daily_data() def global_wordcloud(): wb = openpyxl.load_workbook('COVID-19-Global.xlsx') ws_global = wb['全球各国疫情数据'] ws_global.delete_rows(1) global_dict = {} for data in ws_global.values: global_dict[data[0]] = int(data[2]) word_cloud = wordcloud.WordCloud(font_path='C:/Windows/Fonts/simsun.ttc', background_color='#CDC9C9', width=900, height=500) word_cloud.generate_from_frequencies(global_dict) word_cloud.to_file('WordCloud-Global.png') print('全球各国疫情词云图绘制完毕!') 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/107140534未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【7x00】地图绘制模块 data_map 【7x01】中国累计确诊地图 china_total_map() def china_total_map(): wb = openpyxl.load_workbook('COVID-19-China.xlsx') # 获取已有的xlsx文件 ws_time = wb['中国疫情数据更新时间'] # 获取文件中中国疫情数据更新时间表 ws_data = wb['中国省份疫情数据'] # 获取文件中中国省份疫情数据表 ws_data.delete_rows(1) # 删除第一行 province = [] # 省份 curconfirm = [] # 累计确诊 for data in ws_data.values: province.append(data[0]) curconfirm.append(data[2]) time_china = ws_time['A2'].value # 更新时间 # 设置分级颜色 pieces = [ {'max': 0, 'min': 0, 'label': '0', 'color': '#FFFFFF'}, {'max': 9, 'min': 1, 'label': '1-9', 'color': '#FFE5DB'}, {'max': 99, 'min': 10, 'label': '10-99', 'color': '#FF9985'}, {'max': 999, 'min': 100, 'label': '100-999', 'color': '#F57567'}, {'max': 9999, 'min': 1000, 'label': '1000-9999', 'color': '#E64546'}, {'max': 99999, 'min': 10000, 'label': '≧10000', 'color': '#B80909'} ] # 绘制地图 ct_map = ( Map() .add(series_name='累计确诊人数', data_pair=[list(z) for z in zip(province, curconfirm)], maptype="china") .set_global_opts( title_opts=opts.TitleOpts(title="中国疫情数据(累计确诊)", subtitle='数据更新至:' + time_china + '\n\n来源:百度疫情实时大数据报告'), visualmap_opts=opts.VisualMapOpts(max_=300, is_piecewise=True, pieces=pieces) ) ) return ct_map 【7x02】全球累计确诊地图 global_total_map() def global_total_map(): wb = openpyxl.load_workbook('COVID-19-Global.xlsx') ws_time = wb['全球疫情数据更新时间'] ws_data = wb['全球各国疫情数据'] ws_data.delete_rows(1) country = [] # 国家 curconfirm = [] # 累计确诊 for data in ws_data.values: country.append(data[0]) curconfirm.append(data[2]) time_global = ws_time['A2'].value # 更新时间 # 国家名称中英文映射表 name_map = { "Somalia": "索马里", "Liechtenstein": "列支敦士登", "Morocco": "摩洛哥", "W. Sahara": "西撒哈拉", "Serbia": "塞尔维亚", "Afghanistan": "阿富汗", "Angola": "安哥拉", "Albania": "阿尔巴尼亚", "Andorra": "安道尔共和国", "United Arab Emirates": "阿拉伯联合酋长国", "Argentina": "阿根廷", "Armenia": "亚美尼亚", "Australia": "澳大利亚", "Austria": "奥地利", "Azerbaijan": "阿塞拜疆", "Burundi": "布隆迪", "Belgium": "比利时", "Benin": "贝宁", "Burkina Faso": "布基纳法索", "Bangladesh": "孟加拉国", "Bulgaria": "保加利亚", "Bahrain": "巴林", "Bahamas": "巴哈马", "Bosnia and Herz.": "波斯尼亚和黑塞哥维那", "Belarus": "白俄罗斯", "Belize": "伯利兹", "Bermuda": "百慕大", "Bolivia": "玻利维亚", "Brazil": "巴西", "Barbados": "巴巴多斯", "Brunei": "文莱", "Bhutan": "不丹", "Botswana": "博茨瓦纳", "Central African Rep.": "中非共和国", "Canada": "加拿大", "Switzerland": "瑞士", "Chile": "智利", "China": "中国", "Côte d'Ivoire": "科特迪瓦", "Cameroon": "喀麦隆", "Dem. Rep. Congo": "刚果(布)", "Congo": "刚果(金)", "Colombia": "哥伦比亚", "Cape Verde": "佛得角", "Costa Rica": "哥斯达黎加", "Cuba": "古巴", "N. Cyprus": "北塞浦路斯", "Cyprus": "塞浦路斯", "Czech Rep.": "捷克", "Germany": "德国", "Djibouti": "吉布提", "Denmark": "丹麦", "Dominican Rep.": "多米尼加", "Algeria": "阿尔及利亚", "Ecuador": "厄瓜多尔", "Egypt": "埃及", "Eritrea": "厄立特里亚", "Spain": "西班牙", "Estonia": "爱沙尼亚", "Ethiopia": "埃塞俄比亚", "Finland": "芬兰", "Fiji": "斐济", "France": "法国", "Gabon": "加蓬", "United Kingdom": "英国", "Georgia": "格鲁吉亚", "Ghana": "加纳", "Guinea": "几内亚", "Gambia": "冈比亚", "Guinea-Bissau": "几内亚比绍", "Eq. Guinea": "赤道几内亚", "Greece": "希腊", "Grenada": "格林纳达", "Greenland": "格陵兰岛", "Guatemala": "危地马拉", "Guam": "关岛", "Guyana": "圭亚那合作共和国", "Honduras": "洪都拉斯", "Croatia": "克罗地亚", "Haiti": "海地", "Hungary": "匈牙利", "Indonesia": "印度尼西亚", "India": "印度", "Br. Indian Ocean Ter.": "英属印度洋领土", "Ireland": "爱尔兰", "Iran": "伊朗", "Iraq": "伊拉克", "Iceland": "冰岛", "Israel": "以色列", "Italy": "意大利", "Jamaica": "牙买加", "Jordan": "约旦", "Japan": "日本", "Siachen Glacier": "锡亚琴冰川", "Kazakhstan": "哈萨克斯坦", "Kenya": "肯尼亚", "Kyrgyzstan": "吉尔吉斯斯坦", "Cambodia": "柬埔寨", "Korea": "韩国", "Kuwait": "科威特", "Lao PDR": "老挝", "Lebanon": "黎巴嫩", "Liberia": "利比里亚", "Libya": "利比亚", "Sri Lanka": "斯里兰卡", "Lesotho": "莱索托", "Lithuania": "立陶宛", "Luxembourg": "卢森堡", "Latvia": "拉脱维亚", "Moldova": "摩尔多瓦", "Madagascar": "马达加斯加", "Mexico": "墨西哥", "Macedonia": "马其顿", "Mali": "马里", "Malta": "马耳他", "Myanmar": "缅甸", "Montenegro": "黑山", "Mongolia": "蒙古国", "Mozambique": "莫桑比克", "Mauritania": "毛里塔尼亚", "Mauritius": "毛里求斯", "Malawi": "马拉维", "Malaysia": "马来西亚", "Namibia": "纳米比亚", "New Caledonia": "新喀里多尼亚", "Niger": "尼日尔", "Nigeria": "尼日利亚", "Nicaragua": "尼加拉瓜", "Netherlands": "荷兰", "Norway": "挪威", "Nepal": "尼泊尔", "New Zealand": "新西兰", "Oman": "阿曼", "Pakistan": "巴基斯坦", "Panama": "巴拿马", "Peru": "秘鲁", "Philippines": "菲律宾", "Papua New Guinea": "巴布亚新几内亚", "Poland": "波兰", "Puerto Rico": "波多黎各", "Dem. Rep. Korea": "朝鲜", "Portugal": "葡萄牙", "Paraguay": "巴拉圭", "Palestine": "巴勒斯坦", "Qatar": "卡塔尔", "Romania": "罗马尼亚", "Russia": "俄罗斯", "Rwanda": "卢旺达", "Saudi Arabia": "沙特阿拉伯", "Sudan": "苏丹", "S. Sudan": "南苏丹", "Senegal": "塞内加尔", "Singapore": "新加坡", "Solomon Is.": "所罗门群岛", "Sierra Leone": "塞拉利昂", "El Salvador": "萨尔瓦多", "Suriname": "苏里南", "Slovakia": "斯洛伐克", "Slovenia": "斯洛文尼亚", "Sweden": "瑞典", "Swaziland": "斯威士兰", "Seychelles": "塞舌尔", "Syria": "叙利亚", "Chad": "乍得", "Togo": "多哥", "Thailand": "泰国", "Tajikistan": "塔吉克斯坦", "Turkmenistan": "土库曼斯坦", "Timor-Leste": "东帝汶", "Tonga": "汤加", "Trinidad and Tobago": "特立尼达和多巴哥", "Tunisia": "突尼斯", "Turkey": "土耳其", "Tanzania": "坦桑尼亚", "Uganda": "乌干达", "Ukraine": "乌克兰", "Uruguay": "乌拉圭", "United States": "美国", "Uzbekistan": "乌兹别克斯坦", "Venezuela": "委内瑞拉", "Vietnam": "越南", "Vanuatu": "瓦努阿图", "Yemen": "也门", "South Africa": "南非", "Zambia": "赞比亚", "Zimbabwe": "津巴布韦", "Aland": "奥兰群岛", "American Samoa": "美属萨摩亚", "Fr. S. Antarctic Lands": "南极洲", "Antigua and Barb.": "安提瓜和巴布达", "Comoros": "科摩罗", "Curaçao": "库拉索岛", "Cayman Is.": "开曼群岛", "Dominica": "多米尼加", "Falkland Is.": "福克兰群岛马尔维纳斯", "Faeroe Is.": "法罗群岛", "Micronesia": "密克罗尼西亚", "Heard I. and McDonald Is.": "赫德岛和麦克唐纳群岛", "Isle of Man": "曼岛", "Jersey": "泽西岛", "Kiribati": "基里巴斯", "Saint Lucia": "圣卢西亚", "N. Mariana Is.": "北马里亚纳群岛", "Montserrat": "蒙特塞拉特", "Niue": "纽埃", "Palau": "帕劳", "Fr. Polynesia": "法属波利尼西亚", "S. Geo. and S. Sandw. Is.": "南乔治亚岛和南桑威奇群岛", "Saint Helena": "圣赫勒拿", "St. Pierre and Miquelon": "圣皮埃尔和密克隆群岛", "São Tomé and Principe": "圣多美和普林西比", "Turks and Caicos Is.": "特克斯和凯科斯群岛", "St. Vin. and Gren.": "圣文森特和格林纳丁斯", "U.S. Virgin Is.": "美属维尔京群岛", "Samoa": "萨摩亚" } pieces = [ {'max': 0, 'min': 0, 'label': '0', 'color': '#FFFFFF'}, {'max': 49, 'min': 1, 'label': '1-49', 'color': '#FFE5DB'}, {'max': 99, 'min': 50, 'label': '50-99', 'color': '#FFC4B3'}, {'max': 999, 'min': 100, 'label': '100-999', 'color': '#FF9985'}, {'max': 9999, 'min': 1000, 'label': '1000-9999', 'color': '#F57567'}, {'max': 99999, 'min': 10000, 'label': '10000-99999', 'color': '#E64546'}, {'max': 999999, 'min': 100000, 'label': '100000-999999', 'color': '#B80909'}, {'max': 9999999, 'min': 1000000, 'label': '≧1000000', 'color': '#8A0808'} ] gt_map = ( Map() .add(series_name='累计确诊人数', data_pair=[list(z) for z in zip(country, curconfirm)], maptype="world", name_map=name_map, is_map_symbol_show=False) .set_series_opts(label_opts=opts.LabelOpts(is_show=False)) .set_global_opts( title_opts=opts.TitleOpts(title="全球疫情数据(累计确诊)", subtitle='数据更新至:' + time_global + '\n\n来源:百度疫情实时大数据报告'), visualmap_opts=opts.VisualMapOpts(max_=300, is_piecewise=True, pieces=pieces), ) ) return gt_map 【7x03】中国每日数据折线图 china_daily_map() def china_daily_map(): wb = openpyxl.load_workbook('COVID-19-China.xlsx') ws_china_confirmed = wb['中国每日累计确诊数据'] ws_china_crued = wb['中国每日累计治愈数据'] ws_china_died = wb['中国每日累计死亡数据'] ws_china_confirmed.delete_rows(1) ws_china_crued.delete_rows(1) ws_china_died.delete_rows(1) x_date = [] # 日期 y_china_confirmed = [] # 每日累计确诊 y_china_crued = [] # 每日累计治愈 y_china_died = [] # 每日累计死亡 for china_confirmed in ws_china_confirmed.values: y_china_confirmed.append(china_confirmed[1]) for china_crued in ws_china_crued.values: x_date.append(china_crued[0]) y_china_crued.append(china_crued[1]) for china_died in ws_china_died.values: y_china_died.append(china_died[1]) fi_map = ( Line(init_opts=opts.InitOpts(height='420px')) .add_xaxis(xaxis_data=x_date) .add_yaxis( series_name="中国累计确诊数据", y_axis=y_china_confirmed, label_opts=opts.LabelOpts(is_show=False), ) .add_yaxis( series_name="中国累计治愈趋势", y_axis=y_china_crued, label_opts=opts.LabelOpts(is_show=False), ) .add_yaxis( series_name="中国累计死亡趋势", y_axis=y_china_died, label_opts=opts.LabelOpts(is_show=False), ) .set_global_opts( title_opts=opts.TitleOpts(title="中国每日累计确诊/治愈/死亡趋势"), legend_opts=opts.LegendOpts(pos_bottom="bottom", orient='horizontal'), tooltip_opts=opts.TooltipOpts(trigger="axis"), yaxis_opts=opts.AxisOpts( type_="value", axistick_opts=opts.AxisTickOpts(is_show=True), splitline_opts=opts.SplitLineOpts(is_show=True), ), xaxis_opts=opts.AxisOpts(type_="category", boundary_gap=False), ) ) return fi_map 【7x04】境外每日数据折线图 foreign_daily_map() def foreign_daily_map(): wb = openpyxl.load_workbook('COVID-19-Global.xlsx') ws_foreign_confirmed = wb['境外每日累计确诊数据'] ws_foreign_crued = wb['境外每日累计治愈数据'] ws_foreign_died = wb['境外每日累计死亡数据'] ws_foreign_confirmed.delete_rows(1) ws_foreign_crued.delete_rows(1) ws_foreign_died.delete_rows(1) x_date = [] # 日期 y_foreign_confirmed = [] # 累计确诊 y_foreign_crued = [] # 累计治愈 y_foreign_died = [] # 累计死亡 for foreign_confirmed in ws_foreign_confirmed.values: y_foreign_confirmed.append(foreign_confirmed[1]) for foreign_crued in ws_foreign_crued.values: x_date.append(foreign_crued[0]) y_foreign_crued.append(foreign_crued[1]) for foreign_died in ws_foreign_died.values: y_foreign_died.append(foreign_died[1]) fte_map = ( Line(init_opts=opts.InitOpts(height='420px')) .add_xaxis(xaxis_data=x_date) .add_yaxis( series_name="境外累计确诊趋势", y_axis=y_foreign_confirmed, label_opts=opts.LabelOpts(is_show=False), ) .add_yaxis( series_name="境外累计治愈趋势", y_axis=y_foreign_crued, label_opts=opts.LabelOpts(is_show=False), ) .add_yaxis( series_name="境外累计死亡趋势", y_axis=y_foreign_died, label_opts=opts.LabelOpts(is_show=False), ) .set_global_opts( title_opts=opts.TitleOpts(title="境外每日累计确诊/治愈/死亡趋势"), legend_opts=opts.LegendOpts(pos_bottom="bottom", orient='horizontal'), tooltip_opts=opts.TooltipOpts(trigger="axis"), yaxis_opts=opts.AxisOpts( type_="value", axistick_opts=opts.AxisTickOpts(is_show=True), splitline_opts=opts.SplitLineOpts(is_show=True), ), xaxis_opts=opts.AxisOpts(type_="category", boundary_gap=False), ) ) return fte_map 【8x00】结果截图 【8x01】数据储存 Excel 【8x02】词云图 【8x03】地图 + 折线图 【9x00】完整代码 预览地址:http://cov.itrhx.com/(已失效) 完整代码地址(点亮 star 有 buff 加成):https://github.com/TRHX/Python3-Spider-Practice 爬虫实战专栏(持续更新):https://itrhx.blog.csdn.net/article/category/9351278 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/107140534未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【01x00】读取数据 【01x01】简单示例 【01x02】header / names 定制列标签 【01x03】index_col 指定列为行索引 【01x04】sep 指定分隔符 【01x05】skiprows 忽略行 【01x06】na_values 设置缺失值 【01x07】nrows / chunksize 行与块 【02x00】写入数据 【02x01】简单示例 【02x02】sep 指定分隔符 【02x03】na_rep 替换缺失值 【02x04】index / header 行与列标签 【02x05】columns 指定列 Pandas 系列文章: Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象 Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作 Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理 Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引 Python 数据分析三剑客之 Pandas(五):统计计算与统计描述 Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并 Python 数据分析三剑客之 Pandas(七):合并数据集 Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换 Python 数据分析三剑客之 Pandas(九):时间序列 Python 数据分析三剑客之 Pandas(十):数据读写 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106963135未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【01x00】读取数据 Pandas 提供了一些用于将表格型数据读取为 DataFrame 对象的函数。常见方法如下: Pandas 官方对 IO 工具的介绍:https://pandas.pydata.org/pandas-docs/stable/user_guide/io.html 函数描述 read_csv从文件、URL、文件型对象中加载带分隔符的数据。默认分隔符为逗号 read_table从文件、URL、文件型对象中加载带分隔符的数据。默认分隔符为制表符('\t') read_fwf读取定宽列格式数据(没有分隔符) read_clipboard读取剪贴板中的数据,可以看做 read_table 的剪贴板版本。在将网页转换为表格时很有用 read_excel从 Excel XLS 或 XLSX file 读取表格数据 read_hdf读取 pandas写的 HDF5 文件 read_html读取 HTML 文档中的所有表格 read_json读取 JSON( JavaScript Object Notation)字符串中的数据 read_msgpack读取二进制格式编码的 pandas 数据(Pandas v1.0.0 中已删除对 msgpack 的支持,建议使用 pyarrow) read_pickle读取 Python pickle 格式中存储的任意对象 read_sas读取存储于 SAS 系统自定义存储格式的 SAS 数据集 read_sql(使用 SQLAlchemy)读取 SQL 查询结果为 pandas 的 DataFrame read_stata读取 Stata 文件格式的数据集 read_feather读取 Feather 二进制格式文件 以下以 read_csv 和 read_table 为例,它们的参数多达 50 多个,具体可参见官方文档: read_csv:https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html read_table:https://pandas.pydata.org/docs/reference/api/pandas.read_table.html 常用参数: 参数描述 path表示文件系统位置、URL、文件型对象的字符串 sep / delimiter用于对行中各字段进行拆分的字符序列或正则表达式 header用作列名的行号,默认为 0(第一行),如果没有 header 行就应该设置为 None index_col用作行索引的列编号或列名。可以是单个名称、数字或由多个名称、数字组成的列表(层次化索引) names用于结果的列名列表,结合 header=None skiprows需要忽略的行数(从文件开始处算起),或需要跳过的行号列表(从0开始) na_values指定一组值,将该组值设置为 NaN(缺失值) comment用于将注释信息从行尾拆分出去的字符(一个或多个) parse_dates尝试将数据解析为日期,默认为 False。如果为 True,则尝试解析所有列。此外,还可以指定需要解析的一组列号或列名。 如果列表的元素为列表或元组,就会将多个列组合到一起再进行日期解析工作(例如,日期、时间分别位于两个列中) keep_date_col如果连接多列解析日期,则保持参与连接的列。默认为 False converters由列号 / 列名跟函数之间的映射关系组成的字典。例如,{'foo': f} 会对 foo 列的所有值应用函数 f dayfirst当解析有歧义的日期时,将其看做国际格式(例如,7/6/2012 —> June 7,2012),默认为 Fase date_parser用于解析日期的函数 nrows需要读取的行数(从文件开始处算起) iterator返回一个 TextParser 以便逐块读取文件 chunksize文件块的大小(用于迭代) skip_footer需要忽略的行数(从文件末尾处算起) verbose打印各种解析器输出信息,比如“非数值列中缺失值的数量”等 encoding用于 unicode 的文本编码格式。例如,“utf-8” 表示用 UTF-8 编码的文本 squeeze如果数据经解析后仅含一列,则返回 Series thousands千分位分隔符,如 , 或 . 【01x01】简单示例 首先创建一个 test1.csv 文件: 使用 read_csv 方法将其读出为一个 DataFrame 对象: >>> import pandas as pd>>> obj = pd.read_csv(r'C:\Users\TanRe\Desktop\test1.csv')>>> obj a b c d message0 1 2 3 4 hello1 5 6 7 8 world2 9 10 11 12 python>>> >>> type(obj)<class 'pandas.core.frame.DataFrame'> 前面的 csv 文件是以逗号分隔的,可以使用 read_table 方法并指定分隔符来读取: >>> import pandas as pd>>> obj = pd.read_table(r'C:\Users\TanRe\Desktop\test1.csv', sep=',')>>> obj a b c d message0 1 2 3 4 hello1 5 6 7 8 world2 9 10 11 12 python 【01x02】header / names 定制列标签 以上示例中第一行为列标签,如果没有单独定义列标签,使用 read_csv 方法也会默认将第一行当作列标签: >>> import pandas as pd>>> obj = pd.read_csv(r'C:\Users\TanRe\Desktop\test2.csv')>>> obj 1 2 3 4 hello0 5 6 7 8 world1 9 10 11 12 python 避免以上情况,可以设置 header=None,Pandas 会为其自动分配列标签: >>> import pandas as pd>>> pd.read_csv(r'C:\Users\TanRe\Desktop\test2.csv', header=None) 0 1 2 3 40 1 2 3 4 hello1 5 6 7 8 world2 9 10 11 12 python 也可以使用 names 参数自定义列标签,传递的是一个列表: >>> import pandas as pd>>> pd.read_csv(r'C:\Users\TanRe\Desktop\test2.csv', names=['a', 'b', 'c', 'd', 'message']) a b c d message0 1 2 3 4 hello1 5 6 7 8 world2 9 10 11 12 python 【01x03】index_col 指定列为行索引 index_col 参数可以指定某一列作为 DataFrame 的行索引,传递的参数是列名称,在以下示例中,会将列名为 message 的列作为 DataFrame 的行索引: >>> pd.read_csv(r'C:\Users\TanRe\Desktop\test2.csv', names=['a', 'b', 'c', 'd', 'message'], index_col='message') a b c dmessage hello 1 2 3 4world 5 6 7 8python 9 10 11 12 如果需要构造多层索引的 DataFrame 对象,则只需传入由列编号或列名组成的列表即可: >>> import pandas as pd>>> pd.read_csv(r'C:\Users\TanRe\Desktop\test3.csv', index_col=['key1', 'key2']) value1 value2key1 key2 one a 1 2 b 3 4 c 5 6 d 7 8two a 9 10 b 11 12 c 13 14 d 15 16 【01x04】sep 指定分隔符 在 read_table 中,sep 参数用于接收分隔符,如果遇到不是用固定的分隔符去分隔字段的,也可以传递一个正则表达式作为 read_table 的分隔符,如下面的 txt 文件数据之间是由不同的空白字符间隔开的: >>> import pandas as pd>>> pd.read_table(r'C:\Users\TanRe\Desktop\test1.txt', sep='\s+') A B Caaa -0.264438 -1.026059 -0.619500bbb 0.927272 0.302904 -0.032399ccc -0.264273 -0.386314 -0.217601ddd -0.871858 -0.348382 1.100491 【01x05】skiprows 忽略行 skiprows参数可用于设置需要忽略的行数,或需要跳过的行号列表,在下面的示例中,读取文件时选择跳过第1、3、4行(索引值分别为0、2、3): >>> import pandas as pd>>> pd.read_csv(r'C:\Users\TanRe\Desktop\test4.csv', skiprows=[0, 2, 3]) a b c d message0 1 2 3 4 hello1 5 6 7 8 world2 9 10 11 12 python 【01x06】na_values 设置缺失值 当文件中出现了空字符串或者 NA 值,Pandas 会将其标记成 NaN(缺失值),同样也可以使用 isnull 方法来判断结果值是否为缺失值: >>> import pandas as pd>>> obj = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv')>>> obj something a b c d message0 one 1 2 3.0 4 NaN1 two 5 6 NaN 8 world2 three 9 10 11.0 12 python>>> >>> pd.isnull(obj) something a b c d message0 False False False False False True1 False False False True False False2 False False False False False False na_values 方法可以传递一组值,将这组值设置为缺失值,如果传递的为字典对象,则字典的各值将被设置为 NaN: >>> import pandas as pd>>> obj1 = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv')>>> obj1 something a b c d message0 one 1 2 3.0 4 NaN1 two 5 6 NaN 8 world2 three 9 10 11.0 12 python>>> >>> obj2 = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv', na_values=['1', '12'])>>> obj2 something a b c d message0 one NaN 2 3.0 4.0 NaN1 two 5.0 6 NaN 8.0 world2 three 9.0 10 11.0 NaN python>>> >>> sentinels = {'message': ['python', 'world'], 'something': ['two']}>>> obj3 = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv', na_values=sentinels)>>> obj3 something a b c d message0 one 1 2 3.0 4 NaN1 NaN 5 6 NaN 8 NaN2 three 9 10 11.0 12 NaN 【01x07】nrows / chunksize 行与块 以下 test6.csv 文件中包含 50 行数据: 可以设置 pd.options.display.max_rows 来紧凑地显示指定行数的数据: >>> import pandas as pd>>> pd.options.display.max_rows = 10>>> pd.read_csv(r'C:\Users\TanRe\Desktop\test6.csv') one two three four key0 0.467976 -0.038649 -0.295344 -1.824726 L1 -0.358893 1.404453 0.704965 -0.200638 B2 -0.501840 0.659254 -0.421691 -0.057688 G3 0.204886 1.074134 1.388361 -0.982404 R4 0.354628 -0.133116 0.283763 -0.837063 Q.. ... ... ... ... ..45 2.311896 -0.417070 -1.409599 -0.515821 L46 -0.479893 -0.633419 0.745152 -0.646038 E47 0.523331 0.787112 0.486066 1.093156 K48 -0.362559 0.598894 -1.843201 0.887292 G49 -0.096376 -1.012999 -0.657431 -0.573315 0[50 rows x 5 columns] 通过 nrows 参数可以读取指定行数: >>> import pandas as pd>>> pd.read_csv(r'C:\Users\TanRe\Desktop\test6.csv', nrows=5) one two three four key0 0.467976 -0.038649 -0.295344 -1.824726 L1 -0.358893 1.404453 0.704965 -0.200638 B2 -0.501840 0.659254 -0.421691 -0.057688 G3 0.204886 1.074134 1.388361 -0.982404 R4 0.354628 -0.133116 0.283763 -0.837063 Q 要逐块读取文件,可以指定 chunksize(行数): >>> import pandas as pd>>> chunker = pd.read_csv(r'C:\Users\TanRe\Desktop\test6.csv', chunksize=50)>>> chunker<pandas.io.parsers.TextFileReader object at 0x07A20D60> 返回的 TextParser 对象,可以根据 chunksize 对文件进行逐块迭代。以下示例中,对 test6.csv 文件数据进行迭代处理,将值计数聚合到 “key” 列中: >>> import pandas as pd>>> chunker = pd.read_csv(r'C:\Users\TanRe\Desktop\test6.csv', chunksize=50)>>> tot = pd.Series([], dtype='float64')>>> for piece in chunker: tot = tot.add(piece['key'].value_counts(), fill_value=0)>>> tot = tot.sort_values(ascending=False)>>> tot[:10]G 6.0E 5.0B 5.0L 5.00 5.0K 4.0A 4.0R 4.0C 2.0Q 2.0dtype: float64 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106963135未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【02x00】写入数据 Pandas 提供了一些用于将表格型数据读取为 DataFrame 对象的函数。常见方法如下: 函数描述 to_csv将对象写入逗号分隔值(csv)文件 to_clipboard将对象复制到系统剪贴板 to_excel将对象写入 Excel 工作表 to_hdf使用 HDFStore 将包含的数据写入 HDF5 文件 to_html将 DataFrame 呈现为 HTML 表格 to_json将对象转换为 JSON( JavaScript Object Notation)字符串 to_msgpack将对象写入二进制格式编码的文件(Pandas v1.0.0 中已删除对 msgpack 的支持,建议使用 pyarrow) to_picklePickle(序列化)对象到文件 to_sql将存储在 DataFrame 中的数据写入 SQL 数据库 to_stata将 DataFrame 对象导出为 Stata 格式 to_feather将 DataFrames 写入 Feather 二进制格式文件 以下以 to_csv 为例,它的参数同样多达 50 多个,具体可参见官方文档: https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_csv.html https://pandas.pydata.org/docs/reference/api/pandas.Series.to_csv.html 【02x01】简单示例 以之前的 test5.csv 文件为例,先读出数据,再将数据写入另外的文件: >>> import pandas as pd>>> data = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv')>>> data something a b c d message0 one 1 2 3.0 4 NaN1 two 5 6 NaN 8 world2 three 9 10 11.0 12 python>>> >>> data.to_csv(r'C:\Users\TanRe\Desktop\out1.csv') 【02x02】sep 指定分隔符 sep 参数可用于其他分隔符: >>> import pandas as pd>>> data = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv')>>> data something a b c d message0 one 1 2 3.0 4 NaN1 two 5 6 NaN 8 world2 three 9 10 11.0 12 python>>>>>> data.to_csv(r'C:\Users\TanRe\Desktop\out2.csv', sep='|') 【02x03】na_rep 替换缺失值 na_rep 参数可将缺失值(NaN)替换成其他字符串: >>> import pandas as pd>>> data = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv')>>> data something a b c d message0 one 1 2 3.0 4 NaN1 two 5 6 NaN 8 world2 three 9 10 11.0 12 python>>> >>> data.to_csv(r'C:\Users\TanRe\Desktop\out3.csv', na_rep='X') 【02x04】index / header 行与列标签 设置 index=False, header=False,可以禁用行标签与列标签: >>> import pandas as pd>>> data = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv')>>> data something a b c d message0 one 1 2 3.0 4 NaN1 two 5 6 NaN 8 world2 three 9 10 11.0 12 python>>> >>> data.to_csv(r'C:\Users\TanRe\Desktop\out4.csv', index=False, header=False) 还可以传入列表来重新设置列标签: >>> import pandas as pd>>> data = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv')>>> data something a b c d message0 one 1 2 3.0 4 NaN1 two 5 6 NaN 8 world2 three 9 10 11.0 12 python>>> >>> data.to_csv(r'C:\Users\TanRe\Desktop\out5.csv', header=['a', 'b', 'c', 'd', 'e', 'f']) 【02x05】columns 指定列 可以通过设置 columns 参数,只写入部分列,并按照指定顺序排序: >>> import pandas as pd>>> data = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv')>>> data something a b c d message0 one 1 2 3.0 4 NaN1 two 5 6 NaN 8 world2 three 9 10 11.0 12 python>>>>>> data.to_csv(r'C:\Users\TanRe\Desktop\out6.csv', columns=['c', 'b', 'a']) 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106963135未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【01x00】时间序列 【02x00】Timestamp 时间戳 【02x01】pandas.Timestamp 【02x02】freq 频率部分取值 【02x03】to_datetime 【02x04】date_range 【02x05】索引与切片 【02x06】移动数据与数据偏移 【02x07】时区处理 【03x00】period 固定时期 【03x01】pandas.Period 【03x02】period_range 【03x03】asfreq 时期频率转换 【03x04】to_period 与 to_timestamp() 【04x00】timedelta 时间间隔 【04x01】pandas.Timedelta 【04x02】to_timedelta 【04x03】timedelta_range 【05x00】重采样及频率转换 Pandas 系列文章: Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象 Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作 Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理 Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引 Python 数据分析三剑客之 Pandas(五):统计计算与统计描述 Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并 Python 数据分析三剑客之 Pandas(七):合并数据集 Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换 Python 数据分析三剑客之 Pandas(九):时间序列 Python 数据分析三剑客之 Pandas(十):数据读写 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106947061未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【01x00】时间序列 官网对于时间序列的介绍:https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html 时间序列(time series)是一种重要的结构化数据形式,应用于多个领域,包括金融学、经济学、生态学、神经科学、物理学等。在多个时间点观察或测量到的任何事物都可以形成一段时间序列。很多时间序列是固定频率的,也就是说,数据点是根据某种规律定期出现的(比如每15秒、每5分钟、每月出现一次)。时间序列也可以是不定期的,没有固定的时间单位或单位之间的偏移量。时间序列数据的意义取决于具体的应用场景,主要有以下几种: 时间戳(timestamp),表示某个具体的时间点,例如 2020-6-24 15:30; 固定周期(period),表示某个时间周期,例如 2020-01; 时间间隔(timedelta),持续时间,即两个日期或时间之间的差异。 针对时间戳数据,Pandas 提供了 Timestamp 类型。它本质上是 Python 的原生 datetime 类型的替代品,但是在性能更好的 numpy.datetime64 类型的基础上创建。对应的索引数据结构是 DatetimeIndex。 针对时间周期数据,Pandas 提供了 Period 类型。这是利用 numpy.datetime64 类型将固定频率的时间间隔进行编码。对应的索引数据结构是 PeriodIndex。 针对时间增量或持续时间,Pandas 提供了 Timedelta 类型。Timedelta 是一种代替 Python 原生datetime.timedelta 类型的高性能数据结构,同样是基于 numpy.timedelta64 类型。对应的索引数据结构是 TimedeltaIndex。 【02x00】Timestamp 时间戳 【02x01】pandas.Timestamp 在 pandas 中,pandas.Timestamp 方法用来代替 Python 中的 datetime.datetime 方法。 Timestamp 与 Python 的 Datetime 等效,在大多数情况下都可以互换。 此类型用于组成 DatetimeIndex 以及 Pandas 中其他面向时间序列的数据结构。 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.Timestamp.html 基本语法: class pandas.Timestamp(ts_input=<object object>, freq=None, tz=None, unit=None, year=None, month=None, day=None, hour=None, minute=None, second=None, microsecond=None, nanosecond=None, tzinfo=None) 常用参数: 参数描述 ts_input要转换为时间戳的对象,可以是 datetime-like,str,int,float 类型 freq时间戳将具有的偏移量,可以是 str,日期偏移量类型,取值参见【02x02】freq 频率部分取值 tz时间戳将具有的时区 unit如果 ts_input 是整数或浮点数,该参数用于设置其单位(D、s、ms、us、ns) 简单示例: >>> import pandas as pd>>> pd.Timestamp('2017-01-01T12')Timestamp('2017-01-01 12:00:00') 设置 unit='s',即待转换对象单位为秒: >>> import pandas as pd>>> pd.Timestamp(1513393355.5, unit='s')Timestamp('2017-12-16 03:02:35.500000') 使用 tz 参数设置时区: >>> import pandas as pd>>> pd.Timestamp(1513393355, unit='s', tz='US/Pacific')Timestamp('2017-12-15 19:02:35-0800', tz='US/Pacific') 单独设置年月日: >>> import pandas as pd>>> pd.Timestamp(year=2020, month=6, day=24, hour=12)Timestamp('2020-06-24 12:00:00') 【02x02】freq 频率部分取值 完整取值参见官方文档:https://pandas.pydata.org/docs/user_guide/timeseries.html#timeseries-offset-aliases 参数类型描述 DDay每日历日 BBusinessDay每工作日 HHour每小时 T 或 minMinute每分 SSecond每秒 L 或 msMilli每毫秒(即每千分之一秒) UMicro每微秒(即每百万分之一秒) MMonthEnd每月最后一个日历日 BMBusinessMonthEnd每月最后一个工作日 MSMonthBegin每月第一个日历日 BMSBusinessMonthBegin每月第一个工作日 W-MON、W-TUE…Week从指定的星期几(MON、TUE、 WED、THU、FR、SAT、SUN)开始算起,每周 WoM-1MON、WOM-2MON…WeekOfMonth产生每月第一、第二、第三或第四周的星期几。例如,WoM-3FRI 表示每月第3个星期五 Q-JAN、Q-FEB…QuarterEnd对于以指定月份(JAN、FEB、MAR、APR、MAY、JUN、JUL、AUG、SEP、OCT、NOV、DEC)结束的年度,每季度最后一月的最后个日历日 BQ-JAN、BQ-FEB…BusinessQuarterEnd对于以指定月份结束的年度,每季度最后一月的最后一个工作日 QS-JAN、QS-FEB…QuarterBegin对于以指定月份结束的年度,每季度最后一月的第一个日历日 BQS-JAN、 BQS-FEB…BusinessQuarterBegin对于以指定月份结束的年度,每季度最后一月的第一个工作日 A-JAN、A-FEB…YearEnd每年指定月份(JAN、FEB、MAR、APR、MAY、JUN、JUL、AUG、SEP、 OCT、NOV、DEC)的最后一个日历日 BA-JAN、BA-FEB…BusinessYearEnd每年指定月份的最后一个工作日 AS-JAN、AS-FEB…YearBegin每年指定月份的第一个历日日 BAS-JAN、BAS-FEB…BusinessYearBegin每年指定月份的第一个工作日 【02x03】to_datetime 在 Python 中,datetime 库提供了日期和时间处理方法,利用 str 或 strftime 方法可以将 datetime 对象转化成字符串,具体用法可参见【Python 标准库学习】日期和时间处理库 — datetime。 >>> from datetime import datetime>>> stamp = datetime(2020, 6, 24)>>> stampdatetime.datetime(2020, 6, 24, 0, 0)>>>>>> str(stamp)'2020-06-24 00:00:00'>>> >>> stamp.strftime('%Y-%m-%d')'2020-06-24' 在 pandas 中 to_datetime 方法可以将字符串解析成多种不同的 Timestamp(时间戳) 对象: >>> import pandas as pd>>> datestrs = '2011-07-06 12:00:00'>>> type(datestrs)<class 'str'>>>> >>> pd.to_datetime(datestrs)Timestamp('2011-07-06 12:00:00') 基本语法: pandas.to_datetime(arg, errors='raise', dayfirst=False, yearfirst=False, utc=None, format=None, exact=True, unit=None, infer_datetime_format=False, origin='unix', cache=True) 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.to_datetime.html 常用参数: 参数描述 arg要转换为日期时间的对象,可以接受 int, float, str, datetime, list, tuple, 1-d array, Series DataFrame/dict-like 类型 errors如果字符串不满足时间戳的形式,是否会发生异常 ignore:不引发异常,返回原始输入;raise:无效解析将引发异常(默认);coerce:无效解析将被设置为NaT dayfirstbool 类型,默认 False,如果 arg 是 str 或列表,是否首先解析为日期 例如 dayfirst 为 True,10/11/12 被解析为 2012-11-10,为 False 则解析为 2012-10-11 yearfirstbool 类型,默认 False,如果 arg 是 str 或列表,是否首先解析为年份 例如 dayfirst 为 True,10/11/12 被解析为 2010-11-12,为 False 则解析为 2012-10-11 如果 dayfirst 和 yearfirst 都为 True,则优先 yearfirst utcbool 类型,是否转换为协调世界时,默认 None format格式化时间,如 21/2/20 16:10 使用 %d/%m/%y %H:%M 会被解析为 2020-02-21 16:10:00 符号含义常见文章:【Python 标准库学习】日期和时间处理库 — datetime 或者官方文档 exact如果为 True,则需要精确的格式匹配。如果为 False,则允许格式与目标字符串中的任何位置匹配 unit如果 arg 是整数或浮点数,该参数用于设置其单位(D、s、ms、us、ns) 简单应用: >>> import pandas as pd>>> obj = pd.DataFrame({'year': [2015, 2016], 'month': [2, 3], 'day': [4, 5]})>>> obj year month day0 2015 2 41 2016 3 5>>> >>> pd.to_datetime(obj)0 2015-02-041 2016-03-05dtype: datetime64[ns] 设置 format 和 errors 参数: >>> import pandas as pd>>> pd.to_datetime('13000101', format='%Y%m%d', errors='ignore')datetime.datetime(1300, 1, 1, 0, 0)>>> >>> pd.to_datetime('13000101', format='%Y%m%d', errors='coerce')NaT>>> >>> pd.to_datetime('13000101', format='%Y%m%d', errors='raise')Traceback (most recent call last):...pandas._libs.tslibs.np_datetime.OutOfBoundsDatetime: Out of bounds nanosecond timestamp: 1300-01-01 00:00:00 设置 unit 参数: >>> import pandas as pd>>> pd.to_datetime(1490195805, unit='s')Timestamp('2017-03-22 15:16:45')>>> >>> pd.to_datetime(1490195805433502912, unit='ns')Timestamp('2017-03-22 15:16:45.433502912') 【02x04】date_range pandas.date_range 方法可用于根据指定的频率生成指定长度的 DatetimeIndex。 基本语法: pandas.date_range(start=None, end=None, periods=None, freq=None, tz=None, normalize=False, name=None, closed=None, **kwargs) → pandas.core.indexes.datetimes.DatetimeIndex 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.date_range.html 参数描述 start开始日期 end结束日期 periodsint 类型,要生成的时段数(天) freq频率字符串,即按照某种特定的频率来生成日期,取值参见【02x02】freq 频率部分取值 tz设置时区,例如 “Asia/Hong_Kong” normalizebool 类型,默认 False,是否在生成日期之前对其进行规范化(仅保留年月日) name结果 DatetimeIndex 的名称 closedNone:默认值,同时保留开始日期和结束日期 'left':保留开始日期,不保留结束日期 'right':保留结束日期,不保留开始日期 简单示例: >>> import pandas as pd>>> pd.date_range(start='1/1/2018', end='1/08/2018')DatetimeIndex(['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04', '2018-01-05', '2018-01-06', '2018-01-07', '2018-01-08'], dtype='datetime64[ns]', freq='D') 指定 periods 参数: >>> import pandas as pd>>> pd.date_range(start='2012-04-01', periods=20)DatetimeIndex(['2012-04-01', '2012-04-02', '2012-04-03', '2012-04-04', '2012-04-05', '2012-04-06', '2012-04-07', '2012-04-08', '2012-04-09', '2012-04-10', '2012-04-11', '2012-04-12', '2012-04-13', '2012-04-14', '2012-04-15', '2012-04-16', '2012-04-17', '2012-04-18', '2012-04-19', '2012-04-20'], dtype='datetime64[ns]', freq='D')>>> >>> pd.date_range(end='2012-06-01', periods=20)DatetimeIndex(['2012-05-13', '2012-05-14', '2012-05-15', '2012-05-16', '2012-05-17', '2012-05-18', '2012-05-19', '2012-05-20', '2012-05-21', '2012-05-22', '2012-05-23', '2012-05-24', '2012-05-25', '2012-05-26', '2012-05-27', '2012-05-28', '2012-05-29', '2012-05-30', '2012-05-31', '2012-06-01'], dtype='datetime64[ns]', freq='D')>>>>>> pd.date_range(start='2018-04-24', end='2018-04-27', periods=3)DatetimeIndex(['2018-04-24 00:00:00', '2018-04-25 12:00:00', '2018-04-27 00:00:00'], dtype='datetime64[ns]', freq=None)>>>>>> pd.date_range(start='2018-04-24', end='2018-04-28', periods=3)DatetimeIndex(['2018-04-24', '2018-04-26', '2018-04-28'], dtype='datetime64[ns]', freq=None) 指定 freq='M' 会按照每月最后一个日历日的频率生成日期,指定 freq='3M' 会每隔3个月按照每月最后一个日历日的频率生成日期: >>> import pandas as pd>>> pd.date_range(start='1/1/2018', periods=5, freq='M')DatetimeIndex(['2018-01-31', '2018-02-28', '2018-03-31', '2018-04-30', '2018-05-31'], dtype='datetime64[ns]', freq='M')>>> >>> pd.date_range(start='1/1/2018', periods=5, freq='3M')DatetimeIndex(['2018-01-31', '2018-04-30', '2018-07-31', '2018-10-31', '2019-01-31'], dtype='datetime64[ns]', freq='3M')>>> 使用 tz 参数设置时区: >>> import pandas as pd>>> pd.date_range(start='1/1/2018', periods=5, tz='Asia/Tokyo')DatetimeIndex(['2018-01-01 00:00:00+09:00', '2018-01-02 00:00:00+09:00', '2018-01-03 00:00:00+09:00', '2018-01-04 00:00:00+09:00', '2018-01-05 00:00:00+09:00'], dtype='datetime64[ns, Asia/Tokyo]', freq='D')>>> >>> pd.date_range(start='6/24/2020', periods=5, tz='Asia/Hong_Kong')DatetimeIndex(['2020-06-24 00:00:00+08:00', '2020-06-25 00:00:00+08:00', '2020-06-26 00:00:00+08:00', '2020-06-27 00:00:00+08:00', '2020-06-28 00:00:00+08:00'], dtype='datetime64[ns, Asia/Hong_Kong]', freq='D') 设置 normalize 参数,在生成时间戳之前对其进行格式化操作: >>> import pandas as pd>>> pd.date_range('2020-06-24 12:56:31', periods=5, normalize=True)DatetimeIndex(['2020-06-24', '2020-06-25', '2020-06-26', '2020-06-27', '2020-06-28'], dtype='datetime64[ns]', freq='D') 设置 closed 参数: >>> import pandas as pd>>> pd.date_range(start='2020-06-20', end='2020-06-24', closed=None)DatetimeIndex(['2020-06-20', '2020-06-21', '2020-06-22', '2020-06-23', '2020-06-24'], dtype='datetime64[ns]', freq='D')>>> >>> pd.date_range(start='2020-06-20', end='2020-06-24', closed='left')DatetimeIndex(['2020-06-20', '2020-06-21', '2020-06-22', '2020-06-23'], dtype='datetime64[ns]', freq='D')>>> >>> pd.date_range(start='2020-06-20', end='2020-06-24', closed='right')DatetimeIndex(['2020-06-21', '2020-06-22', '2020-06-23', '2020-06-24'], dtype='datetime64[ns]', freq='D') 【02x05】索引与切片 Pandas 最基本的时间序列类型就是以时间戳(通常以 Python 字符串或 datatime 对象表示)为索引的Series,这些 datetime 对象实际上是被放在 DatetimeIndex 中的,可以使用类似 pandas.Series 对象的切片方法对其进行索引: >>> import pandas as pd>>> import numpy as np>>> dates = [datetime(2011, 1, 2), datetime(2011, 1, 5), datetime(2011, 1, 7), datetime(2011, 1, 8), datetime(2011, 1, 10), datetime(2011, 1, 12)]>>> obj = pd.Series(np.random.randn(6), index=dates)>>> >>> obj2011-01-02 -0.4071102011-01-05 -0.1866612011-01-07 -0.7310802011-01-08 0.8609702011-01-10 1.9299732011-01-12 -0.168599dtype: float64>>> >>> obj.indexDatetimeIndex(['2011-01-02', '2011-01-05', '2011-01-07', '2011-01-08', '2011-01-10', '2011-01-12'], dtype='datetime64[ns]', freq=None)>>>>>> obj.index[0]Timestamp('2011-01-02 00:00:00')>>> >>> obj.index[0:3]DatetimeIndex(['2011-01-02', '2011-01-05', '2011-01-07'], dtype='datetime64[ns]', freq=None) 另外还可以传入一个可以被解释为日期的字符串,或者只需传入“年”或“年月”即可轻松选取数据的切片: >>> import pandas as pd>>> import numpy as np>>> obj = pd.Series(np.random.randn(1000), index=pd.date_range('1/1/2000', periods=1000))>>> obj2000-01-01 -1.1422842000-01-02 1.1987852000-01-03 2.4669092000-01-04 -0.0867282000-01-05 -0.978437 ... 2002-09-22 -0.2522402002-09-23 0.1485612002-09-24 -1.3304092002-09-25 -0.6734712002-09-26 -0.253271Freq: D, Length: 1000, dtype: float64>>> >>> obj['26/9/2002']-0.25327100684233356>>> >>> obj['2002']2002-01-01 1.0587152002-01-02 0.9008592002-01-03 1.9935082002-01-04 -0.1032112002-01-05 -0.950090 ... 2002-09-22 -0.2522402002-09-23 0.1485612002-09-24 -1.3304092002-09-25 -0.6734712002-09-26 -0.253271Freq: D, Length: 269, dtype: float64>>> >>> obj['2002-09']2002-09-01 -0.9955282002-09-02 0.5015282002-09-03 -0.4867532002-09-04 -1.0839062002-09-05 1.4589752002-09-06 -1.3316852002-09-07 0.1953382002-09-08 -0.4296132002-09-09 1.1258232002-09-10 1.6070512002-09-11 0.5303872002-09-12 -0.0159382002-09-13 1.7810432002-09-14 -0.2771232002-09-15 0.3445692002-09-16 -1.0108102002-09-17 0.4630012002-09-18 1.8836362002-09-19 0.2745202002-09-20 0.6241842002-09-21 -1.2030572002-09-22 -0.2522402002-09-23 0.1485612002-09-24 -1.3304092002-09-25 -0.6734712002-09-26 -0.253271Freq: D, dtype: float64>>> >>> obj['20/9/2002':'26/9/2002']2002-09-20 0.6241842002-09-21 -1.2030572002-09-22 -0.2522402002-09-23 0.1485612002-09-24 -1.3304092002-09-25 -0.6734712002-09-26 -0.253271Freq: D, dtype: float64 【02x06】移动数据与数据偏移 移动(shifting)指的是沿着时间轴将数据前移或后移。Series 和 DataFrame 都有一个 shift 方法用于执行单纯的前移或后移操作,保持索引不变: >>> import pandas as pd>>> import numpy as np>>> obj = pd.Series(np.random.randn(4), index=pd.date_range('1/1/2000', periods=4, freq='M'))>>> obj2000-01-31 -0.1002172000-02-29 1.1778342000-03-31 -0.6443532000-04-30 -1.954679Freq: M, dtype: float64>>> >>> obj.shift(2)2000-01-31 NaN2000-02-29 NaN2000-03-31 -0.1002172000-04-30 1.177834Freq: M, dtype: float64>>> >>> obj.shift(-2)2000-01-31 -0.6443532000-02-29 -1.9546792000-03-31 NaN2000-04-30 NaNFreq: M, dtype: float64 因为简单的移位操作不会修改索引,所以部分数据会被丢弃并引入 NaN(缺失值)。因此,如果频率已知,则可以将其传给 shift 以便实现对时间戳进行位移而不是对数据进行简单位移: >>> import pandas as pd>>> import numpy as np>>> obj = pd.Series(np.random.randn(4), index=pd.date_range('1/1/2000', periods=4, freq='M'))>>> obj2000-01-31 -0.1002172000-02-29 1.1778342000-03-31 -0.6443532000-04-30 -1.954679Freq: M, dtype: float64>>> >>> obj.shift(2, freq='M')2000-03-31 -0.1002172000-04-30 1.1778342000-05-31 -0.6443532000-06-30 -1.954679Freq: M, dtype: float64 Pandas 中的频率是由一个基础频率(base frequency)和一个乘数组成的。基础频率通常以一个字符串别名表示,比如 "M" 表示每月,"H" 表示每小时。对于每个基础频率,都有一个被称为日期偏移量(date offset)的对象与之对应。例如,按小时计算的频率可以用 Hour 类表示: >>> from pandas.tseries.offsets import Hour, Minute>>> hour = Hour()>>> hour<Hour>>>> >>> four_hours = Hour(4)>>> four_hours<4 * Hours> 一般来说,无需明确创建这样的对象,只需使用诸如 "H" 或 "4H" 这样的字符串别名即可。在基础频率前面放上一个整数即可创建倍数: >>> import pandas as pd>>> pd.date_range('2000-01-01', '2000-01-03 23:59', freq='4h')DatetimeIndex(['2000-01-01 00:00:00', '2000-01-01 04:00:00', '2000-01-01 08:00:00', '2000-01-01 12:00:00', '2000-01-01 16:00:00', '2000-01-01 20:00:00', '2000-01-02 00:00:00', '2000-01-02 04:00:00', '2000-01-02 08:00:00', '2000-01-02 12:00:00', '2000-01-02 16:00:00', '2000-01-02 20:00:00', '2000-01-03 00:00:00', '2000-01-03 04:00:00', '2000-01-03 08:00:00', '2000-01-03 12:00:00', '2000-01-03 16:00:00', '2000-01-03 20:00:00'], dtype='datetime64[ns]', freq='4H') 大部分偏移量对象都可通过加法进行连接: >>> from pandas.tseries.offsets import Hour, Minute>>> Hour(2) + Minute(30)<150 * Minutes> 对于 freq 参数也可以传入频率字符串(如 "2h30min"),这种字符串可以被高效地解析为等效的表达式: >>> import pandas as pd>>> pd.date_range('2000-01-01', periods=10, freq='1h30min')DatetimeIndex(['2000-01-01 00:00:00', '2000-01-01 01:30:00', '2000-01-01 03:00:00', '2000-01-01 04:30:00', '2000-01-01 06:00:00', '2000-01-01 07:30:00', '2000-01-01 09:00:00', '2000-01-01 10:30:00', '2000-01-01 12:00:00', '2000-01-01 13:30:00'], dtype='datetime64[ns]', freq='90T') 这种偏移量还可以用在 datetime 或 Timestamp 对象上: >>> from pandas.tseries.offsets import Day, MonthEnd>>> now = datetime(2011, 11, 17)>>> now + 3 * Day()Timestamp('2011-11-20 00:00:00') 如果加的是锚点偏移量,比如 MonthEnd,第一次增量会将原日期向前滚动到符合频率规则的下一个日期: >>> from pandas.tseries.offsets import Day, MonthEnd>>> now = datetime(2011, 11, 17)>>> now + MonthEnd()Timestamp('2011-11-30 00:00:00')>>> now + MonthEnd(2)Timestamp('2011-12-31 00:00:00') 通过锚点偏移量的 rollforward 和 rollback 方法,可明确地将日期向前或向后滚动: >>> from pandas.tseries.offsets import Day, MonthEnd>>> now = datetime(2011, 11, 17)>>> offset = MonthEnd()>>> offset.rollforward(now)Timestamp('2011-11-30 00:00:00')>>> offset.rollback(now)Timestamp('2011-10-31 00:00:00') 与 groupby 方法结合使用: >>> import pandas as pd>>> import numpy as np>>> from pandas.tseries.offsets import Day, MonthEnd>>> obj = pd.Series(np.random.randn(20), index=pd.date_range('1/15/2000', periods=20, freq='4d'))>>> obj2000-01-15 -0.5917292000-01-19 -0.7758442000-01-23 -0.7456032000-01-27 -0.0764392000-01-31 1.7964172000-02-04 -0.5003492000-02-08 0.5158512000-02-12 -0.3441712000-02-16 0.4196572000-02-20 0.3072882000-02-24 0.1151132000-02-28 -0.3625852000-03-03 1.0748922000-03-07 1.1113662000-03-11 0.9499102000-03-15 -1.5357272000-03-19 0.5459442000-03-23 -0.8101392000-03-27 -1.2606272000-03-31 -0.128403Freq: 4D, dtype: float64>>>>>> offset = MonthEnd()>>> obj.groupby(offset.rollforward).mean()2000-01-31 -0.0786402000-02-29 0.0215432000-03-31 -0.006598dtype: float64 【02x07】时区处理 在 Python 中,时区信息来自第三方库 pytz,使用 pytz.common_timezones 方法可以查看所有的时区名称,使用 pytz.timezone 方法从 pytz 中获取时区对象: >>> import pytz>>> pytz.common_timezones['Africa/Abidjan', 'Africa/Accra', 'Africa/Addis_Ababa', ..., 'UTC']>>>>>> tz = pytz.timezone('Asia/Shanghai')>>> tz<DstTzInfo 'Asia/Shanghai' LMT+8:06:00 STD> # 表示与 UTC 时间相差8小时6分 在 date_range 方法中,tz 参数用于指定时区,默认为 None,可以使用 tz_localize 方法将其进行本地化时区转换,如下示例中,将无时区转本地化 UTC 时区: >>> import pandas as pd>>> import numpy as np>>> rng = pd.date_range('3/9/2012 9:30', periods=6, freq='D')>>> ts = pd.Series(np.random.randn(len(rng)), index=rng)>>> ts2012-03-09 09:30:00 -1.5279132012-03-10 09:30:00 -1.1161012012-03-11 09:30:00 0.3593582012-03-12 09:30:00 -0.4759202012-03-13 09:30:00 -0.3365702012-03-14 09:30:00 -1.075952Freq: D, dtype: float64>>> >>> print(ts.index.tz)None>>> >>> ts_utc = ts.tz_localize('UTC')>>> ts_utc2012-03-09 09:30:00+00:00 -1.5279132012-03-10 09:30:00+00:00 -1.1161012012-03-11 09:30:00+00:00 0.3593582012-03-12 09:30:00+00:00 -0.4759202012-03-13 09:30:00+00:00 -0.3365702012-03-14 09:30:00+00:00 -1.075952Freq: D, dtype: float64>>>>>> ts_utc.indexDatetimeIndex(['2012-03-09 09:30:00+00:00', '2012-03-10 09:30:00+00:00', '2012-03-11 09:30:00+00:00', '2012-03-12 09:30:00+00:00', '2012-03-13 09:30:00+00:00', '2012-03-14 09:30:00+00:00'], dtype='datetime64[ns, UTC]', freq='D') 时间序列被本地化到某个特定时区后,就可以用 tz_convert 方法将其转换到别的时区了: >>> import pandas as pd>>> import numpy as np>>> rng = pd.date_range('3/9/2012 9:30', periods=6, freq='D')>>> ts = pd.Series(np.random.randn(len(rng)), index=rng)>>> ts2012-03-09 09:30:00 0.4803032012-03-10 09:30:00 -1.4610392012-03-11 09:30:00 -1.5127492012-03-12 09:30:00 -2.1854212012-03-13 09:30:00 1.6578452012-03-14 09:30:00 0.175633Freq: D, dtype: float64>>>>>> ts.tz_localize('UTC').tz_convert('Asia/Shanghai')2012-03-09 17:30:00+08:00 0.4803032012-03-10 17:30:00+08:00 -1.4610392012-03-11 17:30:00+08:00 -1.5127492012-03-12 17:30:00+08:00 -2.1854212012-03-13 17:30:00+08:00 1.6578452012-03-14 17:30:00+08:00 0.175633Freq: D, dtype: float64 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106947061未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【03x00】period 固定时期 【03x01】pandas.Period 固定时期(period)表示的是时间区间,比如数日、数月、数季、数年等。Period 类所表示的就是这种数据类型,其构造函数需要用到一个字符串或整数。 基本语法: class pandas.Period(value=None, freq=None, ordinal=None, year=None, month=None, quarter=None, day=None, hour=None, minute=None, second=None) 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.Period.html 常用参数: 参数描述 value时间段 freq时间戳将具有的偏移量,可以是 str,日期偏移量类型,取值参见【02x02】freq 频率部分取值 以下示例中,Period 对象表示的是从2020年1月1日到2020年12月31日之间的整段时间 >>> import pandas as pd>>> pd.Period(2020, freq='A-DEC')Period('2020', 'A-DEC') 利用加减法对其按照频率进行位移: >>> import pandas as pd>>> obj = pd.Period(2020, freq='A-DEC')>>> objPeriod('2020', 'A-DEC')>>> >>> obj + 5Period('2025', 'A-DEC')>>> >>> obj - 5Period('2015', 'A-DEC') PeriodIndex 类保存了一组 Period,它可以在任何 pandas 数据结构中被用作轴索引: >>> import pandas as pd>>> import numpy as np>>> rng = [pd.Period('2000-01'), pd.Period('2000-02'), pd.Period('2000-03'), pd.Period('2000-04'), pd.Period('2000-05'), pd.Period('2000-06')]>>> obj = pd.Series(np.random.randn(6), index=rng)>>> obj2000-01 0.2290922000-02 1.5154982000-03 -0.3344012000-04 -0.4926812000-05 -2.0128182000-06 0.338804Freq: M, dtype: float64>>> >>> obj.indexPeriodIndex(['2000-01', '2000-02', '2000-03', '2000-04', '2000-05', '2000-06'], dtype='period[M]', freq='M') >>> import pandas as pd>>> values = ['2001Q3', '2002Q2', '2003Q1']>>> index = pd.PeriodIndex(values, freq='Q-DEC')>>> indexPeriodIndex(['2001Q3', '2002Q2', '2003Q1'], dtype='period[Q-DEC]', freq='Q-DEC')>>> 【03x02】period_range pandas.period_range 方法可根据指定的频率生成指定长度的 PeriodIndex。 基本语法: pandas.period_range(start=None, end=None, periods=None, freq=None, name=None) → pandas.core.indexes.period.PeriodIndex 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.period_range.html 常用参数: 参数描述 start起始日期 end结束日期 periods要生成的时段数 freq时间戳将具有的偏移量,可以是 str,日期偏移量类型,取值参见【02x02】freq 频率部分取值 name结果 PeriodIndex 对象名称 简单应用: >>> import pandas as pd>>> pd.period_range(start='2019-01-01', end='2020-01-01', freq='M')PeriodIndex(['2019-01', '2019-02', '2019-03', '2019-04', '2019-05', '2019-06', '2019-07', '2019-08', '2019-09', '2019-10', '2019-11', '2019-12', '2020-01'], dtype='period[M]', freq='M')>>>>>> pd.period_range(start=pd.Period('2017Q1', freq='Q'), end=pd.Period('2017Q2', freq='Q'), freq='M')PeriodIndex(['2017-03', '2017-04', '2017-05', '2017-06'], dtype='period[M]', freq='M') 【03x03】asfreq 时期频率转换 Period 和 PeriodIndex 对象都可以通过 asfreq 方法被转换成别的频率。 基本语法:PeriodIndex.asfreq(self, *args, **kwargs) 常用参数: 参数描述 freq新的频率(偏移量),取值参见【02x02】freq 频率部分取值 how按照开始或者结束对齐,'E' or 'END' or 'FINISH';'S' or 'START' or 'BEGIN' 应用示例: >>> import pandas as pd>>> pidx = pd.period_range('2010-01-01', '2015-01-01', freq='A')>>> pidxPeriodIndex(['2010', '2011', '2012', '2013', '2014', '2015'], dtype='period[A-DEC]', freq='A-DEC')>>> >>> pidx.asfreq('M')PeriodIndex(['2010-12', '2011-12', '2012-12', '2013-12', '2014-12', '2015-12'], dtype='period[M]', freq='M')>>> >>> pidx.asfreq('M', how='S')PeriodIndex(['2010-01', '2011-01', '2012-01', '2013-01', '2014-01', '2015-01'], dtype='period[M]', freq='M') 【03x04】to_period 与 to_timestamp() to_period 方法可以将 Timestamp(时间戳) 转换为 Period(固定时期); to_timestamp 方法可以将 Period(固定时期)转换为 Timestamp(时间戳) 。 >>> import pandas as pd>>> rng = pd.date_range('2000-01-01', periods=3, freq='M')>>> ts = pd.Series(np.random.randn(3), index=rng)>>> ts2000-01-31 0.2207592000-02-29 -0.1082212000-03-31 0.819433Freq: M, dtype: float64>>> >>> pts = ts.to_period()>>> pts2000-01 0.2207592000-02 -0.1082212000-03 0.819433Freq: M, dtype: float64>>> >>> pts2 = pts.to_timestamp()>>> pts22000-01-01 0.2207592000-02-01 -0.1082212000-03-01 0.819433Freq: MS, dtype: float64>>> >>> ts.indexDatetimeIndex(['2000-01-31', '2000-02-29', '2000-03-31'], dtype='datetime64[ns]', freq='M')>>> >>> pts.indexPeriodIndex(['2000-01', '2000-02', '2000-03'], dtype='period[M]', freq='M')>>> >>> pts2.indexDatetimeIndex(['2000-01-01', '2000-02-01', '2000-03-01'], dtype='datetime64[ns]', freq='MS') 【04x00】timedelta 时间间隔 【04x01】pandas.Timedelta Timedelta 表示持续时间,即两个日期或时间之间的差。 Timedelta 相当于 Python 的 datetime.timedelta,在大多数情况下两者可以互换。 基本语法:class pandas.Timedelta(value=<object object>, unit=None, **kwargs) 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.Timedelta.html 常用参数: 参数描述 value传入的值,可以是 Timedelta,timedelta,np.timedelta64,string 或 integer 对象 unit用于设置 value 的单位,具体取值参见官方文档 表示两个 datetime 对象之间的时间差: >>> import pandas as pd>>> pd.to_datetime('2020-6-24') - pd.to_datetime('2016-1-1')Timedelta('1636 days 00:00:00') 通过字符串传递参数: >>> import pandas as pd>>> pd.Timedelta('3 days 3 hours 3 minutes 30 seconds')Timedelta('3 days 03:03:30') 通过整数传递参数: >>> import pandas as pd>>> pd.Timedelta(5,unit='h')Timedelta('0 days 05:00:00') 获取属性: >>> import pandas as pd>>> obj = pd.Timedelta('3 days 3 hours 3 minutes 30 seconds')>>> objTimedelta('3 days 03:03:30')>>> >>> obj.days3>>> obj.seconds11010 【04x02】to_timedelta to_timedelta 方法可以将传入的对象转换成 timedelta 对象。 基本语法:pandas.to_timedelta(arg, unit='ns', errors='raise') 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.to_timedelta.html 常用参数: 参数描述 arg要转换为 timedelta 的对象,可以是 str,timedelta,list-like 或 Series 对象 unit用于设置 arg 的单位,具体取值参见官方文档 errors如果 arg 不满足时间戳的形式,是否会发生异常 ignore:不引发异常,返回原始输入;raise:无效解析将引发异常(默认);coerce:无效解析将被设置为NaT 将单个字符串解析为 timedelta 对象: >>> import pandas as pd>>> pd.to_timedelta('1 days 06:05:01.00003')Timedelta('1 days 06:05:01.000030')>>>>>> pd.to_timedelta('15.5us')Timedelta('0 days 00:00:00.000015') 将字符串列表或数组解析为 timedelta 对象: >>> import pandas as pd>>> pd.to_timedelta(['1 days 06:05:01.00003', '15.5us', 'nan'])TimedeltaIndex(['1 days 06:05:01.000030', '0 days 00:00:00.000015', NaT], dtype='timedelta64[ns]', freq=None) 指定 unit 参数: >>> import pandas as pd>>> pd.to_timedelta(np.arange(5), unit='s')TimedeltaIndex(['00:00:00', '00:00:01', '00:00:02', '00:00:03', '00:00:04'], dtype='timedelta64[ns]', freq=None)>>> >>> pd.to_timedelta(np.arange(5), unit='d')TimedeltaIndex(['0 days', '1 days', '2 days', '3 days', '4 days'], dtype='timedelta64[ns]', freq=None) 【04x03】timedelta_range timedelta_range 方法可根据指定的频率生成指定长度的 TimedeltaIndex。 基本语法: pandas.timedelta_range(start=None, end=None, periods=None, freq=None, name=None, closed=None) → pandas.core.indexes.timedeltas.TimedeltaIndex 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.timedelta_range.html 常用参数: 参数描述 start开始日期 end结束日期 periodsint 类型,要生成的时段数 freq频率字符串,即按照某种特定的频率来生成日期,取值参见【02x02】freq 频率部分取值 name结果 TimedeltaIndex 的名称 closedNone:默认值,同时保留开始日期和结束日期 'left':保留开始日期,不保留结束日期 'right':保留结束日期,不保留开始日期 应用示例: >>> import pandas as pd>>> pd.timedelta_range(start='1 day', periods=4)TimedeltaIndex(['1 days', '2 days', '3 days', '4 days'], dtype='timedelta64[ns]', freq='D') closed 参数指定保留哪个端点。默认保留两个端点: >>> import pandas as pd>>> pd.timedelta_range(start='1 day', periods=4, closed='right')TimedeltaIndex(['2 days', '3 days', '4 days'], dtype='timedelta64[ns]', freq='D') freq 参数指定 TimedeltaIndex 的频率。只接受固定频率,非固定频率如 'M' 将会报错: >>> import pandas as pd>>> pd.timedelta_range(start='1 day', end='2 days', freq='6H')TimedeltaIndex(['1 days 00:00:00', '1 days 06:00:00', '1 days 12:00:00', '1 days 18:00:00', '2 days 00:00:00'], dtype='timedelta64[ns]', freq='6H')>>> >>> pd.timedelta_range(start='1 day', end='2 days', freq='M')Traceback (most recent call last):...ValueError: <MonthEnd> is a non-fixed frequency 【05x00】重采样及频率转换 重采样(resampling)指的是将时间序列从一个频率转换到另一个频率的处理过程。将高频率数据聚合到低频率称为降采样(downsampling),而将低频率数据转换到高频率则称为升采样(upsampling)。并不是所有的重采样都能被划分到这两个大类中。例如,将 W-WED(每周三)转换为 W-FRI 既不是降采样也不是升采样。 Pandas 中提供了 resample 方法来帮助我们实现重采样。Pandas 对象都带有一个 resample 方法,它是各种频率转换工作的主力函数。 基本语法: Series.resample(self, rule, axis=0, closed: Union[str, NoneType] = None, label: Union[str, NoneType] = None, convention: str = 'start', kind: Union[str, NoneType] = None, loffset=None, base: int = 0, on=None, level=None) DataFrame.resample(self, rule, axis=0, closed: Union[str, NoneType] = None, label: Union[str, NoneType] = None, convention: str = 'start', kind: Union[str, NoneType] = None, loffset=None, base: int = 0, on=None, level=None) 常用参数: 参数描述 rule axis重采样的轴,默认 0 closed在重采样中,各时间段的哪一端是闭合(即包含)的, 除 'M'、'A'、'Q'、'BM'、'BA'、'BQ' 和 'W' 默认值为 ‘right’ 外,其他默认值为 'left‘ label在重采样中,如何设置聚合值的标签, right 或 left,默认为 None, 例如,9:30 到 9:35 之间的这 5 分钟会被标记为 9:30 或 9:35 convention仅用于 PeriodIndex(固定时期),对周期进行重采样,'start' or 's','end' or 'e' on对于 DataFrame 对象,可用该参数指定重采样后的数据的 index(行索引) 为原数据中的某列 level对于具有层级索引(MultiIndex)的 DataFrame 对象,可以使用该参数来指定需要在哪个级别上进行重新采样 将序列重采样到三分钟的频率,并将每个频率的值相加: >>> import pandas as pd>>> index = pd.date_range('1/1/2000', periods=9, freq='T')>>> series = pd.Series(range(9), index=index)>>> series2000-01-01 00:00:00 02000-01-01 00:01:00 12000-01-01 00:02:00 22000-01-01 00:03:00 32000-01-01 00:04:00 42000-01-01 00:05:00 52000-01-01 00:06:00 62000-01-01 00:07:00 72000-01-01 00:08:00 8Freq: T, dtype: int64>>> >>> series.resample('3T').sum()2000-01-01 00:00:00 32000-01-01 00:03:00 122000-01-01 00:06:00 21Freq: 3T, dtype: int64 设置 label='right',即每个索引 index 会使用靠右侧(较大值)的标签: >>> import pandas as pd>>> index = pd.date_range('1/1/2000', periods=9, freq='T')>>> series = pd.Series(range(9), index=index)>>> series2000-01-01 00:00:00 02000-01-01 00:01:00 12000-01-01 00:02:00 22000-01-01 00:03:00 32000-01-01 00:04:00 42000-01-01 00:05:00 52000-01-01 00:06:00 62000-01-01 00:07:00 72000-01-01 00:08:00 8Freq: T, dtype: int64>>> >>> series.resample('3T', label='right').sum()2000-01-01 00:03:00 32000-01-01 00:06:00 122000-01-01 00:09:00 21Freq: 3T, dtype: int64 设置 closed='right',即结果中会包含原数据中最右侧(较大)的值: >>> import pandas as pd>>> index = pd.date_range('1/1/2000', periods=9, freq='T')>>> series = pd.Series(range(9), index=index)>>> series2000-01-01 00:00:00 02000-01-01 00:01:00 12000-01-01 00:02:00 22000-01-01 00:03:00 32000-01-01 00:04:00 42000-01-01 00:05:00 52000-01-01 00:06:00 62000-01-01 00:07:00 72000-01-01 00:08:00 8Freq: T, dtype: int64>>> >>> series.resample('3T', label='right', closed='right').sum()2000-01-01 00:00:00 02000-01-01 00:03:00 62000-01-01 00:06:00 152000-01-01 00:09:00 15Freq: 3T, dtype: int64 以下示例将序列重采样到30秒的频率,asfreq()[0:5] 用于选择前5行数据: >>> import pandas as pd>>> index = pd.date_range('1/1/2000', periods=9, freq='T')>>> series = pd.Series(range(9), index=index)>>> series2000-01-01 00:00:00 02000-01-01 00:01:00 12000-01-01 00:02:00 22000-01-01 00:03:00 32000-01-01 00:04:00 42000-01-01 00:05:00 52000-01-01 00:06:00 62000-01-01 00:07:00 72000-01-01 00:08:00 8Freq: T, dtype: int64>>> >>> series.resample('30S').asfreq()[0:5]2000-01-01 00:00:00 0.02000-01-01 00:00:30 NaN2000-01-01 00:01:00 1.02000-01-01 00:01:30 NaN2000-01-01 00:02:00 2.0Freq: 30S, dtype: float64 使用 pad 方法向后填充缺失值(NaN): >>> import pandas as pd>>> index = pd.date_range('1/1/2000', periods=9, freq='T')>>> series = pd.Series(range(9), index=index)>>> series2000-01-01 00:00:00 02000-01-01 00:01:00 12000-01-01 00:02:00 22000-01-01 00:03:00 32000-01-01 00:04:00 42000-01-01 00:05:00 52000-01-01 00:06:00 62000-01-01 00:07:00 72000-01-01 00:08:00 8Freq: T, dtype: int64>>> >>> series.resample('30S').pad()[0:5]2000-01-01 00:00:00 02000-01-01 00:00:30 02000-01-01 00:01:00 12000-01-01 00:01:30 12000-01-01 00:02:00 2Freq: 30S, dtype: int64 使用 bfill 方法向前填充缺失值(NaN): >>> import pandas as pd>>> index = pd.date_range('1/1/2000', periods=9, freq='T')>>> series = pd.Series(range(9), index=index)>>> series2000-01-01 00:00:00 02000-01-01 00:01:00 12000-01-01 00:02:00 22000-01-01 00:03:00 32000-01-01 00:04:00 42000-01-01 00:05:00 52000-01-01 00:06:00 62000-01-01 00:07:00 72000-01-01 00:08:00 8Freq: T, dtype: int64>>> >>> series.resample('30S').bfill()[0:5]2000-01-01 00:00:00 02000-01-01 00:00:30 12000-01-01 00:01:00 12000-01-01 00:01:30 22000-01-01 00:02:00 2Freq: 30S, dtype: int64 通过 apply 方法传递自定义函数: >>> import pandas as pd>>> index = pd.date_range('1/1/2000', periods=9, freq='T')>>> series = pd.Series(range(9), index=index)>>> series2000-01-01 00:00:00 02000-01-01 00:01:00 12000-01-01 00:02:00 22000-01-01 00:03:00 32000-01-01 00:04:00 42000-01-01 00:05:00 52000-01-01 00:06:00 62000-01-01 00:07:00 72000-01-01 00:08:00 8Freq: T, dtype: int64>>> >>> def custom_resampler(array_like): return np.sum(array_like) + 5>>> series.resample('3T').apply(custom_resampler)2000-01-01 00:00:00 82000-01-01 00:03:00 172000-01-01 00:06:00 26Freq: 3T, dtype: int64 convention 参数的应用: >>> import pandas as pd>>> s = pd.Series([1, 2], index=pd.period_range('2012-01-01', freq='A', periods=2))>>> s2012 12013 2Freq: A-DEC, dtype: int64>>> >>> s.resample('Q', convention='start').asfreq()2012Q1 1.02012Q2 NaN2012Q3 NaN2012Q4 NaN2013Q1 2.02013Q2 NaN2013Q3 NaN2013Q4 NaNFreq: Q-DEC, dtype: float64>>> >>> s.resample('Q', convention='end').asfreq()2012Q4 1.02013Q1 NaN2013Q2 NaN2013Q3 NaN2013Q4 2.0Freq: Q-DEC, dtype: float64 >>> import pandas as pd>>> q = pd.Series([1, 2, 3, 4], index=pd.period_range('2018-01-01', freq='Q', periods=4))>>> q2018Q1 12018Q2 22018Q3 32018Q4 4Freq: Q-DEC, dtype: int64>>> >>> q.resample('M', convention='end').asfreq()2018-03 1.02018-04 NaN2018-05 NaN2018-06 2.02018-07 NaN2018-08 NaN2018-09 3.02018-10 NaN2018-11 NaN2018-12 4.0Freq: M, dtype: float64>>> >>> q.resample('M', convention='start').asfreq()2018-01 1.02018-02 NaN2018-03 NaN2018-04 2.02018-05 NaN2018-06 NaN2018-07 3.02018-08 NaN2018-09 NaN2018-10 4.02018-11 NaN2018-12 NaNFreq: M, dtype: float64 对于 DataFrame 对象,可以使用关键字 on 来指定原数据中的某列为重采样后数据的行索引: >>> import pandas as pd>>> d = dict({'price': [10, 11, 9, 13, 14, 18, 17, 19], 'volume': [50, 60, 40, 100, 50, 100, 40, 50]})>>> df = pd.DataFrame(d)>>> df['week_starting'] = pd.date_range('01/01/2018', periods=8, freq='W')>>> df price volume week_starting0 10 50 2018-01-071 11 60 2018-01-142 9 40 2018-01-213 13 100 2018-01-284 14 50 2018-02-045 18 100 2018-02-116 17 40 2018-02-187 19 50 2018-02-25>>> >>> df.resample('M', on='week_starting').mean() price volumeweek_starting 2018-01-31 10.75 62.52018-02-28 17.00 60.0 对于具有层级索引(MultiIndex)的 DataFrame 对象,可以使用关键字 level 来指定需要在哪个级别上进行重新采样: >>> import pandas as pd>>> days = pd.date_range('1/1/2000', periods=4, freq='D')>>> d2 = dict({'price': [10, 11, 9, 13, 14, 18, 17, 19], 'volume': [50, 60, 40, 100, 50, 100, 40, 50]})>>> df2 = pd.DataFrame(d2, index=pd.MultiIndex.from_product([days, ['morning', 'afternoon']]))>>> df2 price volume2000-01-01 morning 10 50 afternoon 11 602000-01-02 morning 9 40 afternoon 13 1002000-01-03 morning 14 50 afternoon 18 1002000-01-04 morning 17 40 afternoon 19 50>>> >>> df2.resample('D', level=0).sum() price volume2000-01-01 21 1102000-01-02 22 1402000-01-03 32 1502000-01-04 36 90 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106947061未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【01x00】数据重塑 【01x01】stack 【01x02】unstack 【02x00】重复数据处理 【02x01】duplicated 【02x02】drop_duplicates 【03x00】数据替换 【03x01】replace 【03x02】where 【03x03】mask Pandas 系列文章: Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象 Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作 Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理 Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引 Python 数据分析三剑客之 Pandas(五):统计计算与统计描述 Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并 Python 数据分析三剑客之 Pandas(七):合并数据集 Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换 Python 数据分析三剑客之 Pandas(九):时间序列 Python 数据分析三剑客之 Pandas(十):数据读写 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106900748未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【01x00】数据重塑 有许多用于重新排列表格型数据的基础运算。这些函数也称作重塑(reshape)或轴向旋转(pivot)运算。重塑层次化索引主要有以下两个方法: stack:将数据的列转换成行; unstack:将数据的行转换成列。 【01x01】stack stack 方法用于将数据的列转换成为行; 基本语法:DataFrame.stack(self, level=-1, dropna=True) 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.stack.html 参数描述 level从列转换到行,指定不同层级的列索引或列标签、由列索引或列标签组成的数组,默认-1 dropnabool 类型,是否删除重塑后数据中所有值为 NaN 的行,默认 True 单层列(Single level columns): >>> import pandas as pd>>> obj = pd.DataFrame([[0, 1], [2, 3]], index=['cat', 'dog'], columns=['weight', 'height'])>>> obj weight heightcat 0 1dog 2 3>>> >>> obj.stack()cat weight 0 height 1dog weight 2 height 3dtype: int64 多层列(Multi level columns): >>> import pandas as pd>>> multicol = pd.MultiIndex.from_tuples([('weight', 'kg'), ('weight', 'pounds')])>>> obj = pd.DataFrame([[1, 2], [2, 4]], index=['cat', 'dog'], columns=multicol)>>> obj weight kg poundscat 1 2dog 2 4>>> >>> obj.stack() weightcat kg 1 pounds 2dog kg 2 pounds 4 缺失值填充: >>> import pandas as pd>>> multicol = pd.MultiIndex.from_tuples([('weight', 'kg'), ('height', 'm')])>>> obj = pd.DataFrame([[1.0, 2.0], [3.0, 4.0]], index=['cat', 'dog'], columns=multicol)>>> obj weight height kg mcat 1.0 2.0dog 3.0 4.0>>> >>> obj.stack() height weightcat kg NaN 1.0 m 2.0 NaNdog kg NaN 3.0 m 4.0 NaN 通过 level 参数指定不同层级的轴进行重塑: >>> import pandas as pd>>> multicol = pd.MultiIndex.from_tuples([('weight', 'kg'), ('height', 'm')])>>> obj = pd.DataFrame([[1.0, 2.0], [3.0, 4.0]], index=['cat', 'dog'], columns=multicol)>>> obj weight height kg mcat 1.0 2.0dog 3.0 4.0>>> >>> obj.stack(level=0) kg mcat height NaN 2.0 weight 1.0 NaNdog height NaN 4.0 weight 3.0 NaN>>> >>> obj.stack(level=1) height weightcat kg NaN 1.0 m 2.0 NaNdog kg NaN 3.0 m 4.0 NaN>>>>>> obj.stack(level=[0, 1])cat height m 2.0 weight kg 1.0dog height m 4.0 weight kg 3.0dtype: float64 对于重塑后的数据,若有一行的值均为 NaN,则默认会被删除,可以设置 dropna=False 来保留缺失值: >>> import pandas as pd>>> multicol = pd.MultiIndex.from_tuples([('weight', 'kg'), ('height', 'm')])>>> obj = pd.DataFrame([[None, 1.0], [2.0, 3.0]], index=['cat', 'dog'], columns=multicol)>>> obj weight height kg mcat NaN 1.0dog 2.0 3.0>>> >>> obj.stack(dropna=False) height weightcat kg NaN NaN m 1.0 NaNdog kg NaN 2.0 m 3.0 NaN>>> >>> obj.stack(dropna=True) height weightcat m 1.0 NaNdog kg NaN 2.0 m 3.0 NaN 【01x02】unstack unstack:将数据的行转换成列。 基本语法: Series.unstack(self, level=-1, fill_value=None) DataFrame.unstack(self, level=-1, fill_value=None) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.unstack.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.unstack.html 参数描述 level从行转换到列,指定不同层级的行索引,默认-1 fill_value用于替换 NaN 的值 在 Series 对象中的应用: >>> import pandas as pd>>> obj = pd.Series([1, 2, 3, 4], index=pd.MultiIndex.from_product([['one', 'two'], ['a', 'b']]))>>> objone a 1 b 2two a 3 b 4dtype: int64>>> >>> obj.unstack() a bone 1 2two 3 4>>> >>> obj.unstack(level=0) one twoa 1 3b 2 4 和 stack 方法类似,如果值不存在将会引入缺失值(NaN): >>> import pandas as pd>>> obj1 = pd.Series([0, 1, 2, 3], index=['a', 'b', 'c', 'd'])>>> obj2 = pd.Series([4, 5, 6], index=['c', 'd', 'e'])>>> obj3 = pd.concat([obj1, obj2], keys=['one', 'two'])>>> obj3one a 0 b 1 c 2 d 3two c 4 d 5 e 6dtype: int64>>> >>> obj3.unstack() a b c d eone 0.0 1.0 2.0 3.0 NaNtwo NaN NaN 4.0 5.0 6.0 在 DataFrame 对象中的应用: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame(np.arange(6).reshape((2, 3)), index=pd.Index(['Ohio','Colorado'], name='state'), columns=pd.Index(['one', 'two', 'three'], name='number'))>>> objnumber one two threestate Ohio 0 1 2Colorado 3 4 5>>> >>> obj2 = obj.stack()>>> obj2state numberOhio one 0 two 1 three 2Colorado one 3 two 4 three 5dtype: int32>>> >>> obj3 = pd.DataFrame({'left': obj2, 'right': obj2 + 5}, columns=pd.Index(['left', 'right'], name='side'))>>> obj3side left rightstate number Ohio one 0 5 two 1 6 three 2 7Colorado one 3 8 two 4 9 three 5 10>>> >>> obj3.unstack('state')side left right state Ohio Colorado Ohio Coloradonumber one 0 3 5 8two 1 4 6 9three 2 5 7 10>>> >>> obj3.unstack('state').stack('side')state Colorado Ohionumber side one left 3 0 right 8 5two left 4 1 right 9 6three left 5 2 right 10 7 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106900748未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【02x00】重复数据处理 duplicated:判断是否为重复值; drop_duplicates:删除重复值。 【02x01】duplicated duplicated 方法可以判断值是否为重复数据。 基本语法: Series.duplicated(self, keep='first') DataFrame.duplicated(self, subset: Union[Hashable, Sequence[Hashable], NoneType] = None, keep: Union[str, bool] = 'first') → ’Series’ 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.duplicated.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.duplicated.html 参数描述 keep标记重复项的方法,默认 'first' 'first':将非重复项和第一个重复项标记为 False,其他重复项标记为 True 'last':将非重复项和最后一个重复项标记为 False,其他重复项标记为 True False:将所有重复项标记为 True,非重复项标记为 False subset列标签或标签序列,在 DataFrame 对象中才有此参数, 用于指定某列,仅标记该列的重复项,默认情况下将考虑所有列 默认情况下,对于每组重复的值,第一个出现的重复值标记为 False,其他重复项标记为 True,非重复项标记为 False,相当于 keep='first': >>> import pandas as pd>>> obj = pd.Series(['lama', 'cow', 'lama', 'beetle', 'lama'])>>> obj0 lama1 cow2 lama3 beetle4 lamadtype: object>>> >>> obj.duplicated()0 False1 False2 True3 False4 Truedtype: bool>>>>>> obj.duplicated(keep='first')0 False1 False2 True3 False4 Truedtype: bool 设置 keep='last',将每组非重复项和最后一次出现的重复项标记为 False,其他重复项标记为 True,设置 keep=False,则所有重复项均为 True,其他值为 False: >>> import pandas as pd>>> obj = pd.Series(['lama', 'cow', 'lama', 'beetle', 'lama'])>>> obj0 lama1 cow2 lama3 beetle4 lamadtype: object>>> >>> obj.duplicated(keep='last')0 True1 False2 True3 False4 Falsedtype: bool>>> >>> obj.duplicated(keep=False)0 True1 False2 True3 False4 Truedtype: bool 在 DataFrame 对象中,subset 参数用于指定某列,仅标记该列的重复项,默认情况下将考虑所有列: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame({'data1' : ['a'] * 4 + ['b'] * 4, 'data2' : np.random.randint(0, 4, 8)})>>> obj data1 data20 a 01 a 02 a 03 a 34 b 35 b 36 b 07 b 2>>> >>> obj.duplicated()0 False1 True2 True3 False4 False5 True6 False7 Falsedtype: bool>>> >>> obj.duplicated(subset='data1')0 False1 True2 True3 True4 False5 True6 True7 Truedtype: bool>>> >>> obj.duplicated(subset='data2', keep='last')0 True1 True2 True3 True4 True5 False6 False7 Falsedtype: bool 【02x02】drop_duplicates drop_duplicates 方法会返回一个删除了重复值的序列。 基本语法: Series.drop_duplicates(self, keep='first', inplace=False) DataFrame.drop_duplicates(self, subset: Union[Hashable, Sequence[Hashable], NoneType] = None, keep: Union[str, bool] = 'first', inplace: bool = False, ignore_index: bool = False) → Union[ForwardRef(‘DataFrame’), NoneType] 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.drop_duplicates.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.drop_duplicates.html 参数描述 keep删除重复项的方法,默认 'first' 'first':保留非重复项和第一个重复项,其他重复项标记均删除 'last':保留非重复项和最后一个重复项,其他重复项删除 False:将所有重复项删除,非重复项保留 inplace是否返回删除重复项后的值,默认 False,若设置为 True,则不返回值,直接改变原数据 subset列标签或标签序列,在 DataFrame 对象中才有此参数, 用于指定某列,仅标记该列的重复项,默认情况下将考虑所有列 ignore_indexbool 类型,在 DataFrame 对象中才有此参数,是否忽略原对象的轴标记, 默认 False,如果为 True,则新对象的索引将是 0, 1, 2, …, n-1 keep 参数的使用: >>> import pandas as pd>>> obj = pd.Series(['lama', 'cow', 'lama', 'beetle', 'lama', 'hippo'], name='animal')>>> obj0 lama1 cow2 lama3 beetle4 lama5 hippoName: animal, dtype: object>>> >>> obj.drop_duplicates()0 lama1 cow3 beetle5 hippoName: animal, dtype: object>>> >>> obj.drop_duplicates(keep='last')1 cow3 beetle4 lama5 hippoName: animal, dtype: object>>> >>> obj.drop_duplicates(keep=False)1 cow3 beetle5 hippoName: animal, dtype: object 如果设置 inplace=True,则不会返回任何值,但原对象的值已被改变: >>> import pandas as pd>>> obj1 = pd.Series(['lama', 'cow', 'lama', 'beetle', 'lama', 'hippo'], name='animal')>>> obj10 lama1 cow2 lama3 beetle4 lama5 hippoName: animal, dtype: object>>> >>> obj2 = obj1.drop_duplicates()>>> obj2 # 有返回值0 lama1 cow3 beetle5 hippoName: animal, dtype: object>>> >>> obj3 = obj1.drop_duplicates(inplace=True)>>> obj3 # 无返回值>>>>>> obj1 # 原对象的值已改变0 lama1 cow3 beetle5 hippoName: animal, dtype: object 在 DataFrame 对象中的使用: >>> import numpy as np>>> import pandas as pd>>> obj = pd.DataFrame({'data1' : ['a'] * 4 + ['b'] * 4, 'data2' : np.random.randint(0, 4, 8)})>>> obj data1 data20 a 21 a 12 a 13 a 24 b 15 b 26 b 07 b 0>>> >>> obj.drop_duplicates() data1 data20 a 21 a 14 b 15 b 26 b 0>>> >>> obj.drop_duplicates(subset='data2') data1 data20 a 21 a 16 b 0>>> >>> obj.drop_duplicates(subset='data2', ignore_index=True) data1 data20 a 21 a 12 b 0 【03x00】数据替换 【03x01】replace replace 方法可以根据值的内容进行替换。 基本语法: Series.replace(self, to_replace=None, value=None, inplace=False, limit=None, regex=False, method='pad') DataFrame.replace(self, to_replace=None, value=None, inplace=False, limit=None, regex=False, method='pad') 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.replace.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.replace.html 常用参数: 参数描述 to_replace找到要替换值的方法,可以是:字符串、正则表达式、列表、字典、整数、浮点数、Series 对象或者 None 使用不同参数的区别参见官方文档 value用于替换匹配项的值, 对于 DataFrame,可以使用字典的值来指定每列要使用的值, 还允许使用此类对象的正则表达式,字符串和列表或字典 inplacebool 类型,是否直接改变原数据且不返回值,默认 False regexbool 类型或者与 to_replace 相同的类型, 当 to_replace 参数为正则表达式时,regex 应为 True,或者直接使用该参数代替 to_replace to_replace 和 value 参数只传入一个值,单个值替换单个值: >>> import pandas as pd>>> obj = pd.Series([0, 1, 2, 3, 4])>>> obj0 01 12 23 34 4dtype: int64>>> >>> obj.replace(0, 5)0 51 12 23 34 4dtype: int64 to_replace 传入多个值,value 传入一个值,多个值替换一个值: >>> import pandas as pd>>> obj = pd.Series([0, 1, 2, 3, 4])>>> obj0 01 12 23 34 4dtype: int64>>> >>> obj.replace([0, 1, 2, 3], 4)0 41 42 43 44 4dtype: int64 to_replace 和 value 参数都传入多个值,多个值替换多个值: >>> import pandas as pd>>> obj = pd.Series([0, 1, 2, 3, 4])>>> obj0 01 12 23 34 4dtype: int64>>> >>> obj.replace([0, 1, 2, 3], [4, 3, 2, 1])0 41 32 23 14 4dtype: int64 to_replace 传入字典: >>> import pandas as pd>>> obj = pd.DataFrame({'A': [0, 1, 2, 3, 4], 'B': [5, 6, 7, 8, 9], 'C': ['a', 'b', 'c', 'd', 'e']})>>> obj A B C0 0 5 a1 1 6 b2 2 7 c3 3 8 d4 4 9 e>>> >>> obj.replace(0, 5) A B C0 5 5 a1 1 6 b2 2 7 c3 3 8 d4 4 9 e>>> >>> obj.replace({0: 10, 1: 100}) A B C0 10 5 a1 100 6 b2 2 7 c3 3 8 d4 4 9 e>>> >>> obj.replace({'A': 0, 'B': 5}, 100) A B C0 100 100 a1 1 6 b2 2 7 c3 3 8 d4 4 9 e>>> obj.replace({'A': {0: 100, 4: 400}}) A B C0 100 5 a1 1 6 b2 2 7 c3 3 8 d4 400 9 e to_replace 传入正则表达式: >>> import pandas as pd>>> obj = pd.DataFrame({'A': ['bat', 'foo', 'bait'], 'B': ['abc', 'bar', 'xyz']})>>> obj A B0 bat abc1 foo bar2 bait xyz>>> >>> obj.replace(to_replace=r'^ba.$', value='new', regex=True) A B0 new abc1 foo new2 bait xyz>>> >>> obj.replace({'A': r'^ba.$'}, {'A': 'new'}, regex=True) A B0 new abc1 foo bar2 bait xyz>>> >>> obj.replace(regex=r'^ba.$', value='new') A B0 new abc1 foo new2 bait xyz>>> >>> obj.replace(regex={r'^ba.$': 'new', 'foo': 'xyz'}) A B0 new abc1 xyz new2 bait xyz>>> >>> obj.replace(regex=[r'^ba.$', 'foo'], value='new') A B0 new abc1 new new2 bait xyz 【03x02】where where 方法用于替换条件为 False 的值。 基本语法: Series.where(self, cond, other=nan, inplace=False, axis=None, level=None, errors='raise', try_cast=False) DataFrame.where(self, cond, other=nan, inplace=False, axis=None, level=None, errors='raise', try_cast=False) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.where.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.where.html 常用参数: 参数描述 cond替换条件,如果 cond 为 True,则保留原始值。如果为 False,则替换为来自 other 的相应值 other替换值,如果 cond 为 False,则替换为来自该参数的相应值 inplacebool 类型,是否直接改变原数据且不返回值,默认 False 在 Series 中的应用: >>> import pandas as pd>>> obj = pd.Series(range(5))>>> obj0 01 12 23 34 4dtype: int64>>> >>> obj.where(obj > 0)0 NaN1 1.02 2.03 3.04 4.0dtype: float64>>> >>> obj.where(obj > 1, 10)0 101 102 23 34 4dtype: int64 在 DataFrame 中的应用: >>> import pandas as pd>>> obj = pd.DataFrame(np.arange(10).reshape(-1, 2), columns=['A', 'B'])>>> obj A B0 0 11 2 32 4 53 6 74 8 9>>> >>> m = obj % 3 == 0>>> obj.where(m, -obj) A B0 0 -11 -2 32 -4 -53 6 -74 -8 9>>> >>> obj.where(m, -obj) == np.where(m, obj, -obj) A B0 True True1 True True2 True True3 True True4 True True 【03x03】mask mask 方法与 where 方法相反,mask 用于替换条件为 False 的值。 基本语法: Series.mask(self, cond, other=nan, inplace=False, axis=None, level=None, errors='raise', try_cast=False) DataFrame.mask(self, cond, other=nan, inplace=False, axis=None, level=None, errors='raise', try_cast=False) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.mask.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.mask.html 常用参数: 参数描述 cond替换条件,如果 cond 为 False,则保留原始值。如果为 True,则替换为来自 other 的相应值 other替换值,如果 cond 为 False,则替换为来自该参数的相应值 inplacebool 类型,是否直接改变原数据且不返回值,默认 False 在 Series 中的应用: >>> import pandas as pd>>> obj = pd.Series(range(5))>>> obj0 01 12 23 34 4dtype: int64>>> >>> obj.mask(obj > 0)0 0.01 NaN2 NaN3 NaN4 NaNdtype: float64>>> >>> obj.mask(obj > 1, 10)0 01 12 103 104 10dtype: int64 在 DataFrame 中的应用: >>> import pandas as pd>>> obj = pd.DataFrame(np.arange(10).reshape(-1, 2), columns=['A', 'B'])>>> obj A B0 0 11 2 32 4 53 6 74 8 9>>> >>> m = obj % 3 == 0>>> >>> obj.mask(m, -obj) A B0 0 11 2 -32 4 53 -6 74 8 -9>>> >>> obj.where(m, -obj) == obj.mask(~m, -obj) A B0 True True1 True True2 True True3 True True4 True True 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106900748未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【01x00】concat 【02x00】append 【03x00】merge 【03x01】一对一连接 【03x02】多对一连接 【03x03】多对多连接 【03x04】参数 on / left_on / right_on 【03x05】参数 how 【03x06】参数 suffixes 【03x07】参数 left_index / right_index 【04x00】join 【05x00】四种方法的区别 Pandas 系列文章: Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象 Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作 Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理 Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引 Python 数据分析三剑客之 Pandas(五):统计计算与统计描述 Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并 Python 数据分析三剑客之 Pandas(七):合并数据集 Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换 Python 数据分析三剑客之 Pandas(九):时间序列 Python 数据分析三剑客之 Pandas(十):数据读写 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106830112未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【01x00】concat pandas.concat 可以沿着指定轴将多个对象堆叠到一起。 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.concat.html 基本语法: pandas.concat(objs: Union[Iterable[‘DataFrame’], Mapping[Optional[Hashable], ‘DataFrame’]], axis='0', join: str = "'outer'", ignore_index: bool = 'False', keys='None', levels='None', names='None', verify_integrity: bool = 'False', sort: bool = 'False', copy: bool = 'True') → ’DataFrame’ pandas.concat(objs: Union[Iterable[FrameOrSeriesUnion], Mapping[Optional[Hashable], FrameOrSeriesUnion]], axis='0', join: str = "'outer'", ignore_index: bool = 'False', keys='None', levels='None', names='None', verify_integrity: bool = 'False', sort: bool = 'False', copy: bool = 'True') → FrameOrSeriesUnion 常用参数描述: 参数描述 objsSeries 或 DataFrame 对象的序列或映射,要合并的对象 axis沿指定轴合并,0 or ‘index’,1 or ‘columns’,只有在 DataFrame 中才有 1 or 'columns’ join如何处理其他轴(或多个轴)上的索引,可取值:‘inner’,‘outer’(默认值) ‘outer’:当 axis = 0 时,列名相同的列会合并,其余列都保留(并集),空值填充; ‘inner’:当 axis = 0 时,列名相同的列会合并,其余列都舍弃(交集) ignore_indexbool 类型,连接后的值是否使用原索引值,如果为 True,则索引将会是 0, 1, …, n-1 keys序列形式,默认 None,传递 keys 后,会构造一个层次索引,即 MultiIndex 对象,keys 为最外层索引 levels用于构造 MultiIndex 的特定级别(唯一值)。未指定则将从键中推断出来 names列表类型,为索引添加标签 verify_integritybool 类型,是否检查合并后的索引有无重复项,设置为 True 若有重复项则会报错 sort当 join='outer' 时对列索引进行排序。当 join='inner' 时此操作无效 合并两个 Series 对象: >>> import pandas as pd>>> obj1 = pd.Series(['a', 'b'])>>> obj2 = pd.Series(['c', 'd'])>>> pd.concat([obj1, obj2])0 a1 b0 c1 ddtype: object 设置 ignore_index=True,放弃原有的索引值: >>> import pandas as pd>>> obj1 = pd.Series(['a', 'b'])>>> obj2 = pd.Series(['c', 'd'])>>> pd.concat([obj1, obj2], ignore_index=True)0 a1 b2 c3 ddtype: object 设置 keys 参数,添加最外层的索引: >>> import pandas as pd>>> obj1 = pd.Series(['a', 'b'])>>> obj2 = pd.Series(['c', 'd'])>>> pd.concat([obj1, obj2], keys=['s1', 's2'])s1 0 a 1 bs2 0 c 1 ddtype: object 设置 names 参数,为索引添加标签: >>> import pandas as pd>>> obj1 = pd.Series(['a', 'b'])>>> obj2 = pd.Series(['c', 'd'])>>> pd.concat([obj1, obj2], keys=['s1', 's2'], names=['Series name', 'Row ID'])Series name Row IDs1 0 a 1 bs2 0 c 1 ddtype: object 合并 DataFrame 对象: >>> import pandas as pd>>> obj1 = pd.DataFrame([['a', 1], ['b', 2]], columns=['letter', 'number'])>>> obj2 = pd.DataFrame([['c', 3], ['d', 4]], columns=['letter', 'number'])>>> obj1 letter number0 a 11 b 2>>> >>> obj2 letter number0 c 31 d 4>>> >>> pd.concat([obj1, obj2]) letter number0 a 11 b 20 c 31 d 4 合并 DataFrame 对象,不存在的值将会被 NaN 填充: >>> import pandas as pd>>> obj1 = pd.DataFrame([['a', 1], ['b', 2]], columns=['letter', 'number'])>>> obj2 = pd.DataFrame([['c', 3, 'cat'], ['d', 4, 'dog']], columns=['letter', 'number', 'animal'])>>> obj1 letter number0 a 11 b 2>>> >>> obj2 letter number animal0 c 3 cat1 d 4 dog>>> >>> pd.concat([obj1, obj2]) letter number animal0 a 1 NaN1 b 2 NaN0 c 3 cat1 d 4 dog 合并 DataFrame 对象,设置 join="inner" 不存在的列将会舍弃: >>> import pandas as pd>>> obj1 = pd.DataFrame([['a', 1], ['b', 2]], columns=['letter', 'number'])>>> obj2 = pd.DataFrame([['c', 3, 'cat'], ['d', 4, 'dog']], columns=['letter', 'number', 'animal'])>>> obj1 letter number0 a 11 b 2>>> >>> obj2 letter number animal0 c 3 cat1 d 4 dog>>> >>> pd.concat([obj1, obj2], join="inner") letter number0 a 11 b 20 c 31 d 4 合并 DataFrame 对象,设置 axis=1 沿 y 轴合并(增加列): >>> import pandas as pd>>> obj1 = pd.DataFrame([['a', 1], ['b', 2]], columns=['letter', 'number'])>>> obj2 = pd.DataFrame([['bird', 'polly'], ['monkey', 'george']], columns=['animal', 'name'])>>> obj1 letter number0 a 11 b 2>>> >>> obj2 animal name0 bird polly1 monkey george>>> >>> pd.concat([obj1, obj2], axis=1) letter number animal name0 a 1 bird polly1 b 2 monkey george 设置 verify_integrity=True ,检查新的索引是否有重复项,有重复项会报错: >>> import pandas as pd>>> obj1 = pd.DataFrame([1], index=['a'])>>> obj2 = pd.DataFrame([2], index=['a'])>>> obj1 0a 1>>> >>> obj2 0a 2>>> >>> pd.concat([obj1, obj2], verify_integrity=True)Traceback (most recent call last): ...ValueError: Indexes have overlapping values: ['a'] 设置 sort=True,会对列索引进行排序输出: >>> obj1 = pd.DataFrame([['a', 3], ['d', 2]], columns=['letter', 'number'])>>> obj2 = pd.DataFrame([['c', 1, 'cat'], ['b', 4, 'dog']], columns=['letter', 'number', 'animal'])>>> obj1 letter number0 a 31 d 2>>> >>> obj2 letter number animal0 c 1 cat1 b 4 dog>>> >>> pd.concat([obj1, obj2], sort=True) animal letter number0 NaN a 31 NaN d 20 cat c 11 dog b 4 【02x00】append Append 方法事实上是在一个 Series / DataFrame 对象后最追加另一个 Series / DataFrame 对象并返回一个新对象,不改变原对象的值。 基本语法: Series.append(self, to_append, ignore_index=False, verify_integrity=False) DataFrame.append(self, other, ignore_index=False, verify_integrity=False, sort=False) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.append.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.append.html 参数描述: 参数描述 to_append / other要追加的数据 ignore_indexbool 类型,连接后的值是否使用原索引值,如果为 True,则索引将会是 0, 1, …, n-1 verify_integritybool 类型,是否检查合并后的索引有无重复项,设置为 True 若有重复项则会报错 sortbool 类型,是否对列索引(columns)进行排序,默认 False 合并 Series 对象: >>> import pandas as pd>>> obj1 = pd.Series([1, 2, 3])>>> obj2 = pd.Series([4, 5, 6])>>> obj3 = pd.Series([4, 5, 6], index=[3, 4, 5])>>> obj10 11 22 3dtype: int64>>> >>> obj20 41 52 6dtype: int64>>> >>> obj33 44 55 6dtype: int64>>> >>> obj1.append(obj2)0 11 22 30 41 52 6dtype: int64>>> >>> obj1.append(obj3)0 11 22 33 44 55 6dtype: int64>>> >>> obj1.append(obj2, ignore_index=True)0 11 22 33 44 55 6dtype: int64>>> >>> obj1.append(obj2, verify_integrity=True)Traceback (most recent call last):...ValueError: Indexes have overlapping values: Int64Index([0, 1, 2], dtype='int64') 合并 DataFrame 对象: >>> import pandas as pd>>> obj1 = pd.DataFrame([[1, 2], [3, 4]], columns=list('AB'))>>> obj2 = pd.DataFrame([[5, 6], [7, 8]], columns=list('AB'))>>> >>> obj1 A B0 1 21 3 4>>> >>> obj2 A B0 5 61 7 8>>> >>> obj1.append(obj2) A B0 1 21 3 40 5 61 7 8>>> >>> obj1.append(obj2, ignore_index=True) A B0 1 21 3 42 5 63 7 8 以下虽然不是生成 DataFrames 的推荐方法,但演示了从多个数据源生成 DataFrames 的两种方法: >>> import pandas as pd>>> obj = pd.DataFrame(columns=['A'])>>> for i in range(5): obj = obj.append({'A': i}, ignore_index=True) >>> obj A0 01 12 23 34 4 >>> import pandas as pd>>> pd.concat([pd.DataFrame([i], columns=['A']) for i in range(5)], ignore_index=True) A0 01 12 23 34 4 【03x00】merge 将不同的数据源进行合并是数据科学中常见的操作,这既包括将两个不同的数据集非常简单地拼接在一起,也包括用数据库那样的连接(join)与合并(merge)操作处理有重叠字段的数据集。Series 与DataFrame 都具备这类操作,Pandas 的函数与方法让数据合并变得快速简单。 数据集的合并(merge)或连接(join)运算是通过一个或多个键将行连接起来的。这些运算是关系型数据库(基于SQL)的核心。Pandas 的 merge 函数是对数据应用这些算法的主要切入点。 pandas.merge 可根据一个或多个连接键将不同 DataFrame 中的行连接起来。 基本语法: pandas.merge(left, right, how: str = 'inner', on=None, left_on=None, right_on=None, left_index: bool = False, right_index: bool = False, sort: bool = False, suffixes='_x', '_y', copy: bool = True, indicator: bool = False, validate=None) → ’DataFrame’ 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.merge.html 常见参数描述: 参数描述 left参与合并的左侧 DataFrame 对象 right参与合并的右侧 DataFrame 对象 how合并方式,默认 'inner' 'inner':内连接,即使用两个对象中都有的键(交集); 'outer':外连接,即使用两个对象中所有的键(并集); 'left':左连接,即使用左对象中所有的键; 'right':右连接,即使用右对象中所有的键; on用于连接的列名。必须存在于左右两个 Dataframe对象中 如果未指定,且其他连接键也未指定,则以 left 和 right 列名的交集作为连接键 left_on左侧 DataFrame 对象中用作连接键的列 right_on右侧 DataFrame 对象中用作连接键的列 left_indexbool 类型,是否使用左侧 DataFrame 对象中的索引(index)作为连接键,默认 False right_indexbool 类型,是否使用右侧 DataFrame 对象中的索引(index)作为连接键,默认 False sortbool 类型,是否在结果中按顺序对连接键排序,默认 False。 如果为 False,则连接键的顺序取决于联接类型(how 关键字) suffixes字符串值元组,用于追加到重叠列名的末尾,默认为 ('_x', '_y')。 例如,如果左右两个 DataFrame 对象都有 data 列时,则结果中就会出现 data_x 和 data_y 【03x01】一对一连接 一对一连接是指两个 DataFrame 对象的列的值没有重复值。 如果不指定任何参数,调用 merge 方法,merge 就会将重叠的列的列名当做键来合并。 在下面的示例中,两个 DataFrame 对象都有一个列名为 key 的列,未指定按照哪一列来合并,merge 就会默认按照 key 来合并: >>> import pandas as pd>>> obj1 = pd.DataFrame({'key': ['b', 'a', 'c'], 'data1': range(3)})>>> obj2 = pd.DataFrame({'key': ['a', 'c', 'b'], 'data2': range(3)})>>> obj1 key data10 b 01 a 12 c 2>>> >>> obj2 key data20 a 01 c 12 b 2>>> >>> pd.merge(obj1, obj2) key data1 data20 b 0 21 a 1 02 c 2 1 【03x02】多对一连接 多对一连接是指两个 DataFrame 对象中,有一个的列的值有重复值。通过多对一连接获得的结果,DataFrame 将会保留重复值。 >>> import pandas as pd>>> obj1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], 'data1': range(7)})>>> obj2 = pd.DataFrame({'key': ['a', 'b', 'd'], 'data2': range(3)})>>> >>> obj1 key data10 b 01 b 12 a 23 c 34 a 45 a 56 b 6>>> >>> obj2 key data20 a 01 b 12 d 2>>> >>> pd.merge(obj1, obj2) key data1 data20 b 0 11 b 1 12 b 6 13 a 2 04 a 4 05 a 5 0 【03x03】多对多连接 多对多连接是指两个 DataFrame 对象中的列的值都有重复值。 >>> import pandas as pd>>> obj1 = pd.DataFrame({'key': ['a', 'b', 'b', 'c'], 'data1': range(4)})>>> obj2 = pd.DataFrame({'key': ['a', 'a', 'b', 'b', 'c', 'c'], 'data2': range(6)})>>> obj1 key data10 a 01 b 12 b 23 c 3>>> >>> obj2 key data20 a 01 a 12 b 23 b 34 c 45 c 5>>> >>> pd.merge(obj1, obj2) key data1 data20 a 0 01 a 0 12 b 1 23 b 1 34 b 2 25 b 2 36 c 3 47 c 3 5 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106830112未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【03x04】参数 on / left_on / right_on 参数 on 用于指定按照某一列来进行合并,若不指定该参数,则会默认按照重叠的列的列名当做键来合并: >>> import pandas as pd>>> obj1 = pd.DataFrame({'key': ['b', 'a', 'c'], 'data1': range(3)})>>> obj2 = pd.DataFrame({'key': ['a', 'c', 'b'], 'data2': range(3)})>>> obj1 key data10 b 01 a 12 c 2>>> >>> obj2 key data20 a 01 c 12 b 2>>> >>> pd.merge(obj1, obj2, on='key') key data1 data20 b 0 21 a 1 02 c 2 1 如果要根据多个键进行合并,传入一个由列名组成的列表即可: >>> import pandas as pd>>> left = pd.DataFrame({'key1': ['foo', 'foo', 'bar'], 'key2': ['one', 'two', 'one'], 'lval': [1, 2, 3]})>>> right = pd.DataFrame({'key1': ['foo', 'foo', 'bar', 'bar'], 'key2': ['one', 'one', 'one', 'two'], 'rval': [4, 5, 6, 7]})>>> left key1 key2 lval0 foo one 11 foo two 22 bar one 3>>> >>> right key1 key2 rval0 foo one 41 foo one 52 bar one 63 bar two 7>>> >>> pd.merge(left, right, on=['key1', 'key2']) key1 key2 lval rval0 foo one 1 41 foo one 1 52 bar one 3 6 如果两个对象的列名不同,就可以使用 left_on、right_on 参数分别进行指定: >>> import pandas as pd>>> obj1 = pd.DataFrame({'lkey': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], 'data1': range(7)})>>> obj2 = pd.DataFrame({'rkey': ['a', 'b', 'd'], 'data2': range(3)})>>> obj1 lkey data10 b 01 b 12 a 23 c 34 a 45 a 56 b 6>>> >>> obj2 rkey data20 a 01 b 12 d 2>>> >>> pd.merge(obj1, obj2, left_on='lkey', right_on='rkey') lkey data1 rkey data20 b 0 b 11 b 1 b 12 b 6 b 13 a 2 a 04 a 4 a 05 a 5 a 0 【03x05】参数 how 在前面的示例中,结果里面 c 和 d 以及与之相关的数据消失了。默认情况下,merge 做的是内连接('inner'),结果中的键是交集。其他方式还有:'left'、'right'、'outer',含义如下: 'inner':内连接,即使用两个对象中都有的键(交集); 'outer':外连接,即使用两个对象中所有的键(并集); 'left':左连接,即使用左对象中所有的键; 'right':右连接,即使用右对象中所有的键; >>> import pandas as pd>>> obj1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], 'data1': range(7)})>>> obj2 = pd.DataFrame({'key': ['a', 'b', 'd'], 'data2': range(3)})>>> obj1 key data10 b 01 b 12 a 23 c 34 a 45 a 56 b 6>>> >>> obj2 key data20 a 01 b 12 d 2>>> >>> pd.merge(obj1, obj2, on='key', how='inner') key data1 data20 b 0 11 b 1 12 b 6 13 a 2 04 a 4 05 a 5 0>>> >>> pd.merge(obj1, obj2, on='key', how='outer') key data1 data20 b 0.0 1.01 b 1.0 1.02 b 6.0 1.03 a 2.0 0.04 a 4.0 0.05 a 5.0 0.06 c 3.0 NaN7 d NaN 2.0>>> >>> pd.merge(obj1, obj2, on='key', how='left') key data1 data20 b 0 1.01 b 1 1.02 a 2 0.03 c 3 NaN4 a 4 0.05 a 5 0.06 b 6 1.0>>> >>> pd.merge(obj1, obj2, on='key', how='right') key data1 data20 b 0.0 11 b 1.0 12 b 6.0 13 a 2.0 04 a 4.0 05 a 5.0 06 d NaN 2 【03x06】参数 suffixes suffixes 参数用于指定附加到左右两个 DataFrame 对象的重叠列名上的字符串: 在以下示例中,选择按照 key1 进行合并,而两个 DataFrame 对象都包含 key2 列,如果未指定 suffixes 参数,则默认会为两个对象的 key2 加上 _x 和 _y,以便区分它们,如果指定了 suffixes 参数,就会按照添加指定的后缀: >>> import pandas as pd>>> left = pd.DataFrame({'key1': ['foo', 'foo', 'bar'], 'key2': ['one', 'two', 'one'], 'lval': [1, 2, 3]})>>> right = pd.DataFrame({'key1': ['foo', 'foo', 'bar', 'bar'], 'key2': ['one', 'one', 'one', 'two'], 'rval': [4, 5, 6, 7]})>>> left key1 key2 lval0 foo one 11 foo two 22 bar one 3>>> >>> right key1 key2 rval0 foo one 41 foo one 52 bar one 63 bar two 7>>> >>> pd.merge(left, right, on='key1') key1 key2_x lval key2_y rval0 foo one 1 one 41 foo one 1 one 52 foo two 2 one 43 foo two 2 one 54 bar one 3 one 65 bar one 3 two 7>>> >>> pd.merge(left, right, on='key1', suffixes=('_left', '_right')) key1 key2_left lval key2_right rval0 foo one 1 one 41 foo one 1 one 52 foo two 2 one 43 foo two 2 one 54 bar one 3 one 65 bar one 3 two 7 【03x07】参数 left_index / right_index 有时候,DataFrame 中的连接键位于其索引中。在这种情况下,可以使用 left_index=True 或right_index=True(或两个都传)以说明索引应该被用作连接键。这种方法称为按索引连接,在 Pandas 中还有个 join 方法可以实现这个功能。 在以下示例中,按照 left 的 key 列进行连接,而 right 对象的连接键位于其索引中,因此要指定 right_index=True: >>> import pandas as pd>>> left = pd.DataFrame({'key': ['a', 'b', 'a', 'a', 'b', 'c'], 'value': range(6)})>>> right = pd.DataFrame({'group_val': [3.5, 7]}, index=['a', 'b'])>>> left key value0 a 01 b 12 a 23 a 34 b 45 c 5>>> >>> right group_vala 3.5b 7.0>>> >>> pd.merge(left, right, left_on='key', right_index=True) key value group_val0 a 0 3.52 a 2 3.53 a 3 3.51 b 1 7.04 b 4 7.0 【04x00】join join 方法只适用于 DataFrame 对象,Series 对象没有该方法,该方法用于连接另一个 DataFrame 对象的列(columns)。 基本语法:DataFrame.join(self, other, on=None, how='left', lsuffix='', rsuffix='', sort=False) → ’DataFrame’ 参数描述: 参数描述 other另一个 DataFrame、Series 或 DataFrame 列表对象 on列名称,或者列名称组成的列表、元组,连接的列 how合并方式,默认 'left' 'inner':内连接,即使用两个对象中都有的键(交集); 'outer':外连接,即使用两个对象中所有的键(并集); 'left':左连接,即使用左对象中所有的键; 'right':右连接,即使用右对象中所有的键; lsuffix当两个对象有相同的列名时,合并后左边数据列名的后缀 rsuffix当两个对象有相同的列名时,合并后右边数据列名的后缀 sortbool 类型,是否在结果中按顺序对连接键排序,默认 False。 如果为 False,则连接键的顺序取决于联接类型(how 关键字) 使用 lsuffix 和 rsuffix 参数: >>> import pandas as pd>>> obj = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3', 'K4', 'K5'], 'A': ['A0', 'A1', 'A2', 'A3', 'A4', 'A5']})>>> other = pd.DataFrame({'key': ['K0', 'K1', 'K2'], 'B': ['B0', 'B1', 'B2']})>>> obj key A0 K0 A01 K1 A12 K2 A23 K3 A34 K4 A45 K5 A5>>> >>> other key B0 K0 B01 K1 B12 K2 B2>>> >>> obj.join(other, lsuffix='_1', rsuffix='_2') key_1 A key_2 B0 K0 A0 K0 B01 K1 A1 K1 B12 K2 A2 K2 B23 K3 A3 NaN NaN4 K4 A4 NaN NaN5 K5 A5 NaN NaN 如果右表的索引是左表的某一列的值,这时可以将右表的索引和左表的列对齐合并这样的灵活方式进行合并: >>> import pandas as pd>>> obj = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'], 'B': ['B0', 'B1', 'B2', 'B3'],'key': ['K0', 'K1', 'K0', 'K1']})>>> other = pd.DataFrame({'C': ['C0', 'C1'],'D': ['D0', 'D1']},index=['K0', 'K1'])>>> obj A B key0 A0 B0 K01 A1 B1 K12 A2 B2 K03 A3 B3 K1>>> >>> other C DK0 C0 D0K1 C1 D1>>> >>> obj.join(other, on='key') A B key C D0 A0 B0 K0 C0 D01 A1 B1 K1 C1 D12 A2 B2 K0 C0 D03 A3 B3 K1 C1 D1 【05x00】四种方法的区别 concat:可用于两个或多个 Series 或 DataFrame 对象间,通过 axis 参数指定按照行方向(增加行)或列方向(增加列)进合并操作,默认行合并(增加行),取并集; append:在一个 Series 或 DataFrame 对象后最追加另一个 Series 或 DataFrame 对象并返回一个新对象,不改变原对象的值。只能按行合并(增加行)。 merge:只能对两个 DataFrame 对象进行合并,一般按照列方向(增加列)进行合并操作,按照行方向合并一般用 join 方法代替,默认列合并(增加列),取交集; join:只能对两个 DataFrame 对象进行合并,按照列方向(增加列)进行合并操作,默认左连接。 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106830112未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【01x00】GroupBy 机制 【02x00】GroupBy 对象 【03x00】GroupBy Split 数据分裂 【03x01】分组运算 【03x02】按类型按列分组 【03x03】自定义分组 【03x03x01】字典分组 【03x03x02】函数分组 【03x03x03】索引层级分组 【03x04】分组迭代 【03x05】对象转换 【04x00】GroupBy Apply 数据应用 【04x01】聚合函数 【04x02】自定义函数 【04x03】对不同列作用不同函数 【04x04】GroupBy.apply() Pandas 系列文章: Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象 Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作 Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理 Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引 Python 数据分析三剑客之 Pandas(五):统计计算与统计描述 Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并 Python 数据分析三剑客之 Pandas(七):合并数据集 Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换 Python 数据分析三剑客之 Pandas(九):时间序列 Python 数据分析三剑客之 Pandas(十):数据读写 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106804881未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【01x00】GroupBy 机制 对数据集进行分组并对各组应用一个函数(无论是聚合还是转换),通常是数据分析工作中的重要环节。在将数据集加载、融合、准备好之后,通常就是计算分组统计或生成透视表。Pandas 提供了一个灵活高效的 GroupBy 功能,虽然“分组”(group by)这个名字是借用 SQL 数据库语言的命令,但其理念引用发明 R 语言 frame 的 Hadley Wickham 的观点可能更合适:分裂(Split)、应用(Apply)和组合(Combine)。 分组运算过程:Split —> Apply —> Combine 分裂(Split):根据某些标准将数据分组; 应用(Apply):对每个组独立应用一个函数; 合并(Combine):把每个分组的计算结果合并起来。 官方介绍:https://pandas.pydata.org/docs/user_guide/groupby.html 【02x00】GroupBy 对象 常见的 GroupBy 对象:Series.groupby、DataFrame.groupby,基本语法如下: Series.groupby(self, by=None, axis=0, level=None, as_index: bool = True, sort: bool = True, group_keys: bool = True, squeeze: bool = False, observed: bool = False) → ’groupby_generic.SeriesGroupBy’ DataFrame.groupby(self, by=None, axis=0, level=None, as_index: bool = True, sort: bool = True, group_keys: bool = True, squeeze: bool = False, observed: bool = False) → ’groupby_generic.DataFrameGroupBy’ 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.groupby.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.groupby.html 常用参数解释如下: 参数描述 by映射、函数、标签或标签列表,用于确定分组依据的分组。如果 by 是函数,则会在对象索引的每个值上调用它。 如果传递了 dict 或 Series,则将使用 Series 或 dict 的值来确定组(将 Series 的值首先对齐;请参见.align() 方法)。 如果传递了 ndarray,则按原样使用这些值来确定组。标签或标签列表可以按自身中的列传递给分组。 注意,元组被解释为(单个)键 axis沿指定轴拆分,默认 0,0 or ‘index’,1 or ‘columns’,只有在 DataFrame 中才有 1 or 'columns’ level如果轴是 MultiIndex(层次结构),则按特定层级进行分组,默认 None as_indexbool 类型,默认 True,对于聚合输出,返回以组标签为索引的对象。仅与 DataFrame 输入相关。 as_index=False 实际上是“SQL样式”分组输出 sortbool 类型,默认 True,对组键排序。关闭此选项可获得更好的性能。注:这不影响每组的观察顺序。Groupby 保留每个组中行的顺序 group_keysbool 类型,默认 True,调用 apply 方法时,是否将组键(keys)添加到索引( index)以标识块 squeezebool 类型,默认 False,如果可能,减少返回类型的维度,否则返回一致的类型 groupby() 进行分组,GroupBy 对象没有进行实际运算,只是包含分组的中间数据,示例如下: >>> import pandas as pd>>> import numpy as np>>> data = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], 'data1': np.random.randn(8), 'data2': np.random.randn(8)}>>> >>> obj = pd.DataFrame(data)>>> obj key1 key2 data1 data20 a one -0.804160 -0.8689051 b one -0.086990 0.3257412 a two 0.757992 0.5411013 b three -0.281435 0.0978414 a two 0.817757 -0.6436995 b two -0.462760 -0.3211966 a one -0.403699 0.6021387 a three 0.883940 -0.850526>>> >>> obj.groupby('key1')<pandas.core.groupby.generic.DataFrameGroupBy object at 0x03CDB7C0>>>> >>> obj['data1'].groupby(obj['key1'])<pandas.core.groupby.generic.SeriesGroupBy object at 0x03CDB748> 【03x00】GroupBy Split 数据分裂 【03x01】分组运算 前面通过 groupby() 方法获得了一个 GroupBy 对象,它实际上还没有进行任何计算,只是含有一些有关分组键 obj['key1'] 的中间数据而已。换句话说,该对象已经有了接下来对各分组执行运算所需的一切信息。例如,我们可以调用 GroupBy 的 mean() 方法来计算分组平均值,size() 方法返回每个分组的元素个数: >>> import pandas as pd>>> import numpy as np>>> data = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], 'data1': np.random.randn(8), 'data2': np.random.randn(8)}>>> >>> obj = pd.DataFrame(data)>>> obj key1 key2 data1 data20 a one -0.544099 -0.6140791 b one 2.193712 0.1010052 a two -0.004683 0.8827703 b three 0.312858 1.7321054 a two 0.011089 0.0895875 b two 0.292165 1.3276386 a one -1.433291 -0.2389717 a three -0.004724 -2.117326>>> >>> grouped1 = obj.groupby('key1')>>> grouped2 = obj['data1'].groupby(obj['key1'])>>> >>> grouped1.mean() data1 data2key1 a -0.395142 -0.399604b 0.932912 1.053583>>> >>> grouped2.mean()key1a -0.395142b 0.932912Name: data1, dtype: float64>>>>>> grouped1.size()key1a 5b 3dtype: int64>>> >>> grouped2.size()key1a 5b 3Name: data1, dtype: int64 【03x02】按类型按列分组 groupby() 方法 axis 参数默认是 0,通过设置也可以在其他任何轴上进行分组,也支持按照类型(dtype)进行分组: >>> import pandas as pd>>> import numpy as np>>> data = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], 'data1': np.random.randn(8), 'data2': np.random.randn(8)}>>> obj = pd.DataFrame(data)>>> obj key1 key2 data1 data20 a one -0.607009 1.9483011 b one 0.150818 -0.0250952 a two -2.086024 0.3581643 b three 0.446061 1.7087974 a two 0.745457 -0.9809485 b two 0.981877 2.1593276 a one 0.804480 -0.4996617 a three 0.112884 0.004367>>> >>> obj.dtypeskey1 objectkey2 objectdata1 float64data2 float64dtype: object>>> >>> obj.groupby(obj.dtypes, axis=1).size()float64 2object 2dtype: int64>>> >>> obj.groupby(obj.dtypes, axis=1).sum() float64 object0 1.341291 aone1 0.125723 bone2 -1.727860 atwo3 2.154858 bthree4 -0.235491 atwo5 3.141203 btwo6 0.304819 aone7 0.117251 athree 【03x03】自定义分组 groupby() 方法中可以一次传入多个数组的列表,也可以自定义一组分组键。也可以通过一个字典、一个函数,或者按照索引层级进行分组。 传入多个数组的列表: >>> import pandas as pd>>> import numpy as np>>> data = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], 'data1': np.random.randn(8), 'data2': np.random.randn(8)}>>> obj = pd.DataFrame(data)>>> obj key1 key2 data1 data20 a one -0.841652 0.6880551 b one 0.510042 -0.5611712 a two -0.418862 -0.1459833 b three -1.104698 0.5631584 a two 0.329527 -0.8931085 b two 0.753653 -0.3425206 a one -0.882527 -1.1213297 a three 1.726794 0.160244>>> >>> means = obj['data1'].groupby([obj['key1'], obj['key2']]).mean()>>> meanskey1 key2 a one -0.862090 three 1.726794 two -0.044667b one 0.510042 three -1.104698 two 0.753653Name: data1, dtype: float64>>> >>> means.unstack()key2 one three twokey1 a -0.862090 1.726794 -0.044667b 0.510042 -1.104698 0.753653 自定义分组键: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame({'key1' : ['a', 'a', 'b', 'b', 'a'], 'key2' : ['one', 'two', 'one', 'two', 'one'], 'data1' : np.random.randn(5), 'data2' : np.random.randn(5)})>>> obj key1 key2 data1 data20 a one -0.024003 0.3504801 a two -0.767534 -0.1004262 b one -0.594983 -1.9455803 b two -0.374482 0.8175924 a one 0.755452 -0.137759>>> >>> states = np.array(['Wuhan', 'Beijing', 'Beijing', 'Wuhan', 'Wuhan'])>>> years = np.array([2005, 2005, 2006, 2005, 2006])>>> >>> obj['data1'].groupby([states, years]).mean()Beijing 2005 -0.767534 2006 -0.594983Wuhan 2005 -0.199242 2006 0.755452Name: data1, dtype: float64 【03x03x01】字典分组 通过字典进行分组: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame(np.random.randint(1, 10, (5,5)), columns=['a', 'b', 'c', 'd', 'e'], index=['A', 'B', 'C', 'D', 'E'])>>> obj a b c d eA 1 4 7 1 9B 8 2 4 7 8C 9 8 2 5 1D 2 4 2 8 3E 7 5 7 2 3>>> >>> obj_dict = {'a':'Python', 'b':'Python', 'c':'Java', 'd':'C++', 'e':'Java'}>>> obj.groupby(obj_dict, axis=1).size()C++ 1Java 2Python 2dtype: int64>>> >>> obj.groupby(obj_dict, axis=1).count() C++ Java PythonA 1 2 2B 1 2 2C 1 2 2D 1 2 2E 1 2 2>>> >>> obj.groupby(obj_dict, axis=1).sum() C++ Java PythonA 1 16 5B 7 12 10C 5 3 17D 8 5 6E 2 10 12 【03x03x02】函数分组 通过函数进行分组: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame(np.random.randint(1, 10, (5,5)), columns=['a', 'b', 'c', 'd', 'e'], index=['AA', 'BBB', 'CC', 'D', 'EE'])>>> obj a b c d eAA 3 9 5 8 2BBB 1 4 2 2 6CC 9 2 4 7 6D 2 5 5 7 1EE 8 8 8 2 2>>> >>> def group_key(idx): """ idx 为列索引或行索引 """ return len(idx)>>> obj.groupby(group_key).size() # 等价于 obj.groupby(len).size()1 12 33 1dtype: int64 【03x03x03】索引层级分组 通过不同索引层级进行分组: >>> import pandas as pd>>> import numpy as np>>> columns = pd.MultiIndex.from_arrays([['Python', 'Java', 'Python', 'Java', 'Python'], ['A', 'A', 'B', 'C', 'B']], names=['language', 'index'])>>> obj = pd.DataFrame(np.random.randint(1, 10, (5, 5)), columns=columns)>>> objlanguage Python Java Python Java Pythonindex A A B C B0 7 1 9 8 51 4 5 4 5 62 4 3 1 9 53 6 6 3 8 14 7 9 2 8 2>>> >>> obj.groupby(level='language', axis=1).sum()language Java Python0 9 211 10 142 12 103 14 104 17 11>>> >>> obj.groupby(level='index', axis=1).sum()index A B C0 8 14 81 9 10 52 7 6 93 12 4 84 16 4 8 【03x04】分组迭代 GroupBy 对象支持迭代,对于单层分组,可以产生一组二元元组,由分组名和数据块组成: >>> import pandas as pd>>> import numpy as np>>> data = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], 'data1': np.random.randn(8), 'data2': np.random.randn(8)}>>> obj = pd.DataFrame(data)>>> obj key1 key2 data1 data20 a one -1.088762 0.6685041 b one 0.275500 0.7878442 a two -0.108417 -0.4912963 b three 0.019524 -0.3633904 a two 0.453612 0.7969995 b two 1.982858 1.5018776 a one 1.101132 -1.9283627 a three 0.524775 -1.205842>>> >>> for group_name, group_data in obj.groupby('key1'): print(group_name) print(group_data) a key1 key2 data1 data20 a one -1.088762 0.6685042 a two -0.108417 -0.4912964 a two 0.453612 0.7969996 a one 1.101132 -1.9283627 a three 0.524775 -1.205842b key1 key2 data1 data21 b one 0.275500 0.7878443 b three 0.019524 -0.3633905 b two 1.982858 1.501877 对于多层分组,元组的第一个元素将会是由键值组成的元组,第二个元素为数据块: >>> import pandas as pd>>> import numpy as np>>> data = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], 'data1': np.random.randn(8), 'data2': np.random.randn(8)}>>> obj = pd.DataFrame(data)>>> obj key1 key2 data1 data20 a one -1.088762 0.6685041 b one 0.275500 0.7878442 a two -0.108417 -0.4912963 b three 0.019524 -0.3633904 a two 0.453612 0.7969995 b two 1.982858 1.5018776 a one 1.101132 -1.9283627 a three 0.524775 -1.205842>>> >>> for group_name, group_data in obj.groupby(['key1', 'key2']): print(group_name) print(group_data) ('a', 'one') key1 key2 data1 data20 a one -1.088762 0.6685046 a one 1.101132 -1.928362('a', 'three') key1 key2 data1 data27 a three 0.524775 -1.205842('a', 'two') key1 key2 data1 data22 a two -0.108417 -0.4912964 a two 0.453612 0.796999('b', 'one') key1 key2 data1 data21 b one 0.2755 0.787844('b', 'three') key1 key2 data1 data23 b three 0.019524 -0.36339('b', 'two') key1 key2 data1 data25 b two 1.982858 1.501877 【03x05】对象转换 GroupBy 对象支持转换成列表或字典: >>> import pandas as pd>>> import numpy as np>>> data = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], 'data1': np.random.randn(8), 'data2': np.random.randn(8)}>>> obj = pd.DataFrame(data)>>> obj key1 key2 data1 data20 a one -0.607009 1.9483011 b one 0.150818 -0.0250952 a two -2.086024 0.3581643 b three 0.446061 1.7087974 a two 0.745457 -0.9809485 b two 0.981877 2.1593276 a one 0.804480 -0.4996617 a three 0.112884 0.004367>>> >>> grouped = obj.groupby('key1')>>> list(grouped)[('a', key1 key2 data1 data20 a one -0.607009 1.9483012 a two -2.086024 0.3581644 a two 0.745457 -0.9809486 a one 0.804480 -0.4996617 a three 0.112884 0.004367),('b', key1 key2 data1 data21 b one 0.150818 -0.0250953 b three 0.446061 1.7087975 b two 0.981877 2.159327)]>>>>>> dict(list(grouped)){'a': key1 key2 data1 data20 a one -0.607009 1.9483012 a two -2.086024 0.3581644 a two 0.745457 -0.9809486 a one 0.804480 -0.4996617 a three 0.112884 0.004367,'b': key1 key2 data1 data21 b one 0.150818 -0.0250953 b three 0.446061 1.7087975 b two 0.981877 2.159327} 【04x00】GroupBy Apply 数据应用 聚合指的是任何能够从数组产生标量值的数据转换过程,常用于对分组后的数据进行计算 【04x01】聚合函数 之前的例子已经用过一些内置的聚合函数,比如 mean、count、min 以及 sum 等。常见的聚合运算如下表所示: 官方文档:https://pandas.pydata.org/docs/reference/groupby.html 方法描述 count非NA值的数量 describe针对Series或各DataFrame列计算汇总统计 min计算最小值 max计算最大值 argmin计算能够获取到最小值的索引位置(整数) argmax计算能够获取到最大值的索引位置(整数) idxmin计算能够获取到最小值的索引值 idxmax计算能够获取到最大值的索引值 quantile计算样本的分位数(0到1) sum值的总和 mean值的平均数 median值的算术中位数(50%分位数) mad根据平均值计算平均绝对离差 var样本值的方差 std样本值的标准差 应用示例: >>> import pandas as pd>>> import numpy as np>>> obj = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], 'data1': np.random.randint(1,10, 8), 'data2': np.random.randint(1,10, 8)}>>> obj = pd.DataFrame(obj)>>> obj key1 key2 data1 data20 a one 9 71 b one 5 92 a two 2 43 b three 3 44 a two 5 15 b two 5 96 a one 1 87 a three 2 4>>> >>> obj.groupby('key1').sum() data1 data2key1 a 19 24b 13 22>>> >>> obj.groupby('key1').max() key2 data1 data2key1 a two 9 8b two 5 9>>> >>> obj.groupby('key1').min() key2 data1 data2key1 a one 1 1b one 3 4>>> >>> obj.groupby('key1').mean() data1 data2key1 a 3.800000 4.800000b 4.333333 7.333333>>> >>> obj.groupby('key1').size()key1a 5b 3dtype: int64>>> >>> obj.groupby('key1').count() key2 data1 data2key1 a 5 5 5b 3 3 3>>> >>> obj.groupby('key1').describe() data1 ... data2 count mean std min 25% ... min 25% 50% 75% maxkey1 ... a 5.0 3.800000 3.271085 1.0 2.0 ... 1.0 4.0 4.0 7.0 8.0b 3.0 4.333333 1.154701 3.0 4.0 ... 4.0 6.5 9.0 9.0 9.0[2 rows x 16 columns] 【04x02】自定义函数 如果自带的内置函数满足不了我们的要求,则可以自定义一个聚合函数,然后传入 GroupBy.agg(func) 或 GroupBy.aggregate(func) 方法中即可。func 的参数为 groupby 索引对应的记录。 >>> import pandas as pd>>> import numpy as np>>> obj = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], 'data1': np.random.randint(1,10, 8), 'data2': np.random.randint(1,10, 8)}>>> obj = pd.DataFrame(obj)>>> obj key1 key2 data1 data20 a one 9 71 b one 5 92 a two 2 43 b three 3 44 a two 5 15 b two 5 96 a one 1 87 a three 2 4>>> >>> def peak_range(df): return df.max() - df.min()>>> >>> obj.groupby('key1').agg(peak_range) data1 data2key1 a 8 7b 2 5>>> >>> obj.groupby('key1').agg(lambda df : df.max() - df.min()) data1 data2key1 a 8 7b 2 5 【04x03】对不同列作用不同函数 使用字典可以对不同列作用不同的聚合函数: >>> import pandas as pd>>> import numpy as np>>> obj = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], 'data1': np.random.randint(1,10, 8), 'data2': np.random.randint(1,10, 8)}>>> obj = pd.DataFrame(obj)>>> obj key1 key2 data1 data20 a one 9 71 b one 5 92 a two 2 43 b three 3 44 a two 5 15 b two 5 96 a one 1 87 a three 2 4>>> >>> dict1 = {'data1':'mean', 'data2':'sum'}>>> dict2 = {'data1':['mean','max'], 'data2':'sum'}>>> >>> obj.groupby('key1').agg(dict1) data1 data2key1 a 3.800000 24b 4.333333 22>>> >>> obj.groupby('key1').agg(dict2) data1 data2 mean max sumkey1 a 3.800000 9 24b 4.333333 5 22 【04x04】GroupBy.apply() apply() 方法会将待处理的对象拆分成多个片段,然后对各片段调用传入的函数,最后尝试将各片段组合到一起。 >>> import pandas as pd>>> obj = pd.DataFrame({'A':['bob','sos','bob','sos','bob','sos','bob','bob'], 'B':['one','one','two','three','two','two','one','three'], 'C':[3,1,4,1,5,9,2,6], 'D':[1,2,3,4,5,6,7,8]})>>> obj A B C D0 bob one 3 11 sos one 1 22 bob two 4 33 sos three 1 44 bob two 5 55 sos two 9 66 bob one 2 77 bob three 6 8>>> >>> grouped = obj.groupby('A')>>> for name, group in grouped: print(name) print(group) bob A B C D0 bob one 3 12 bob two 4 34 bob two 5 56 bob one 2 77 bob three 6 8sos A B C D1 sos one 1 23 sos three 1 45 sos two 9 6>>> >>> grouped.apply(lambda x:x.describe()) # 对 bob 和 sos 两组数据使用 describe 方法 C DA bob count 5.000000 5.000000 mean 4.000000 4.800000 std 1.581139 2.863564 min 2.000000 1.000000 25% 3.000000 3.000000 50% 4.000000 5.000000 75% 5.000000 7.000000 max 6.000000 8.000000sos count 3.000000 3.000000 mean 3.666667 4.000000 std 4.618802 2.000000 min 1.000000 2.000000 25% 1.000000 3.000000 50% 1.000000 4.000000 75% 5.000000 5.000000 max 9.000000 6.000000>>>>>> grouped.apply(lambda x:x.min()) # # 对 bob 和 sos 两组数据使用 min 方法 A B C DA bob bob one 2 1sos sos one 1 2 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106804881未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【01x00】统计计算 【01x01】sum() 求和 【01x02】min() 最小值 【01x03】max() 最大值 【01x04】mean() 平均值 【01x05】idxmin() 最小值索引 【01x06】idxmax() 最大值索引 【02x00】统计描述 【03x00】常用统计方法 Pandas 系列文章: Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象 Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作 Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理 Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引 Python 数据分析三剑客之 Pandas(五):统计计算与统计描述 Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并 Python 数据分析三剑客之 Pandas(七):合并数据集 Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换 Python 数据分析三剑客之 Pandas(九):时间序列 Python 数据分析三剑客之 Pandas(十):数据读写 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106788501未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【01x00】统计计算 Pandas 对象拥有一组常用的数学和统计方法。它们大部分都属于约简和汇总统计,用于从 Series 中提取单个值(如 sum 或 mean)或从 DataFrame 的行或列中提取一个 Series。跟对应的 NumPy 数组方法相比,它们都是基于没有缺失数据的假设而构建的。 【01x01】sum() 求和 sum() 方法用于返回指定轴的和,相当于 numpy.sum()。 在 Series 和 DataFrame 中的基本语法如下: Series.sum(self, axis=None, skipna=None, level=None, numeric_only=None, min_count=0, **kwargs) DataFrame.sum(self, axis=None, skipna=None, level=None, numeric_only=None, min_count=0, **kwargs) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.sum.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.sum.html 常用参数描述如下: 参数描述 axis指定轴求和,0 or ‘index’,1 or ‘columns’,只有在 DataFrame 中才有 1 or 'columns’ skipnabool 类型,求和时是否排除缺失值(NA/null),默认 True level如果轴是 MultiIndex(层次结构),则沿指定层次求和 在 Series 中的应用: >>> import pandas as pd>>> idx = pd.MultiIndex.from_arrays([ ['warm', 'warm', 'cold', 'cold'], ['dog', 'falcon', 'fish', 'spider']], names=['blooded', 'animal'])>>> obj = pd.Series([4, 2, 0, 8], name='legs', index=idx)>>> objblooded animalwarm dog 4 falcon 2cold fish 0 spider 8Name: legs, dtype: int64>>> >>> obj.sum()14>>> >>> obj.sum(level='blooded')bloodedwarm 6cold 8Name: legs, dtype: int64>>> >>> obj.sum(level=0)bloodedwarm 6cold 8Name: legs, dtype: int64 在 DataFrame 中的应用: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame([[1.4, np.nan], [7.1, -4.5], [np.nan, np.nan], [0.75, -1.3]], index=['a', 'b', 'c', 'd'], columns=['one', 'two'])>>> obj one twoa 1.40 NaNb 7.10 -4.5c NaN NaNd 0.75 -1.3>>> >>> obj.sum()one 9.25two -5.80dtype: float64>>> >>> obj.sum(axis=1)a 1.40b 2.60c 0.00d -0.55dtype: float64 【01x02】min() 最小值 min() 方法用于返回指定轴的最小值。 在 Series 和 DataFrame 中的基本语法如下: Series.min(self, axis=None, skipna=None, level=None, numeric_only=None, **kwargs) DataFrame.min(self, axis=None, skipna=None, level=None, numeric_only=None, **kwargs) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.min.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.min.html 常用参数描述如下: 参数描述 axis指定轴求最小值,0 or ‘index’,1 or ‘columns’,只有在 DataFrame 中才有 1 or 'columns’ skipnabool 类型,求最小值时是否排除缺失值(NA/null),默认 True level如果轴是 MultiIndex(层次结构),则沿指定层次求最小值 在 Series 中的应用: >>> import pandas as pd>>> idx = pd.MultiIndex.from_arrays([ ['warm', 'warm', 'cold', 'cold'], ['dog', 'falcon', 'fish', 'spider']], names=['blooded', 'animal'])>>> obj = pd.Series([4, 2, 0, 8], name='legs', index=idx)>>> objblooded animalwarm dog 4 falcon 2cold fish 0 spider 8Name: legs, dtype: int64>>> >>> obj.min()0>>> >>> obj.min(level='blooded')bloodedwarm 2cold 0Name: legs, dtype: int64>>> >>> obj.min(level=0)bloodedwarm 2cold 0Name: legs, dtype: int64 在 DataFrame 中的应用: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame([[1.4, np.nan], [7.1, -4.5], [np.nan, np.nan], [0.75, -1.3]], index=['a', 'b', 'c', 'd'],columns=['one', 'two'])>>> obj one twoa 1.40 NaNb 7.10 -4.5c NaN NaNd 0.75 -1.3>>> >>> obj.min()one 0.75two -4.50dtype: float64>>> >>> obj.min(axis=1)a 1.4b -4.5c NaNd -1.3dtype: float64>>> >>> obj.min(axis='columns', skipna=False)a NaNb -4.5c NaNd -1.3dtype: float64 【01x03】max() 最大值 max() 方法用于返回指定轴的最大值。 在 Series 和 DataFrame 中的基本语法如下: Series.max(self, axis=None, skipna=None, level=None, numeric_only=None, **kwargs) DataFrame.max(self, axis=None, skipna=None, level=None, numeric_only=None, **kwargs) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.max.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.max.html 常用参数描述如下: 参数描述 axis指定轴求最大值,0 or ‘index’,1 or ‘columns’,只有在 DataFrame 中才有 1 or 'columns’ skipnabool 类型,求最大值时是否排除缺失值(NA/null),默认 True level如果轴是 MultiIndex(层次结构),则沿指定层次求最大值 在 Series 中的应用: >>> import pandas as pd>>> idx = pd.MultiIndex.from_arrays([ ['warm', 'warm', 'cold', 'cold'], ['dog', 'falcon', 'fish', 'spider']], names=['blooded', 'animal'])>>> obj = pd.Series([4, 2, 0, 8], name='legs', index=idx)>>> objblooded animalwarm dog 4 falcon 2cold fish 0 spider 8Name: legs, dtype: int64>>> >>> obj.max()8>>> >>> obj.max(level='blooded')bloodedwarm 4cold 8Name: legs, dtype: int64>>> >>> obj.max(level=0)bloodedwarm 4cold 8Name: legs, dtype: int64 在 DataFrame 中的应用: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame([[1.4, np.nan], [7.1, -4.5], [np.nan, np.nan], [0.75, -1.3]], index=['a', 'b', 'c', 'd'],columns=['one', 'two'])>>> obj one twoa 1.40 NaNb 7.10 -4.5c NaN NaNd 0.75 -1.3>>> >>> obj.max()one 7.1two -1.3dtype: float64>>> >>> obj.max(axis=1)a 1.40b 7.10c NaNd 0.75dtype: float64>>> >>> obj.max(axis='columns', skipna=False)a NaNb 7.10c NaNd 0.75dtype: float64 【01x04】mean() 平均值 mean() 方法用于返回指定轴的平均值。 在 Series 和 DataFrame 中的基本语法如下: Series.mean(self, axis=None, skipna=None, level=None, numeric_only=None, **kwargs) DataFrame.mean(self, axis=None, skipna=None, level=None, numeric_only=None, **kwargs) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.mean.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.mean.html 常用参数描述如下: 参数描述 axis指定轴求平均值,0 or ‘index’,1 or ‘columns’,只有在 DataFrame 中才有 1 or 'columns’ skipnabool 类型,求平均值时是否排除缺失值(NA/null),默认 True level如果轴是 MultiIndex(层次结构),则沿指定层次求平均值 在 Series 中的应用: >>> import pandas as pd>>> idx = pd.MultiIndex.from_arrays([ ['warm', 'warm', 'cold', 'cold'], ['dog', 'falcon', 'fish', 'spider']], names=['blooded', 'animal'])>>> obj = pd.Series([4, 2, 0, 8], name='legs', index=idx)>>> objblooded animalwarm dog 4 falcon 2cold fish 0 spider 8Name: legs, dtype: int64>>> >>> obj.mean()3.5>>> >>> obj.mean(level='blooded')bloodedwarm 3cold 4Name: legs, dtype: int64>>> >>> obj.mean(level=0)bloodedwarm 3cold 4Name: legs, dtype: int64 在 DataFrame 中的应用: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame([[1.4, np.nan], [7.1, -4.5], [np.nan, np.nan], [0.75, -1.3]], index=['a', 'b', 'c', 'd'],columns=['one', 'two'])>>> obj one twoa 1.40 NaNb 7.10 -4.5c NaN NaNd 0.75 -1.3>>> >>> obj.mean()one 3.083333two -2.900000dtype: float64>>> >>> obj.mean(axis=1)a 1.400b 1.300c NaNd -0.275dtype: float64>>> >>> obj.mean(axis='columns', skipna=False)a NaNb 1.300c NaNd -0.275dtype: float64 【01x05】idxmin() 最小值索引 idxmin() 方法用于返回最小值的索引。 在 Series 和 DataFrame 中的基本语法如下: Series.idxmin(self, axis=0, skipna=True, *args, **kwargs) DataFrame.idxmin(self, axis=0, skipna=True) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.idxmin.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.idxmin.html 常用参数描述如下: 参数描述 axis指定轴,0 or ‘index’,1 or ‘columns’,只有在 DataFrame 中才有 1 or 'columns’ skipnabool 类型,是否排除缺失值(NA/null),默认 True 在 Series 中的应用: >>> import pandas as pd>>> idx = pd.MultiIndex.from_arrays([ ['warm', 'warm', 'cold', 'cold'], ['dog', 'falcon', 'fish', 'spider']], names=['blooded', 'animal'])>>> obj = pd.Series([4, 2, 0, 8], name='legs', index=idx)>>> objblooded animalwarm dog 4 falcon 2cold fish 0 spider 8Name: legs, dtype: int64>>> >>> obj.idxmin()('cold', 'fish') 在 DataFrame 中的应用: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame([[1.4, np.nan], [7.1, -4.5], [np.nan, np.nan], [0.75, -1.3]], index=['a', 'b', 'c', 'd'],columns=['one', 'two'])>>> obj one twoa 1.40 NaNb 7.10 -4.5c NaN NaNd 0.75 -1.3>>> >>> obj.idxmin()one dtwo bdtype: object 【01x06】idxmax() 最大值索引 idxmax() 方法用于返回最大值的索引。 在 Series 和 DataFrame 中的基本语法如下: Series.idxmax(self, axis=0, skipna=True, *args, **kwargs) DataFrame.idxmax(self, axis=0, skipna=True) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.idxmax.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.idxmax.html 常用参数描述如下: 参数描述 axis指定轴,0 or ‘index’,1 or ‘columns’,只有在 DataFrame 中才有 1 or 'columns’ skipnabool 类型,是否排除缺失值(NA/null),默认 True 在 Series 中的应用: >>> import pandas as pd>>> idx = pd.MultiIndex.from_arrays([ ['warm', 'warm', 'cold', 'cold'], ['dog', 'falcon', 'fish', 'spider']], names=['blooded', 'animal'])>>> obj = pd.Series([4, 2, 0, 8], name='legs', index=idx)>>> objblooded animalwarm dog 4 falcon 2cold fish 0 spider 8Name: legs, dtype: int64>>> >>> obj.idxmax()('cold', 'spider') 在 DataFrame 中的应用: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame([[1.4, np.nan], [7.1, -4.5], [np.nan, np.nan], [0.75, -1.3]], index=['a', 'b', 'c', 'd'],columns=['one', 'two'])>>> obj one twoa 1.40 NaNb 7.10 -4.5c NaN NaNd 0.75 -1.3>>> >>> obj.idxmax()one btwo ddtype: object 【02x00】统计描述 describe() 方法用于快速综合统计结果:计数、均值、标准差、最大最小值、四分位数等。还可以通过参数来设置需要忽略或者包含的统计选项。 在 Series 和 DataFrame 中的基本语法如下: Series.describe(self: ~ FrameOrSeries, percentiles=None, include=None, exclude=None) DataFrame.describe(self: ~ FrameOrSeries, percentiles=None, include=None, exclude=None) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.describe.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.describe.html 参数描述 percentiles数字列表,可选项,要包含在输出中的百分比。所有值都应介于 0 和 1 之间。默认值为 [.25、.5、.75],即返回第 25、50 和 75 个百分点 include要包含在结果中的数据类型,数据类型列表,默认 None,具体取值类型参见官方文档 exclude要从结果中忽略的数据类型,数据类型列表,默认 None,具体取值类型参见官方文档 描述数字形式的 Series 对象: >>> import pandas as pd>>> obj = pd.Series([1, 2, 3])>>> obj0 11 22 3dtype: int64>>> >>> obj.describe()count 3.0mean 2.0std 1.0min 1.025% 1.550% 2.075% 2.5max 3.0dtype: float64 分类描述: >>> import pandas as pd>>> obj = pd.Series(['a', 'a', 'b', 'c'])>>> obj0 a1 a2 b3 cdtype: object>>> >>> obj.describe()count 4unique 3top afreq 2dtype: object 描述时间戳: >>> import pandas as pd>>> obj = pd.Series([ np.datetime64("2000-01-01"), np.datetime64("2010-01-01"), np.datetime64("2010-01-01") ])>>> obj0 2000-01-011 2010-01-012 2010-01-01dtype: datetime64[ns]>>> >>> obj.describe()count 3unique 2top 2010-01-01 00:00:00freq 2first 2000-01-01 00:00:00last 2010-01-01 00:00:00dtype: object 描述 DataFrame 对象: >>> import pandas as pd>>> obj = pd.DataFrame({'categorical': pd.Categorical(['d','e','f']), 'numeric': [1, 2, 3], 'object': ['a', 'b', 'c']})>>> obj categorical numeric object0 d 1 a1 e 2 b2 f 3 c>>> >>> obj.describe() numericcount 3.0mean 2.0std 1.0min 1.025% 1.550% 2.075% 2.5max 3.0 不考虑数据类型,显示所有描述: >>> import pandas as pd>>> obj = pd.DataFrame({'categorical': pd.Categorical(['d','e','f']), 'numeric': [1, 2, 3], 'object': ['a', 'b', 'c']})>>> obj categorical numeric object0 d 1 a1 e 2 b2 f 3 c>>> >>> obj.describe(include='all') categorical numeric objectcount 3 3.0 3unique 3 NaN 3top f NaN cfreq 1 NaN 1mean NaN 2.0 NaNstd NaN 1.0 NaNmin NaN 1.0 NaN25% NaN 1.5 NaN50% NaN 2.0 NaN75% NaN 2.5 NaNmax NaN 3.0 NaN 仅包含 category 列: >>> import pandas as pd>>> obj = pd.DataFrame({'categorical': pd.Categorical(['d','e','f']), 'numeric': [1, 2, 3], 'object': ['a', 'b', 'c']})>>> obj categorical numeric object0 d 1 a1 e 2 b2 f 3 c>>> >>> obj.describe(include=['category']) categoricalcount 3unique 3top ffreq 1 【03x00】常用统计方法 其他常用统计方法参见下表: 方法描述官方文档 count非NA值的数量Series丨DataFrame describe针对Series或各DataFrame列计算汇总统计Series丨DataFrame min计算最小值Series丨DataFrame max计算最大值Series丨DataFrame argmin计算能够获取到最小值的索引位置(整数)Series argmax计算能够获取到最大值的索引位置(整数)Series idxmin计算能够获取到最小值的索引值Series丨DataFrame idxmax计算能够获取到最大值的索引值Series丨DataFrame quantile计算样本的分位数(0到1)Series丨DataFrame sum值的总和Series丨DataFrame mean值的平均数Series丨DataFrame median值的算术中位数(50%分位数)Series丨DataFrame mad根据平均值计算平均绝对离差Series丨DataFrame var样本值的方差Series丨DataFrame std样本值的标准差Series丨DataFrame 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106788501未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【01x00】函数应用和映射 【02x00】排序 【02x01】sort_index() 索引排序 【02x02】sort_values() 按值排序 【02x03】rank() 返回排序后元素索引 【03x00】层级索引 【03x01】认识层级索引 【03x02】MultiIndex 索引对象 【03x03】提取值 【03x04】交换分层与排序 Pandas 系列文章: Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象 Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作 Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理 Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引 Python 数据分析三剑客之 Pandas(五):统计计算与统计描述 Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并 Python 数据分析三剑客之 Pandas(七):合并数据集 Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换 Python 数据分析三剑客之 Pandas(九):时间序列 Python 数据分析三剑客之 Pandas(十):数据读写 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106758103未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【01x00】函数应用和映射 Pandas 可直接使用 NumPy 的 ufunc(元素级数组方法) 函数: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame(np.random.randn(5,4) - 1)>>> obj 0 1 2 30 -0.228107 1.377709 -1.096528 -2.0510011 -2.477144 -0.500013 -0.040695 -0.2674522 -0.485999 -1.232930 -0.390701 -1.9479843 -0.839161 -0.702802 -1.756359 -1.8731494 0.853121 -1.540105 0.621614 -0.583360>>> >>> np.abs(obj) 0 1 2 30 0.228107 1.377709 1.096528 2.0510011 2.477144 0.500013 0.040695 0.2674522 0.485999 1.232930 0.390701 1.9479843 0.839161 0.702802 1.756359 1.8731494 0.853121 1.540105 0.621614 0.583360 函数映射:在 Pandas 中 apply 方法可以将函数应用到列或行上,可以通过设置 axis 参数来指定行或列,默认 axis = 0,即按列映射: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame(np.random.randn(5,4) - 1)>>> obj 0 1 2 30 -0.707028 -0.755552 -2.196480 -0.5296761 -0.772668 0.127485 -2.015699 -0.2836542 0.248200 -1.940189 -1.068028 -1.7517373 -0.872904 -0.465371 -1.327951 -2.8831604 -0.092664 0.258351 -1.010747 -2.313039>>> >>> obj.apply(lambda x : x.max())0 0.2482001 0.2583512 -1.0107473 -0.283654dtype: float64>>>>>> obj.apply(lambda x : x.max(), axis=1)0 -0.5296761 0.1274852 0.2482003 -0.4653714 0.258351dtype: float64 另外还可以通过 applymap 将函数映射到每个数据上: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame(np.random.randn(5,4) - 1)>>> obj 0 1 2 30 -0.772463 -1.597008 -3.196100 -1.9484861 -1.765108 -1.646421 -0.687175 -0.4017822 0.275699 -3.115184 -1.429063 -1.0756103 -0.251734 -0.448399 -3.077677 -0.2946744 -1.495896 -1.689729 -0.560376 -1.808794>>> >>> obj.applymap(lambda x : '%.2f' % x) 0 1 2 30 -0.77 -1.60 -3.20 -1.951 -1.77 -1.65 -0.69 -0.402 0.28 -3.12 -1.43 -1.083 -0.25 -0.45 -3.08 -0.294 -1.50 -1.69 -0.56 -1.81 【02x00】排序 【02x01】sort_index() 索引排序 根据条件对数据集排序(sorting)也是一种重要的内置运算。要对行或列索引进行排序(按字典顺序),可使用 sort_index 方法,它将返回一个已排序的新对象。 在 Series 和 DataFrame 中的基本语法如下: Series.sort_index(self, axis=0, level=None, ascending=True, inplace=False, kind='quicksort', na_position='last', sort_remaining=True, ignore_index: bool = False) DataFrame.sort_index(self, axis=0, level=None, ascending=True, inplace=False, kind='quicksort', na_position='last', sort_remaining=True, ignore_index: bool = False) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.sort_index.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.sort_index.html 常用参数描述如下: 参数描述 axis指定轴排序,0 or ‘index’,1 or ‘columns’,只有在 DataFrame 中才有 1 or 'columns’ ascending为 True时升序排序(默认),为 False时降序排序 kind排序方法,quicksort:快速排序(默认);'mergesort’:归并排序;'heapsort':堆排序;具体可参见 numpy.sort() 在 Series 中的应用(按照索引 index 排序): >>> import pandas as pd>>> obj = pd.Series(range(4), index=['d', 'a', 'b', 'c'])>>> objd 0a 1b 2c 3dtype: int64>>> >>> obj.sort_index()a 1b 2c 3d 0dtype: int64 在 DataFrame 中的应用(可按照索引 index 或列标签 columns 排序): >>> import pandas as pd>>> obj = pd.DataFrame(np.arange(8).reshape((2, 4)), index=['three', 'one'], columns=['d', 'a', 'b', 'c'])>>> obj d a b cthree 0 1 2 3one 4 5 6 7>>> >>> obj.sort_index() d a b cone 4 5 6 7three 0 1 2 3>>> >>> obj.sort_index(axis=1) a b c dthree 1 2 3 0one 5 6 7 4>>> >>> obj.sort_index(axis=1, ascending=False) d c b athree 0 3 2 1one 4 7 6 5 【02x02】sort_values() 按值排序 在 Series 和 DataFrame 中的基本语法如下: Series.sort_values(self, axis=0, ascending=True, inplace=False, kind='quicksort', na_position='last', ignore_index=False) DataFrame.sort_values(self, by, axis=0, ascending=True, inplace=False, kind='quicksort', na_position='last', ignore_index=False) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.sort_values.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.sort_values.html 常用参数描述如下: 参数描述 byDataFrame 中的必须参数,指定列的值进行排序,Series 中没有此参数 axis指定轴排序,0 or ‘index’,1 or ‘columns’,只有在 DataFrame 中才有 1 or 'columns’ ascending为 True时升序排序(默认),为 False时降序排序 kind排序方法,quicksort:快速排序(默认);'mergesort’:归并排序;'heapsort':堆排序;具体可参见 numpy.sort() 在 Series 中的应用,按照值排序,如果有缺失值,默认都会被放到 Series 的末尾: >>> import pandas as pd>>> obj = pd.Series([4, 7, -3, 2])>>> obj0 41 72 -33 2dtype: int64>>> >>> obj.sort_values()2 -33 20 41 7dtype: int64>>> >>> obj = pd.Series([4, np.nan, 7, np.nan, -3, 2])>>> obj0 4.01 NaN2 7.03 NaN4 -3.05 2.0dtype: float64>>> >>> obj.sort_values()4 -3.05 2.00 4.02 7.01 NaN3 NaNdtype: float64 在 DataFrame 中的应用,有时候可能希望根据一个或多个列中的值进行排序。将一个或多个列的名字传递给 sort_values() 的 by 参数即可达到该目的,当传递多个列时,首先会对第一列进行排序,若第一列有相同的值,再根据第二列进行排序,依次类推: >>> import pandas as pd>>> obj = pd.DataFrame({'a': [4, 4, -3, 2], 'b': [0, 1, 0, 1], 'c': [6, 4, 1, 3]})>>> obj a b c0 4 0 61 4 1 42 -3 0 13 2 1 3>>> >>> obj.sort_values(by='c') a b c2 -3 0 13 2 1 31 4 1 40 4 0 6>>> >>> obj.sort_values(by='c', ascending=False) a b c0 4 0 61 4 1 43 2 1 32 -3 0 1>>>>>> obj.sort_values(by=['a', 'b']) a b c2 -3 0 13 2 1 30 4 0 61 4 1 4 >>> import pandas as pd>>> obj = pd.DataFrame({'a': [4, 4, -3, 2], 'b': [0, 1, 0, 1], 'c': [6, 4, 1, 3]}, index=['A', 'B', 'C', 'D'])>>> obj a b cA 4 0 6B 4 1 4C -3 0 1D 2 1 3>>> >>> obj.sort_values(by='B', axis=1) b a cA 0 4 6B 1 4 4C 0 -3 1D 1 2 3 【02x03】rank() 返回排序后元素索引 rank() 函数会返回一个对象,对象的值是原对象经过排序后的索引值,即下标。 在 Series 和 DataFrame 中的基本语法如下: Series.rank(self: ~ FrameOrSeries, axis=0, method: str = 'average', numeric_only: Union[bool, NoneType] = None, na_option: str = 'keep', ascending: bool = True, pct: bool = False) DataFrame.rank(self: ~ FrameOrSeries, axis=0, method: str = 'average', numeric_only: Union[bool, NoneType] = None, na_option: str = 'keep', ascending: bool = True, pct: bool = False) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.rank.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.rank.html 常用参数描述如下: 参数描述 axis指定轴排序,0 or ‘index’,1 or ‘columns’,只有在 DataFrame 中才有 1 or 'columns’ method有相同值时,如何处理: ‘average’:默认值,去两个相同索引的平均值;‘min’:取两个相同索引的最小值; ‘max’:取两个相同索引的最大值;‘first’:按照出现的先后顺序; ‘dense’:和 'min' 差不多,但是各组之间总是+1的,不太好解释,可以看后面的示例 ascending为 True时升序排序(默认),为 False时降序排序 在 Series 中的应用,按照值排序,如果有缺失值,默认都会被放到 Series 的末尾: >>> import pandas as pd>>> obj = pd.Series([7, -5, 7, 4, 2, 0, 4])>>> obj0 71 -52 73 44 25 06 4dtype: int64>>> >>> obj.rank()0 6.5 # 第 0 个和第 2 个值从小到大排名分别为 6 和 7,默认取平均值,即 6.51 1.02 6.53 4.5 # 第 3 个和第 6 个值从小到大排名分别为 4 和 5,默认取平均值,即 4.54 3.05 2.06 4.5dtype: float64>>> >>> obj.rank(method='first')0 6.0 # 第 0 个和第 2 个值从小到大排名分别为 6 和 7,按照第一次出现排序,分别为 6 和 71 1.02 7.03 4.0 # 第 3 个和第 6 个值从小到大排名分别为 4 和 5,按照第一次出现排序,分别为 4 和 54 3.05 2.06 5.0dtype: float64>>> >>> obj.rank(method='dense')0 5.0 # 第 0 个和第 2 个值从小到大排名分别为 6 和 7,按照最小值排序,但 dense 规定间隔为 1 所以为 51 1.02 5.03 4.0 # 第 3 个和第 6 个值从小到大排名分别为 4 和 5,按照最小值排序,即 44 3.05 2.06 4.0dtype: float64>>> >>> obj.rank(method='min')0 6.0 # 第 0 个和第 2 个值从小到大排名分别为 6 和 7,按照最小值排序,即 61 1.02 6.03 4.0 # 第 3 个和第 6 个值从小到大排名分别为 4 和 5,按照最小值排序,即 44 3.05 2.06 4.0dtype: float64 在 DataFrame 中可以使用 axis 参数来指定轴: >>> import pandas as pd>>> obj = pd.DataFrame({'b': [4.3, 7, -3, 2], 'a': [0, 1, 0, 1], 'c': [-2, 5, 8, -2.5]})>>> obj b a c0 4.3 0 -2.01 7.0 1 5.02 -3.0 0 8.03 2.0 1 -2.5>>> >>> obj.rank() b a c0 3.0 1.5 2.01 4.0 3.5 3.02 1.0 1.5 4.03 2.0 3.5 1.0>>> >>> obj.rank(axis='columns') b a c0 3.0 2.0 1.01 3.0 1.0 2.02 1.0 2.0 3.03 3.0 2.0 1.0 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106758103未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【03x00】层级索引 【03x01】认识层级索引 以下示例将创建一个 Series 对象, 索引 Index 由两个子 list 组成,第一个子 list 是外层索引,第二个 list 是内层索引: >>> import pandas as pd>>> import numpy as np>>> obj = pd.Series(np.random.randn(12),index=[['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd'], [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]])>>> obja 0 -0.201536 1 -0.629058 2 0.766716b 0 -1.255831 1 -0.483727 2 -0.018653c 0 0.788787 1 1.010097 2 -0.187258d 0 1.242363 1 -0.822011 2 -0.085682dtype: float64 【03x02】MultiIndex 索引对象 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.MultiIndex.html 尝试打印上面示例中 Series 的索引类型,会得到一个 MultiIndex 对象,MultiIndex 对象的 levels 属性表示两个层级中分别有那些标签,codes 属性表示每个位置分别是什么标签,如下所示: >>> import pandas as pd>>> import numpy as np>>> obj = pd.Series(np.random.randn(12),index=[['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd'], [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]])>>> obja 0 0.035946 1 -0.867215 2 -0.053355b 0 -0.986616 1 0.026071 2 -0.048394c 0 0.251274 1 0.217790 2 1.137674d 0 -1.245178 1 1.234972 2 -0.035624dtype: float64>>> >>> type(obj.index)<class 'pandas.core.indexes.multi.MultiIndex'>>>> >>> obj.indexMultiIndex([('a', 0), ('a', 1), ('a', 2), ('b', 0), ('b', 1), ('b', 2), ('c', 0), ('c', 1), ('c', 2), ('d', 0), ('d', 1), ('d', 2)], )>>> obj.index.levelsFrozenList([['a', 'b', 'c', 'd'], [0, 1, 2]])>>>>>> obj.index.codesFrozenList([[0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3], [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]]) 通常可以使用 from_arrays() 方法来将数组对象转换为 MultiIndex 索引对象: >>> arrays = [[1, 1, 2, 2], ['red', 'blue', 'red', 'blue']]>>> pd.MultiIndex.from_arrays(arrays, names=('number', 'color'))MultiIndex([(1, 'red'), (1, 'blue'), (2, 'red'), (2, 'blue')], names=['number', 'color']) 其他常用方法见下表(更多方法参见官方文档): 方法描述 from_arrays(arrays[, sortorder, names])将数组转换为 MultiIndex from_tuples(tuples[, sortorder, names])将元组列表转换为 MultiIndex from_product(iterables[, sortorder, names])将多个可迭代的笛卡尔积转换成 MultiIndex from_frame(df[, sortorder, names])将 DataFrame 对象转换为 MultiIndex set_levels(self, levels[, level, inplace, …])为 MultiIndex 设置新的 levels set_codes(self, codes[, level, inplace, …])为 MultiIndex 设置新的 codes sortlevel(self[, level, ascending, …])根据 level 进行排序 droplevel(self[, level])删除指定的 level swaplevel(self[, i, j])交换 level i 与 level i,即交换外层索引与内层索引 【03x03】提取值 对于这种有多层索引的对象,如果只传入一个参数,则会对外层索引进行提取,其中包含对应所有的内层索引,如果传入两个参数,则第一个参数表示外层索引,第二个参数表示内层索引,示例如下: >>> import pandas as pd>>> import numpy as np>>> obj = pd.Series(np.random.randn(12),index=[['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd'], [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]])>>> obja 0 0.550202 1 0.328784 2 1.422690b 0 -1.333477 1 -0.933809 2 -0.326541c 0 0.663686 1 0.943393 2 0.273106d 0 1.354037 1 -2.312847 2 -2.343777dtype: float64>>> >>> obj['b']0 -1.3334771 -0.9338092 -0.326541dtype: float64>>>>>> obj['b', 1]-0.9338094811708413>>> >>> obj[:, 2]a 1.422690b -0.326541c 0.273106d -2.343777dtype: float64 【03x04】交换分层与排序 MultiIndex 对象的 swaplevel() 方法可以交换外层与内层索引,sortlevel() 方法会先对外层索引进行排序,再对内层索引进行排序,默认是升序,如果设置 ascending 参数为 False 则会降序排列,示例如下: >>> import pandas as pd>>> import numpy as np>>> obj = pd.Series(np.random.randn(12),index=[['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd'], [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]])>>> obja 0 -0.110215 1 0.193075 2 -1.101706b 0 -1.325743 1 0.528418 2 -0.127081c 0 -0.733822 1 1.665262 2 0.127073d 0 1.262022 1 -1.170518 2 0.966334dtype: float64>>> >>> obj.swaplevel()0 a -0.1102151 a 0.1930752 a -1.1017060 b -1.3257431 b 0.5284182 b -0.1270810 c -0.7338221 c 1.6652622 c 0.1270730 d 1.2620221 d -1.1705182 d 0.966334dtype: float64>>> >>> obj.swaplevel().index.sortlevel()(MultiIndex([(0, 'a'), (0, 'b'), (0, 'c'), (0, 'd'), (1, 'a'), (1, 'b'), (1, 'c'), (1, 'd'), (2, 'a'), (2, 'b'), (2, 'c'), (2, 'd')], ), array([ 0, 3, 6, 9, 1, 4, 7, 10, 2, 5, 8, 11], dtype=int32)) 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106758103未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【01x00】Pandas 算术运算 【01x01】使用 NumPy 通用函数 【01x02】数据对齐 【01x03】DataFrame 与 Series 之间的运算 【01x04】Pandas 算术方法 【02x00】处理缺失值 【02x01】fill_value() 指定值与缺失值进行运算 【02x02】isnull() / notnull() 判断缺失值 【02x03】dropna() 删除缺失值 【02x04】fillna() 填充缺失值 Pandas 系列文章: Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象 Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作 Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理 Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引 Python 数据分析三剑客之 Pandas(五):统计计算与统计描述 Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并 Python 数据分析三剑客之 Pandas(七):合并数据集 Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换 Python 数据分析三剑客之 Pandas(九):时间序列 Python 数据分析三剑客之 Pandas(十):数据读写 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106743778未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【01x00】Pandas 算术运算 Pandas 继承了 NumPy 的功能,NumPy 的基本能力之一是快速对每个元素进行运算,既包括基本算术运算(加、减、乘、除),也包括更复杂的运算(三角函数、指数函数和对数函数等)。具体可以参考 NumPy 系列文章。 【01x01】使用 NumPy 通用函数 因为 Pandas 是建立在 NumPy 基础之上的,所以 NumPy 的通用函数同样适用于 Pandas 的 Series 和 DataFrame 对象,如下所示: >>> import pandas as pd>>> import numpy as np>>> rng = np.random.RandomState(42)>>> ser = pd.Series(rng.randint(0, 10, 4))>>> ser0 61 32 73 4dtype: int32>>> >>> obj = pd.DataFrame(rng.randint(0, 10, (3, 4)), columns=['A', 'B', 'C', 'D'])>>> obj A B C D0 6 9 2 61 7 4 3 72 7 2 5 4 使用 NumPy 通用函数,生成的结果是另一个保留索引的 Pandas 对象: >>> import pandas as pd>>> import numpy as np>>> rng = np.random.RandomState(42)>>> ser = pd.Series(rng.randint(0, 10, 4))>>> ser0 61 32 73 4dtype: int32>>> >>> np.exp(ser)0 403.4287931 20.0855372 1096.6331583 54.598150dtype: float64 >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame(rng.randint(0, 10, (3, 4)), columns=['A', 'B', 'C', 'D'])>>> np.sin(obj * np.pi / 4) A B C D0 -1.000000 7.071068e-01 1.000000 -1.000000e+001 -0.707107 1.224647e-16 0.707107 -7.071068e-012 -0.707107 1.000000e+00 -0.707107 1.224647e-16 【01x02】数据对齐 Pandas 最重要的一个功能是,它可以对不同索引的对象进行算术运算。在将对象相加时,如果存在不同的索引对,则结果的索引就是该索引对的并集。自动的数据对齐操作会在不重叠的索引处引入缺失值,即 NaN,缺失值会在算术运算过程中传播。 Series 对象的数据对齐操作: >>> import pandas as pd>>> obj1 = pd.Series([7.3, -2.5, 3.4, 1.5], index=['a', 'c', 'd', 'e'])>>> obj2 = pd.Series([-2.1, 3.6, -1.5, 4, 3.1], index=['a', 'c', 'e', 'f', 'g'])>>> obj1a 7.3c -2.5d 3.4e 1.5dtype: float64>>> >>> obj2a -2.1c 3.6e -1.5f 4.0g 3.1dtype: float64>>>>>> obj1 + obj2a 5.2c 1.1d NaNe 0.0f NaNg NaNdtype: float64 DataFrame 对象的数据对齐操作会同时发生在行和列上: >>> import pandas as pd>>> obj1 = pd.DataFrame(np.arange(9.).reshape((3, 3)), columns=list('bcd'), index=['Ohio', 'Texas', 'Colorado'])>>> obj2 = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'])>>> obj1 b c dOhio 0.0 1.0 2.0Texas 3.0 4.0 5.0Colorado 6.0 7.0 8.0>>> >>> obj2 b d eUtah 0.0 1.0 2.0Ohio 3.0 4.0 5.0Texas 6.0 7.0 8.0Oregon 9.0 10.0 11.0>>> >>> obj1 + obj2 b c d eColorado NaN NaN NaN NaNOhio 3.0 NaN 6.0 NaNOregon NaN NaN NaN NaNTexas 9.0 NaN 12.0 NaNUtah NaN NaN NaN NaN 【01x03】DataFrame 与 Series 之间的运算 首先回忆 NumPy 中的广播(参见:《Python 数据分析三剑客之 NumPy(二):数组索引 / 切片 / 广播 / 拼接 / 分割》),跟不同维度的 NumPy 数组一样,DataFrame 和 Series 之间算术运算也是有明确规定的。首先回忆一下 NumPy 中不同维度的数组之间的运算: >>> import numpy as np>>> arr = np.arange(12.).reshape((3, 4))>>> arrarray([[ 0., 1., 2., 3.], [ 4., 5., 6., 7.], [ 8., 9., 10., 11.]])>>> >>> arr[0]array([0., 1., 2., 3.])>>> >>> arr - arr[0]array([[0., 0., 0., 0.], [4., 4., 4., 4.], [8., 8., 8., 8.]]) 可以看到每一行都进行了减法运算,这正是 NumPy 中的广播,而 DataFrame 与 Series 之间的运算也类似,默认情况下,DataFrame 和 Series 之间的算术运算会将 Series 的索引匹配到 DataFrame 的列,然后沿着行一直向下广播: >>> import numpy as np>>> import pandas as pd>>> frame = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'), index=['AA', 'BB', 'CC', 'DD'])>>> frame b d eAA 0.0 1.0 2.0BB 3.0 4.0 5.0CC 6.0 7.0 8.0DD 9.0 10.0 11.0>>> >>> series = frame.iloc[0]>>> seriesb 0.0d 1.0e 2.0Name: AA, dtype: float64>>> >>> frame - series b d eAA 0.0 0.0 0.0BB 3.0 3.0 3.0CC 6.0 6.0 6.0DD 9.0 9.0 9.0 如果某个索引值在 DataFrame 的列或 Series 的索引中找不到,则参与运算的两个对象就会被重新索引以形成并集: >>> import numpy as np>>> import pandas as pd>>> frame = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'), index=['AA', 'BB', 'CC', 'DD'])>>> frame b d eAA 0.0 1.0 2.0BB 3.0 4.0 5.0CC 6.0 7.0 8.0DD 9.0 10.0 11.0>>> >>> series = pd.Series(range(3), index=['b', 'e', 'f'])>>> seriesb 0e 1f 2dtype: int64>>> >>> frame + series b d e fAA 0.0 NaN 3.0 NaNBB 3.0 NaN 6.0 NaNCC 6.0 NaN 9.0 NaNDD 9.0 NaN 12.0 NaN 如果希望匹配行且在列上广播,则必须使用算术运算方法,在方法中传入的轴(axis)就是希望匹配的轴。在下例中,我们的目的是匹配 DataFrame 的行索引(axis=‘index’ or axis=0)并进行广播: >>> import numpy as np>>> import pandas as pd>>> frame = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'), index=['AA', 'BB', 'CC', 'DD'])>>> frame b d eAA 0.0 1.0 2.0BB 3.0 4.0 5.0CC 6.0 7.0 8.0DD 9.0 10.0 11.0>>> >>> series = frame['d']>>> seriesAA 1.0BB 4.0CC 7.0DD 10.0Name: d, dtype: float64>>> >>> frame.sub(series, axis='index') b d eAA -1.0 0.0 1.0BB -1.0 0.0 1.0CC -1.0 0.0 1.0DD -1.0 0.0 1.0 【01x04】Pandas 算术方法 完整的 Pandas 算术方法见下表: 方法副本描述 add()radd()加法(+) sub()、subtract()rsub()减法(-) mul()、multiply()rmul()乘法(*) pow()rpow()指数(**) truediv()、div()、divide()rdiv()除法(/) floordiv()rfloordiv()底除(//) mod()rmod()求余(%) 副本均为原方法前加了个 r,它会翻转参数: >>> import pandas as pd>>> obj = pd.DataFrame(np.arange(12.).reshape((3, 4)), columns=list('abcd'))>>> obj a b c d0 0.0 1.0 2.0 3.01 4.0 5.0 6.0 7.02 8.0 9.0 10.0 11.0>>> >>> 1 / obj a b c d0 inf 1.000000 0.500000 0.3333331 0.250 0.200000 0.166667 0.1428572 0.125 0.111111 0.100000 0.090909>>> >>> obj.rdiv(1) a b c d0 inf 1.000000 0.500000 0.3333331 0.250 0.200000 0.166667 0.1428572 0.125 0.111111 0.100000 0.090909 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106743778未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【02x00】处理缺失值 在现实中遇到的数据很少是干净整齐的,许多数据集都会有数据缺失的现象,缺失值主要有三种形式:null、NaN(NAN,nan) 或 NA。 【02x01】fill_value() 指定值与缺失值进行运算 使用 add, sub, div, mul 等算术方法时,通过 fill_value 指定填充值,未对齐的数据将和填充值做运算。 Series 中的应用: >>> import pandas as pd>>> obj1 = pd.Series([1, 2, 3, 4, 5])>>> obj2 = pd.Series([6, 7])>>> >>> obj10 11 22 33 44 5dtype: int64>>> >>> obj20 61 7dtype: int64>>> >>> obj1.add(obj2)0 7.01 9.02 NaN3 NaN4 NaNdtype: float64>>> >>> obj1.add(obj2, fill_value=-1)0 7.01 9.02 2.03 3.04 4.0dtype: float64 DataFrame 中的应用: >>> import pandas as pd>>> import numpy as np>>> obj1 = pd.DataFrame(np.arange(12.).reshape((3, 4)), columns=list('abcd'))>>> obj2 = pd.DataFrame(np.arange(20.).reshape((4, 5)), columns=list('abcde'))>>> >>> obj2.loc[1, 'b'] = np.nan>>> >>> obj1 a b c d0 0.0 1.0 2.0 3.01 4.0 5.0 6.0 7.02 8.0 9.0 10.0 11.0>>> >>> obj2 a b c d e0 0.0 1.0 2.0 3.0 4.01 5.0 NaN 7.0 8.0 9.02 10.0 11.0 12.0 13.0 14.03 15.0 16.0 17.0 18.0 19.0>>> >>> obj1 + obj2 a b c d e0 0.0 2.0 4.0 6.0 NaN1 9.0 NaN 13.0 15.0 NaN2 18.0 20.0 22.0 24.0 NaN3 NaN NaN NaN NaN NaN>>> >>> obj1.add(obj2, fill_value=10) a b c d e0 0.0 2.0 4.0 6.0 14.01 9.0 15.0 13.0 15.0 19.02 18.0 20.0 22.0 24.0 24.03 25.0 26.0 27.0 28.0 29.0 【02x02】isnull() / notnull() 判断缺失值 isnull():为缺失值时为 True,否则为 False; notnull() 为缺失值时为 False,否则为 True。 >>> import numpy as np>>> import pandas as pd>>> obj = pd.Series([1, np.nan, 'hello', None])>>> obj0 11 NaN2 hello3 Nonedtype: object>>> >>> obj.isnull()0 False1 True2 False3 Truedtype: bool>>> >>> obj.notnull()0 True1 False2 True3 Falsedtype: bool 【02x03】dropna() 删除缺失值 dropna() 方法用于返回一个删除了缺失值的新 Series 或 DataFrame 对象。 在 Series 对象当中,dropna() 方法的语法如下(其他参数用法可参考在 DataFrame 中的应用): Series.dropna(self, axis=0, inplace=False, how=None) 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.Series.dropna.html >>> import numpy as np>>> import pandas as pd>>> obj = pd.Series([1, np.nan, 'hello', None])>>> obj0 11 NaN2 hello3 Nonedtype: object>>> >>> obj.dropna()0 12 hellodtype: object 在 DataFrame 对象中,dropna() 方法的语法如下: DataFrame.dropna(self, axis=0, how='any', thresh=None, subset=None, inplace=False) 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.dropna.html 参数描述 axis确定是否删除包含缺失值的行或列 0 或 'index':删除包含缺失值的行。1 或 'columns':删除包含缺失值的列 how'any':如果存在任何NA值,则删除该行或列。'all':如果所有值都是NA,则删除该行或列 thresh设置行或列中非缺失值的最小数量 不传递任何参数,将会删除任何包含缺失值的整行数据: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame([[1, np.nan, 2], [2, 3, 5], [np.nan, 4, 6]])>>> obj 0 1 20 1.0 NaN 21 2.0 3.0 52 NaN 4.0 6>>> >>> obj.dropna() 0 1 21 2.0 3.0 5 指定 axis 参数,删除包含缺失值的行或列: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame([[1, np.nan, 2], [2, 3, 5], [np.nan, 4, 6]])>>> obj 0 1 20 1.0 NaN 21 2.0 3.0 52 NaN 4.0 6>>> >>> obj.dropna(axis='columns') 20 21 52 6 指定 how 参数,'any':如果存在任何NA值,则删除该行或列。'all':如果所有值都是NA,则删除该行或列: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame([[1, np.nan, 2, np.nan], [2, 3, 5, np.nan], [np.nan, 4, 6, np.nan]])>>> obj 0 1 2 30 1.0 NaN 2 NaN1 2.0 3.0 5 NaN2 NaN 4.0 6 NaN>>> obj.dropna(axis='columns', how='all') 0 1 20 1.0 NaN 21 2.0 3.0 52 NaN 4.0 6 指定 thresh 参数,设置行或列中非缺失值的最小数量,以下示例中,第一行和第三行只有两个非缺失值,所以会被删除: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame([[1, np.nan, 2, np.nan], [2, 3, 5, np.nan], [np.nan, 4, 6, np.nan]])>>> obj 0 1 2 30 1.0 NaN 2 NaN1 2.0 3.0 5 NaN2 NaN 4.0 6 NaN>>>>>> obj.dropna(axis='rows', thresh=3) 0 1 2 31 2.0 3.0 5 NaN 【02x04】fillna() 填充缺失值 fillna() 方法可以将缺失值替换成有效的数值。 在 Series 对象中,fillna() 方法的语法如下: Series.fillna(self, value=None, method=None, axis=None, inplace=False, limit=None, downcast=None) 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.Series.fillna.html 参数描述 value用于填充的值(例如 0),或者是一个 dict / Series / DataFrame 值 指定要用于每个 index(对于 Series)或column(对于 DataFrame)的值 不在dict / Series / DataFrame中的值将不被填充。此值不能是列表 method填充方法:None ‘pad’ / ‘ffill’:将上一个有效观测值向前传播到下一个有效观测值 ‘backfill’ / ‘bfill’:使用下一个有效观察值来填补空白 axis0 or ‘index’,要填充缺失值的轴 >>> import pandas as pd>>> obj = pd.Series([1, np.nan, 2, None, 3], index=list('abcde'))>>> obja 1.0b NaNc 2.0d NaNe 3.0dtype: float64>>> >>> obj.fillna(0)a 1.0b 0.0c 2.0d 0.0e 3.0dtype: float64>>> >>> obj.fillna(method='ffill')a 1.0b 1.0c 2.0d 2.0e 3.0dtype: float64>>> >>> obj.fillna(method='bfill')a 1.0b 2.0c 2.0d 3.0e 3.0dtype: float64 在 DataFrame 对象中,fillna() 方法的语法如下: DataFrame.fillna(self, value=None, method=None, axis=None, inplace=False, limit=None, downcast=None) 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.fillna.html 参数描述 value用于填充的值(例如 0),或者是一个 dict / Series / DataFrame 值 指定要用于每个 index(对于 Series)或column(对于 DataFrame)的值 不在dict / Series / DataFrame中的值将不被填充。此值不能是列表 method填充方法:None ‘pad’ / ‘ffill’:将上一个有效观测值向前传播到下一个有效观测值 ‘backfill’ / ‘bfill’:使用下一个有效观察值来填补空白 axis0 or ‘index’,1 or ‘columns’,要填充缺失值的轴 在 DataFrame 对象中的用法和在 Series 对象中的用法大同小异,只不过 axis 参数多了一个选择: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame([[1, np.nan, 2, np.nan], [2, 3, 5, np.nan], [np.nan, 4, 6, np.nan]])>>> obj 0 1 2 30 1.0 NaN 2 NaN1 2.0 3.0 5 NaN2 NaN 4.0 6 NaN>>> >>> obj.fillna(method='ffill', axis=1) 0 1 2 30 1.0 1.0 2.0 2.01 2.0 3.0 5.0 5.02 NaN 4.0 6.0 6.0 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106743778未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【1】Index 索引对象 【2】Pandas 一般索引 【2.1】Series 索引 【2.1.1】head() / tail() 【2.1.2】行索引 【2.1.3】切片索引 【2.1.4】花式索引 【2.1.5】布尔索引 【2.2】DataFrame 索引 【2.2.1】head() / tail() 【2.2.2】列索引 【2.2.3】切片索引 【2.2.4】花式索引 【2.2.5】布尔索引 【3】索引器:loc 和 iloc 【3.1】loc 标签索引 【3.1.1】Series.loc 【3.1.2】DataFrame.loc 【3.2】iloc 位置索引 【3.2.1】Series.iloc 【3.2.2】DataFrame.iloc 【4】Pandas 重新索引 Pandas 系列文章: Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象 Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作 Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理 Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引 Python 数据分析三剑客之 Pandas(五):统计计算与统计描述 Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并 Python 数据分析三剑客之 Pandas(七):合并数据集 Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换 Python 数据分析三剑客之 Pandas(九):时间序列 Python 数据分析三剑客之 Pandas(十):数据读写 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106698307未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【1】Index 索引对象 Series 和 DataFrame 中的索引都是 Index 对象,为了保证数据的安全,索引对象是不可变的,如果尝试更改索引就会报错;常见的 Index 种类有:索引(Index),整数索引(Int64Index),层级索引(MultiIndex),时间戳类型(DatetimeIndex)。 一下代码演示了 Index 索引对象和其不可变的性质: >>> import pandas as pd>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> obj.indexIndex(['a', 'b', 'c', 'd'], dtype='object')>>> type(obj.index)<class 'pandas.core.indexes.base.Index'>>>> obj.index[0] = 'e'Traceback (most recent call last): File "<pyshell#28>", line 1, in <module> obj.index[0] = 'e' File "C:\Users\...\base.py", line 3909, in __setitem__ raise TypeError("Index does not support mutable operations")TypeError: Index does not support mutable operations index 索引对象常用属性 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.Index.html 属性描述 T转置 arrayindex 的数组形式,常见官方文档 dtype返回基础数据的 dtype 对象 hasnans是否有 NaN(缺失值) inferred_type返回一个字符串,表示 index 的类型 is_monotonic判断 index 是否是递增的 is_monotonic_decreasing判断 index 是否单调递减 is_monotonic_increasing判断 index 是否单调递增 is_uniqueindex 是否没有重复值 nbytes返回 index 中的字节数 ndimindex 的维度 nlevelsNumber of levels. shape返回一个元组,表示 index 的形状 sizeindex 的大小 values返回 index 中的值 / 数组 >>> import pandas as pd>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> obj.indexIndex(['a', 'b', 'c', 'd'], dtype='object')>>> >>> obj.index.array<PandasArray>['a', 'b', 'c', 'd']Length: 4, dtype: object>>> >>> obj.index.dtypedtype('O')>>> >>> obj.index.hasnansFalse>>>>>> obj.index.inferred_type'string'>>> >>> obj.index.is_monotonicTrue>>>>>> obj.index.is_monotonic_decreasingFalse>>> >>> obj.index.is_monotonic_increasingTrue>>> >>> obj.index.is_uniqueTrue>>> >>> obj.index.nbytes16>>>>>> obj.index.ndim1>>>>>> obj.index.nlevels1>>>>>> obj.index.shape(4,)>>> >>> obj.index.size4>>> >>> obj.index.valuesarray(['a', 'b', 'c', 'd'], dtype=object) index 索引对象常用方法 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.Index.html 方法描述 all(self, *args, **kwargs)判断所有元素是否为真,有 0 会被视为 False any(self, *args, **kwargs)判断是否至少有一个元素为真,均为 0 会被视为 False append(self, other)连接另一个 index,产生一个新的 index argmax(self[, axis, skipna])返回 index 中最大值的索引值 argmin(self[, axis, skipna])返回 index 中最小值的索引值 argsort(self, *args, **kwargs)对 index 从小到大排序,返回排序后的元素在原 index 中的索引值 delete(self, loc)删除指定索引位置的元素,返回删除后的新 index difference(self, other[, sort])在第一个 index 中删除第二个 index 中的元素,即差集 drop(self, labels[, errors])在原 index 中删除传入的值 drop_duplicates(self[, keep])删除重复值,keep 参数可选值如下: ‘first’:保留第一次出现的重复项; ‘last’:保留最后一次出现的重复项; False:不保留重复项 duplicated(self[, keep])判断是否为重复值,keep 参数可选值如下: ‘first’:第一次重复的为 False,其他为 True; ‘last’:最后一次重复的为 False,其他为 True; False:所有重复的均为 True dropna(self[, how])删除缺失值,即 NaN fillna(self[, value, downcast])用指定值填充缺失值,即 NaN equals(self, other)判断两个 index 是否相同 insert(self, loc, item)将元素插入到指定索引处,返回新的 index intersection(self, other[, sort])返回两个 index 的交集 isna(self)检测 index 元素是否为缺失值,即 NaN isnull(self)检测 index 元素是否为缺失值,即 NaN max(self[, axis, skipna])返回 index 的最大值 min(self[, axis, skipna])返回 index 的最小值 union(self, other[, sort])返回两个 index 的并集 unique(self[, level])返回 index 中的唯一值,相当于去除重复值 all(self, *args, **kwargs) 【官方文档】 >>> import pandas as pd>>> pd.Index([1, 2, 3]).all()True>>>>>> pd.Index([0, 1, 2]).all()False any(self, *args, **kwargs) 【官方文档】 >>> import pandas as pd>>> pd.Index([0, 0, 1]).any()True>>>>>> pd.Index([0, 0, 0]).any()False append(self, other) 【官方文档】 >>> import pandas as pd>>> pd.Index(['a', 'b', 'c']).append(pd.Index([1, 2, 3]))Index(['a', 'b', 'c', 1, 2, 3], dtype='object') argmax(self[, axis, skipna]) 【官方文档】 >>> import pandas as pd>>> pd.Index([5, 2, 3, 9, 1]).argmax()3 argmin(self[, axis, skipna]) 【官方文档】 >>> import pandas as pd>>> pd.Index([5, 2, 3, 9, 1]).argmin()4 argsort(self, *args, **kwargs) 【官方文档】 >>> import pandas as pd>>> pd.Index([5, 2, 3, 9, 1]).argsort()array([4, 1, 2, 0, 3], dtype=int32) delete(self, loc) 【官方文档】 >>> import pandas as pd>>> pd.Index([5, 2, 3, 9, 1]).delete(0)Int64Index([2, 3, 9, 1], dtype='int64') difference(self, other[, sort]) 【官方文档】 >>> import pandas as pd>>> idx1 = pd.Index([2, 1, 3, 4])>>> idx2 = pd.Index([3, 4, 5, 6])>>> idx1.difference(idx2)Int64Index([1, 2], dtype='int64')>>> idx1.difference(idx2, sort=False)Int64Index([2, 1], dtype='int64') drop(self, labels[, errors]) 【官方文档】 >>> import pandas as pd>>> pd.Index([5, 2, 3, 9, 1]).drop([2, 1])Int64Index([5, 3, 9], dtype='int64') drop_duplicates(self[, keep]) 【官方文档】 >>> import pandas as pd>>> idx = pd.Index(['lama', 'cow', 'lama', 'beetle', 'lama', 'hippo'])>>> idx.drop_duplicates(keep='first')Index(['lama', 'cow', 'beetle', 'hippo'], dtype='object')>>> idx.drop_duplicates(keep='last')Index(['cow', 'beetle', 'lama', 'hippo'], dtype='object')>>> idx.drop_duplicates(keep=False)Index(['cow', 'beetle', 'hippo'], dtype='object') duplicated(self[, keep]) 【官方文档】 >>> import pandas as pd>>> idx = pd.Index(['lama', 'cow', 'lama', 'beetle', 'lama'])>>> idx.duplicated()array([False, False, True, False, True])>>> idx.duplicated(keep='first')array([False, False, True, False, True])>>> idx.duplicated(keep='last')array([ True, False, True, False, False])>>> idx.duplicated(keep=False)array([ True, False, True, False, True]) dropna(self[, how]) 【官方文档】 >>> import numpy as np>>> import pandas as pd>>> pd.Index([2, 5, np.NaN, 6, np.NaN, np.NaN]).dropna()Float64Index([2.0, 5.0, 6.0], dtype='float64') fillna(self[, value, downcast]) 【官方文档】 >>> import numpy as np>>> import pandas as pd>>> pd.Index([2, 5, np.NaN, 6, np.NaN, np.NaN]).fillna(5)Float64Index([2.0, 5.0, 5.0, 6.0, 5.0, 5.0], dtype='float64') equals(self, other) 【官方文档】 >>> import pandas as pd>>> idx1 = pd.Index([5, 2, 3, 9, 1])>>> idx2 = pd.Index([5, 2, 3, 9, 1])>>> idx1.equals(idx2)True>>> >>> idx1 = pd.Index([5, 2, 3, 9, 1])>>> idx2 = pd.Index([5, 2, 4, 9, 1])>>> idx1.equals(idx2)False intersection(self, other[, sort]) 【官方文档】 >>> import pandas as pd>>> idx1 = pd.Index([1, 2, 3, 4])>>> idx2 = pd.Index([3, 4, 5, 6])>>> idx1.intersection(idx2)Int64Index([3, 4], dtype='int64') insert(self, loc, item) 【官方文档】 >>> import pandas as pd>>> pd.Index([5, 2, 3, 9, 1]).insert(2, 'A')Index([5, 2, 'A', 3, 9, 1], dtype='object') isna(self) 【官方文档】、isnull(self) 【官方文档】 >>> import numpy as np>>> import pandas as pd>>> pd.Index([2, 5, np.NaN, 6, np.NaN, np.NaN]).isna()array([False, False, True, False, True, True])>>> pd.Index([2, 5, np.NaN, 6, np.NaN, np.NaN]).isnull()array([False, False, True, False, True, True]) max(self[, axis, skipna]) 【官方文档】、min(self[, axis, skipna]) 【官方文档】 >>> import pandas as pd>>> pd.Index([5, 2, 3, 9, 1]).max()9>>> pd.Index([5, 2, 3, 9, 1]).min()1 union(self, other[, sort]) 【官方文档】 >>> import pandas as pd>>> idx1 = pd.Index([1, 2, 3, 4])>>> idx2 = pd.Index([3, 4, 5, 6])>>> idx1.union(idx2)Int64Index([1, 2, 3, 4, 5, 6], dtype='int64') unique(self[, level]) 【官方文档】 >>> import pandas as pd>>> pd.Index([5, 1, 3, 5, 1]).unique()Int64Index([5, 1, 3], dtype='int64') 【2】Pandas 一般索引 由于在 Pandas 中,由于有一些更高级的索引操作,比如重新索引,层级索引等,因此将一般的切片索引、花式索引、布尔索引等归纳为一般索引。 【2.1】Series 索引 【2.1.1】head() / tail() Series.head() 和 Series.tail() 方法可以获取的前五行和后五行数据,如果向 head() / tail() 里面传入参数,则会获取指定行: >>> import pandas as pd>>> import numpy as np>>> obj = pd.Series(np.random.randn(8))>>> obj0 -0.6434371 -0.3656522 -0.9665543 -0.0361274 1.0460955 -2.0483626 -1.8655517 1.344728dtype: float64>>> >>> obj.head()0 -0.6434371 -0.3656522 -0.9665543 -0.0361274 1.046095dtype: float64>>> >>> obj.head(3)0 -0.6434371 -0.3656522 -0.966554dtype: float64>>>>>> obj.tail()3 1.2212214 -1.3734965 1.0328436 0.0297347 -1.861485dtype: float64>>>>>> obj.tail(3)5 1.0328436 0.0297347 -1.861485dtype: float64 【2.1.2】行索引 Pandas 中可以按照位置进行索引,也可以按照索引名(index)进行索引,也可以用 Python 字典的表达式和方法来获取值: >>> import pandas as pd>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> obja 1b 5c -8d 2dtype: int64>>> obj['c']-8>>> obj[2]-8>>> 'b' in objTrue>>> obj.keys()Index(['a', 'b', 'c', 'd'], dtype='object')>>> list(obj.items())[('a', 1), ('b', 5), ('c', -8), ('d', 2)] 【2.1.3】切片索引 切片的方法有两种:按位置切片和按索引名(index)切片,注意:按位置切片时,不包含终止索引;按索引名(index)切片时,包含终止索引。 >>> import pandas as pd>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> obja 1b 5c -8d 2dtype: int64>>>>>> obj[1:3]b 5c -8dtype: int64>>>>>> obj[0:3:2]a 1c -8dtype: int64>>>>>> obj['b':'d']b 5c -8d 2dtype: int64 【2.1.4】花式索引 所谓的花式索引,就是间隔索引、不连续的索引,传递一个由索引名(index)或者位置参数组成的列表来一次性获得多个元素: >>> import pandas as pd>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> obja 1b 5c -8d 2dtype: int64>>> >>> obj[[0, 2]]a 1c -8dtype: int64>>> >>> obj[['a', 'c', 'd']]a 1c -8d 2dtype: int64 【2.1.5】布尔索引 可以通过一个布尔数组来索引目标数组,即通过布尔运算(如:比较运算符)来获取符合指定条件的元素的数组。 >>> import pandas as pd>>> obj = pd.Series([1, 5, -8, 2, -3], index=['a', 'b', 'c', 'd', 'e'])>>> obja 1b 5c -8d 2e -3dtype: int64>>> >>> obj[obj > 0]a 1b 5d 2dtype: int64>>> >>> obj > 0a Trueb Truec Falsed Truee Falsedtype: bool 【2.2】DataFrame 索引 【2.2.1】head() / tail() 和 Series 一样,DataFrame.head() 和 DataFrame.tail() 方法同样可以获取 DataFrame 的前五行和后五行数据,如果向 head() / tail() 里面传入参数,则会获取指定行: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame(np.random.randn(8,4), columns = ['a', 'b', 'c', 'd'])>>> obj a b c d0 -1.399390 0.521596 -0.869613 0.5066211 -0.748562 -0.364952 0.188399 -1.4025662 1.378776 -1.476480 0.361635 0.4511343 -0.206405 -1.188609 3.002599 0.5636504 0.993289 1.133748 1.177549 -2.5622865 -0.482157 1.069293 1.143983 -1.3030796 -1.199154 0.220360 0.801838 -0.1045337 -1.359816 -2.092035 2.003530 -0.151812>>> >>> obj.head() a b c d0 -1.399390 0.521596 -0.869613 0.5066211 -0.748562 -0.364952 0.188399 -1.4025662 1.378776 -1.476480 0.361635 0.4511343 -0.206405 -1.188609 3.002599 0.5636504 0.993289 1.133748 1.177549 -2.562286>>> >>> obj.head(3) a b c d0 -1.399390 0.521596 -0.869613 0.5066211 -0.748562 -0.364952 0.188399 -1.4025662 1.378776 -1.476480 0.361635 0.451134>>>>>> obj.tail() a b c d3 -0.206405 -1.188609 3.002599 0.5636504 0.993289 1.133748 1.177549 -2.5622865 -0.482157 1.069293 1.143983 -1.3030796 -1.199154 0.220360 0.801838 -0.1045337 -1.359816 -2.092035 2.003530 -0.151812>>> >>> obj.tail(3) a b c d5 -0.482157 1.069293 1.143983 -1.3030796 -1.199154 0.220360 0.801838 -0.1045337 -1.359816 -2.092035 2.003530 -0.151812 【2.2.2】列索引 DataFrame 可以按照列标签(columns)来进行列索引: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame(np.random.randn(7,2), columns = ['a', 'b'])>>> obj a b0 -1.198795 0.9283781 -2.878230 0.0146502 2.267475 0.3709523 0.639340 -1.3010414 -1.953444 0.1489345 -0.445225 0.4596326 0.097109 -2.592833>>>>>> obj['a']0 -1.1987951 -2.8782302 2.2674753 0.6393404 -1.9534445 -0.4452256 0.097109Name: a, dtype: float64>>> >>> obj[['a']] a0 -1.1987951 -2.8782302 2.2674753 0.6393404 -1.9534445 -0.4452256 0.097109>>> >>> type(obj['a'])<class 'pandas.core.series.Series'>>>> type(obj[['a']])<class 'pandas.core.frame.DataFrame'> 【2.2.3】切片索引 DataFrame 中的切片索引是针对行来操作的,切片的方法有两种:按位置切片和按索引名(index)切片,注意:按位置切片时,不包含终止索引;按索引名(index)切片时,包含终止索引。 >>> import pandas as pd>>> import numpy as np>>> data = np.random.randn(5,4)>>> index = ['I1', 'I2', 'I3', 'I4', 'I5']>>> columns = ['a', 'b', 'c', 'd']>>> obj = pd.DataFrame(data, index, columns)>>> obj a b c dI1 0.828676 -1.663337 1.753632 1.432487I2 0.368138 0.222166 0.902764 -1.436186I3 2.285615 -2.415175 -1.344456 -0.502214I4 3.224288 -0.500268 1.293596 -1.235549I5 -0.938833 -0.804433 -0.170047 -0.566766>>> >>> obj[0:3] a b c dI1 0.828676 -1.663337 1.753632 1.432487I2 0.368138 0.222166 0.902764 -1.436186I3 2.285615 -2.415175 -1.344456 -0.502214>>>>>> obj[0:4:2] a b c dI1 -0.042168 1.437354 -1.114545 0.830790I3 0.241506 0.018984 -0.499151 -1.190143>>>>>> obj['I2':'I4'] a b c dI2 0.368138 0.222166 0.902764 -1.436186I3 2.285615 -2.415175 -1.344456 -0.502214I4 3.224288 -0.500268 1.293596 -1.235549 【2.2.4】花式索引 和 Series 一样,所谓的花式索引,就是间隔索引、不连续的索引,传递一个由列名(columns)组成的列表来一次性获得多列元素: >>> import pandas as pd>>> import numpy as np>>> data = np.random.randn(5,4)>>> index = ['I1', 'I2', 'I3', 'I4', 'I5']>>> columns = ['a', 'b', 'c', 'd']>>> obj = pd.DataFrame(data, index, columns)>>> obj a b c dI1 -1.083223 -0.182874 -0.348460 -1.572120I2 -0.205206 -0.251931 1.180131 0.847720I3 -0.980379 0.325553 -0.847566 -0.882343I4 -0.638228 -0.282882 -0.624997 -0.245980I5 -0.229769 1.002930 -0.226715 -0.916591>>> >>> obj[['a', 'd']] a dI1 -1.083223 -1.572120I2 -0.205206 0.847720I3 -0.980379 -0.882343I4 -0.638228 -0.245980I5 -0.229769 -0.916591 【2.2.5】布尔索引 可以通过一个布尔数组来索引目标数组,即通过布尔运算(如:比较运算符)来获取符合指定条件的元素的数组。 >>> import pandas as pd>>> import numpy as np>>> data = np.random.randn(5,4)>>> index = ['I1', 'I2', 'I3', 'I4', 'I5']>>> columns = ['a', 'b', 'c', 'd']>>> obj = pd.DataFrame(data, index, columns)>>> obj a b c dI1 -0.602984 -0.135716 0.999689 -0.339786I2 0.911130 -0.092485 -0.914074 -0.279588I3 0.849606 -0.420055 -1.240389 -0.179297I4 0.249986 -1.250668 0.329416 -1.105774I5 -0.743816 0.430647 -0.058126 -0.337319>>> >>> obj[obj > 0] a b c dI1 NaN NaN 0.999689 NaNI2 0.911130 NaN NaN NaNI3 0.849606 NaN NaN NaNI4 0.249986 NaN 0.329416 NaNI5 NaN 0.430647 NaN NaN>>> >>> obj > 0 a b c dI1 False False True FalseI2 True False False FalseI3 True False False FalseI4 True False True FalseI5 False True False False 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106698307未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【3】索引器:loc 和 iloc loc 是标签索引、iloc 是位置索引,注意:在 Pandas1.0.0 之前还有 ix 方法(即可按标签也可按位置索引),在 Pandas1.0.0 之后已被移除。 【3.1】loc 标签索引 loc 标签索引,即根据 index 和 columns 来选择数据。 【3.1.1】Series.loc 在 Series 中,允许输入: 单个标签,例如 5 或 'a',(注意,5 是 index 的名称,而不是位置索引); 标签列表或数组,例如 ['a', 'b', 'c']; 带有标签的切片对象,例如 'a':'f'。 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.Series.loc.html >>> import pandas as np>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> obja 1b 5c -8d 2dtype: int64>>> >>> obj.loc['a']1>>> >>> obj.loc['a':'c']a 1b 5c -8dtype: int64>>>>>> obj.loc[['a', 'd']]a 1d 2dtype: int64 【3.1.2】DataFrame.loc 在 DataFrame 中,第一个参数索引行,第二个参数是索引列,允许输入的格式和 Series 大同小异。 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.loc.html >>> import pandas as pd>>> obj = pd.DataFrame([[1, 2, 3], [4, 5, 6], [7, 8, 9]], index=['a', 'b', 'c'], columns=['A', 'B', 'C'])>>> obj A B Ca 1 2 3b 4 5 6c 7 8 9>>> >>> obj.loc['a']A 1B 2C 3Name: a, dtype: int64>>> >>> obj.loc['a':'c'] A B Ca 1 2 3b 4 5 6c 7 8 9>>> >>> obj.loc[['a', 'c']] A B Ca 1 2 3c 7 8 9>>> >>> obj.loc['b', 'B']5>>> obj.loc['b', 'A':'C']A 4B 5C 6Name: b, dtype: int64 【3.2】iloc 位置索引 作用和 loc 一样,不过是基于索引的编号来索引,即根据 index 和 columns 的位置编号来选择数据。 【3.2.1】Series.iloc 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.Series.iloc.html 在 Series 中,允许输入: 整数,例如 5; 整数列表或数组,例如 [4, 3, 0]; 具有整数的切片对象,例如 1:7。 >>> import pandas as np>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> obja 1b 5c -8d 2dtype: int64>>> >>> obj.iloc[1]5>>> >>> obj.iloc[0:2]a 1b 5dtype: int64>>> >>> obj.iloc[[0, 1, 3]]a 1b 5d 2dtype: int64 【3.2.2】DataFrame.iloc 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.iloc.html 在 DataFrame 中,第一个参数索引行,第二个参数是索引列,允许输入的格式和 Series 大同小异: >>> import pandas as pd>>> obj = pd.DataFrame([[1, 2, 3], [4, 5, 6], [7, 8, 9]], index=['a', 'b', 'c'], columns=['A', 'B', 'C'])>>> obj A B Ca 1 2 3b 4 5 6c 7 8 9>>> >>> obj.iloc[1]A 4B 5C 6Name: b, dtype: int64>>> >>> obj.iloc[0:2] A B Ca 1 2 3b 4 5 6>>> >>> obj.iloc[[0, 2]] A B Ca 1 2 3c 7 8 9>>> >>> obj.iloc[1, 2]6>>> >>> obj.iloc[1, 0:2]A 4B 5Name: b, dtype: int64 【4】Pandas 重新索引 Pandas 对象的一个重要方法是 reindex,其作用是创建一个新对象,它的数据符合新的索引。以 DataFrame.reindex 为例(Series 类似),基本语法如下: DataFrame.reindex(self, labels=None, index=None, columns=None, axis=None, method=None, copy=True, level=None, fill_value=nan, limit=None, tolerance=None) 部分参数描述如下:(完整参数解释参见官方文档) 参数描述 index用作索引的新序列,既可以是 index 实例,也可以是其他序列型的 Python 数据结构 method插值(填充)方式,取值如下: None:不填补空白; pad / ffill:将上一个有效的观测值向前传播到下一个有效的观测值; backfill / bfill:使用下一个有效观察值来填补空白; nearest:使用最近的有效观测值来填补空白。 fill_value在重新索引的过程中,需要引入缺失值时使用的替代值 limit前向或后向填充时的最大填充量 tolerance向前或向后填充时,填充不准确匹配项的最大间距(绝对值距离) level在 Multilndex 的指定级别上匹配简单索引,否则选其子集 copy默认为 True,无论如何都复制;如果为 False,则新旧相等就不复制 reindex 将会根据新索引进行重排。如果某个索引值当前不存在,就引入缺失值: >>> import pandas as pd>>> obj = pd.Series([4.5, 7.2, -5.3, 3.6], index=['d', 'b', 'a', 'c'])>>> objd 4.5b 7.2a -5.3c 3.6dtype: float64>>> >>> obj2 = obj.reindex(['a', 'b', 'c', 'd', 'e'])>>> obj2a -5.3b 7.2c 3.6d 4.5e NaNdtype: float64 对于时间序列这样的有序数据,重新索引时可能需要做一些插值处理。method 选项即可达到此目的,例如,使用 ffill 可以实现前向值填充: >>> import pandas as pd>>> obj = pd.Series(['blue', 'purple', 'yellow'], index=[0, 2, 4])>>> obj0 blue2 purple4 yellowdtype: object>>> >>> obj2 = obj.reindex(range(6), method='ffill')>>> obj20 blue1 blue2 purple3 purple4 yellow5 yellowdtype: object 借助 DataFrame,reindex可以修改(行)索引和列。只传递一个序列时,会重新索引结果的行: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame(np.arange(9).reshape((3, 3)), index=['a', 'c', 'd'], columns=['Ohio', 'Texas', 'California'])>>> obj Ohio Texas Californiaa 0 1 2c 3 4 5d 6 7 8>>> >>> obj2 = obj.reindex(['a', 'b', 'c', 'd'])>>> obj2 Ohio Texas Californiaa 0.0 1.0 2.0b NaN NaN NaNc 3.0 4.0 5.0d 6.0 7.0 8.0 列可以用 columns 关键字重新索引: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame(np.arange(9).reshape((3, 3)), index=['a', 'c', 'd'], columns=['Ohio', 'Texas', 'California'])>>> obj Ohio Texas Californiaa 0 1 2c 3 4 5d 6 7 8>>> >>> states = ['Texas', 'Utah', 'California']>>> obj.reindex(columns=states) Texas Utah Californiaa 1 NaN 2c 4 NaN 5d 7 NaN 8 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106698307未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【01x00】了解 Pandas 【02x00】Pandas 数据结构 【03x00】Series 对象 【03x01】通过 list 构建 Series 【03x02】通过 dict 构建 Series 【03x03】获取其数据和索引 【03x04】通过索引获取数据 【03x05】使用函数运算 【03x06】name 属性 【04x00】DataFrame 对象 【03x01】通过 ndarray 构建 DataFrame 【03x02】通过 dict 构建 DataFrame 【03x03】获取其数据和索引 【03x04】通过索引获取数据 【03x05】修改列的值 【03x06】增加 / 删除列 【03x07】name 属性 Pandas 系列文章: Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象 Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作 Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理 Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引 Python 数据分析三剑客之 Pandas(五):统计计算与统计描述 Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并 Python 数据分析三剑客之 Pandas(七):合并数据集 Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换 Python 数据分析三剑客之 Pandas(九):时间序列 Python 数据分析三剑客之 Pandas(十):数据读写 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106676693未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【01x00】了解 Pandas Pandas 是 Python 的一个数据分析包,是基于 NumPy 构建的,最初由 AQR Capital Management 于 2008 年 4 月开发,并于 2009 年底开源出来,目前由专注于 Python 数据包开发的 PyData 开发团队继续开发和维护,属于 PyData 项目的一部分。 Pandas 最初被作为金融数据分析工具而开发出来,因此,Pandas 为时间序列分析提供了很好的支持。Pandas 的名称来自于面板数据(panel data)和 Python 数据分析(data analysis)。panel data 是经济学中关于多维数据集的一个术语,在 Pandas 中也提供了 panel 的数据类型。 Pandas 经常和其它工具一同使用,如数值计算工具 NumPy 和 SciPy,分析库 statsmodels 和 scikit-learn,数据可视化库 Matplotlib 等,虽然 Pandas 采用了大量的 NumPy 编码风格,但二者最大的不同是 Pandas 是专门为处理表格和混杂数据设计的。而 NumPy 更适合处理统一的数值数组数据。 【以下对 Pandas 的解释翻译自官方文档:https://pandas.pydata.org/docs/getting_started/overview.html#package-overview】 Pandas 是 Python 的核心数据分析支持库,提供了快速、灵活、明确的数据结构,旨在简单、直观地处理关系型、标记型数据。Pandas 的目标是成为 Python 数据分析实践与实战的必备高级工具,其长远目标是成为最强大、最灵活、可以支持任何语言的开源数据分析工具。经过多年不懈的努力,Pandas 离这个目标已经越来越近了。 Pandas 适用于处理以下类型的数据: 与 SQL 或 Excel 表类似的,含异构列的表格数据; 有序和无序(非固定频率)的时间序列数据; 带行列标签的矩阵数据,包括同构或异构型数据; 任意其它形式的观测、统计数据集, 数据转入 Pandas 数据结构时不必事先标记。 Pandas 的主要数据结构是 Series(一维数据)与 DataFrame(二维数据),这两种数据结构足以处理- 金融、统计、社会科学、工程等领域里的大多数典型用例。对于 R 语言用户,DataFrame 提供了比 R 语言 data.frame 更丰富的功能。Pandas 基于 NumPy 开发,可以与其它第三方科学计算支持库完美集成。 Pandas 就像一把万能瑞士军刀,下面仅列出了它的部分优势 : 处理浮点与非浮点数据里的缺失数据,表示为 NaN; 大小可变:插入或删除 DataFrame 等多维对象的列; 自动、显式数据对齐:显式地将对象与一组标签对齐,也可以忽略标签,在 Series、DataFrame 计算时自动与数据对齐; 强大、灵活的分组(group by)功能:拆分-应用-组合数据集,聚合、转换数据; 把 Python 和 NumPy 数据结构里不规则、不同索引的数据轻松地转换为 DataFrame 对象; 基于智能标签,对大型数据集进行切片、花式索引、子集分解等操作; 直观地合并和连接数据集; 灵活地重塑和旋转数据集; 轴支持分层标签(每个刻度可能有多个标签); 强大的 IO 工具,读取平面文件(CSV 等支持分隔符的文件)、Excel 文件、数据库等来源的数据,以及从超快 HDF5 格式保存 / 加载数据; 时间序列:支持日期范围生成、频率转换、移动窗口统计、移动窗口线性回归、日期位移等时间序列功能。 这些功能主要是为了解决其它编程语言、科研环境的痛点。处理数据一般分为几个阶段:数据整理与清洗、数据分析与建模、数据可视化与制表,Pandas 是处理数据的理想工具。 其它说明: Pandas 速度很快。Pandas 的很多底层算法都用 Cython 优化过。然而,为了保持通用性,必然要牺牲一些性能,如果专注某一功能,完全可以开发出比 Pandas 更快的专用工具。 Pandas 是 statsmodels 的依赖项,因此,Pandas 也是 Python 中统计计算生态系统的重要组成部分。 Pandas 已广泛应用于金融领域。 【02x00】Pandas 数据结构 Pandas 的主要数据结构是 Series(带标签的一维同构数组)与 DataFrame(带标签的,大小可变的二维异构表格)。 Pandas 数据结构就像是低维数据的容器。比如,DataFrame 是 Series 的容器,Series 则是标量的容器。使用这种方式,可以在容器中以字典的形式插入或删除对象。 此外,通用 API 函数的默认操作要顾及时间序列与截面数据集的方向。当使用 Ndarray 存储二维或三维数据时,编写函数要注意数据集的方向,这对用户来说是一种负担;如果不考虑 C 或 Fortran 中连续性对性能的影响,一般情况下,不同的轴在程序里其实没有什么区别。Pandas 里,轴的概念主要是为了给数据赋予更直观的语义,即用更恰当的方式表示数据集的方向。这样做可以让用户编写数据转换函数时,少费点脑子。 处理 DataFrame 等表格数据时,对比 Numpy,index(行)或 columns(列)比 axis 0 和 axis 1 更直观。用这种方式迭代 DataFrame 的列,代码更易读易懂: for col in df.columns: series = df[col] # do something with series 【03x00】Series 对象 Series 是带标签的一维数组,可存储整数、浮点数、字符串、Python 对象等类型的数据。轴标签统称为索引。调用 pandas.Series 函数即可创建 Series,基本语法如下: pandas.Series(data=None[, index=None, dtype=None, name=None, copy=False, fastpath=False]) 参数描述 data数组类型,可迭代的,字典或标量值,存储在序列中的数据 index索引(数据标签),值必须是可哈希的,并且具有与数据相同的长度, 允许使用非唯一索引值。如果未提供,将默认为RangeIndex(0,1,2,…,n) dtype输出系列的数据类型。可选项,如果未指定,则将从数据中推断,具体参考官网 dtypes 介绍 namestr 类型,可选项,给 Series 命名 copybool 类型,可选项,默认 False,是否复制输入数据 【03x01】通过 list 构建 Series 一般情况下我们只会用到 data 和 index 参数,可以通过 list(列表) 构建 Series,示例如下: >>> import pandas as pd>>> obj = pd.Series([1, 5, -8, 2])>>> obj0 11 52 -83 2dtype: int64 由于我们没有为数据指定索引,于是会自动创建一个 0 到 N-1(N 为数据的长度)的整数型索引,左边一列是自动创建的索引(index),右边一列是数据(data)。 此外,还可以自定义索引(index): >>> import pandas as pd>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> obja 1b 5c -8d 2dtype: int64 索引(index)也可以通过赋值的方式就地修改: >>> import pandas as pd>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> obja 1b 5c -8d 2dtype: int64>>> obj.index = ['Bob', 'Steve', 'Jeff', 'Ryan']>>> objBob 1Steve 5Jeff -8Ryan 2dtype: int64 【03x02】通过 dict 构建 Series 通过 字典(dict) 构建 Series,字典的键(key)会作为索引(index),字典的值(value)会作为数据(data),示例如下: >>> import pandas as pd>>> data = {'Beijing': 21530000, 'Shanghai': 24280000, 'Wuhan': 11210000, 'Zhejiang': 58500000}>>> obj = pd.Series(data)>>> objBeijing 21530000Shanghai 24280000Wuhan 11210000Zhejiang 58500000dtype: int64 如果你想按照某个特定的顺序输出结果,可以传入排好序的字典的键以改变顺序: >>> import pandas as pd>>> data = {'Beijing': 21530000, 'Shanghai': 24280000, 'Wuhan': 11210000, 'Zhejiang': 58500000}>>> cities = ['Guangzhou', 'Wuhan', 'Zhejiang', 'Shanghai']>>> obj = pd.Series(data, index=cities)>>> objGuangzhou NaNWuhan 11210000.0Zhejiang 58500000.0Shanghai 24280000.0dtype: float64 注意:data 为字典,且未设置 index 参数时: 如果 Python >= 3.6 且 Pandas >= 0.23,Series 按字典的插入顺序排序索引。 如果 Python < 3.6 或 Pandas < 0.23,Series 按字母顺序排序索引。 【03x03】获取其数据和索引 我们可以通过 Series 的 values 和 index 属性获取其数据和索引对象: >>> import pandas as pd>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> obj.valuesarray([ 1, 5, -8, 2], dtype=int64)>>> obj.indexIndex(['a', 'b', 'c', 'd'], dtype='object') 【03x04】通过索引获取数据 与普通 NumPy 数组相比,Pandas 可以通过索引的方式选取 Series 中的单个或一组值,获取一组值时,传入的是一个列表,列表中的元素是索引值,另外还可以通过索引来修改其对应的值: >>> import pandas as pd>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> obja 1b 5c -8d 2dtype: int64>>> obj['a']1>>> obj['a'] = 3>>> obj[['a', 'b', 'c']]a 3b 5c -8dtype: int64 【03x05】使用函数运算 在 Pandas 中可以使用 NumPy 函数或类似 NumPy 的运算(如根据布尔型数组进行过滤、标量乘法、应用数学函数等): >>> import pandas as pd>>> import numpy as np>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> obj[obj > 0]a 1b 5d 2dtype: int64>>> obj * 2a 2b 10c -16d 4dtype: int64>>> np.exp(obj)a 2.718282b 148.413159c 0.000335d 7.389056dtype: float64 除了这些运算函数以外,还可以将 Series 看成是一个定长的有序字典,因为它是索引值到数据值的一个映射。它可以用在许多原本需要字典参数的函数中: >>> import pandas as pd>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> 'a' in objTrue>>> 'e' in objFalse 和 NumPy 类似,Pandas 中也有 NaN(即非数字,not a number),在 Pandas 中,它用于表示缺失值,Pandas 的 isnull 和 notnull 函数可用于检测缺失数据: >>> import pandas as pd>>> import numpy as np>>> obj = pd.Series([np.NaN, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> obja NaNb 5.0c -8.0d 2.0dtype: float64>>> pd.isnull(obj)a Trueb Falsec Falsed Falsedtype: bool>>> pd.notnull(obj)a Falseb Truec Trued Truedtype: bool>>> obj.isnull()a Trueb Falsec Falsed Falsedtype: bool>>> obj.notnull()a Falseb Truec Trued Truedtype: bool 【03x06】name 属性 可以在 pandas.Series 方法中为 Series 对象指定一个 name: >>> import pandas as pd>>> data = {'Beijing': 21530000, 'Shanghai': 24280000, 'Wuhan': 11210000, 'Zhejiang': 58500000}>>> obj = pd.Series(data, name='population')>>> objBeijing 21530000Shanghai 24280000Wuhan 11210000Zhejiang 58500000Name: population, dtype: int64 也可以通过 name 和 index.name 属性为 Series 对象和其索引指定 name: >>> import pandas as pd>>> data = {'Beijing': 21530000, 'Shanghai': 24280000, 'Wuhan': 11210000, 'Zhejiang': 58500000}>>> obj = pd.Series(data)>>> obj.name = 'population'>>> obj.index.name = 'cities'>>> objcitiesBeijing 21530000Shanghai 24280000Wuhan 11210000Zhejiang 58500000Name: population, dtype: int64 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106676693未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【04x00】DataFrame 对象 DataFrame 是一个表格型的数据结构,它含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔值等)。DataFrame 既有行索引也有列索引,它可以被看做由 Series 组成的字典(共用同一个索引)。DataFrame 中的数据是以一个或多个二维块存放的(而不是列表、字典或别的一维数据结构)。 类似多维数组/表格数据 (如Excel、R 语言中的 data.frame); 每列数据可以是不同的类型; 索引包括列索引和行索引 基本语法如下: pandas.DataFrame(data=None, index: Optional[Collection] = None, columns: Optional[Collection] = None, dtype: Union[str, numpy.dtype, ExtensionDtype, None] = None, copy: bool = False) 参数描述 datandarray 对象(结构化或同类的)、可迭代的或者字典形式,存储在序列中的数据 index数组类型,索引(数据标签),如果未提供,将默认为 RangeIndex(0,1,2,…,n) columns列标签。如果未提供,则将默认为 RangeIndex(0、1、2、…、n) dtype输出系列的数据类型。可选项,如果未指定,则将从数据中推断,具体参考官网 dtypes 介绍 copybool 类型,可选项,默认 False,是否复制输入数据,仅影响 DataFrame/2d ndarray 输入 【03x01】通过 ndarray 构建 DataFrame >>> import numpy as np>>> import pandas as pd>>> data = np.random.randn(5,3)>>> dataarray([[-2.16231157, 0.44967198, -0.73131523], [ 1.18982913, 0.94670798, 0.82973421], [-1.57680831, -0.99732066, 0.96432 ], [-0.77483149, -1.23802881, 0.44061227], [ 1.77666419, 0.24931983, -1.12960153]])>>> obj = pd.DataFrame(data)>>> obj 0 1 20 -2.162312 0.449672 -0.7313151 1.189829 0.946708 0.8297342 -1.576808 -0.997321 0.9643203 -0.774831 -1.238029 0.4406124 1.776664 0.249320 -1.129602 指定索引(index)和列标签(columns),和 Series 对象类似,可以在构建的时候添加索引和标签,也可以直接通过赋值的方式就地修改: >>> import numpy as np>>> import pandas as pd>>> data = np.random.randn(5,3)>>> index = ['a', 'b', 'c', 'd', 'e']>>> columns = ['A', 'B', 'C']>>> obj = pd.DataFrame(data, index, columns)>>> obj A B Ca -1.042909 -0.238236 -1.050308b 0.587079 0.739683 -0.233624c -0.451254 -0.638496 1.708807d -0.620158 -1.875929 -0.432382e -1.093815 0.396965 -0.759479>>>>>> obj.index = ['A1', 'A2', 'A3', 'A4', 'A5']>>> obj.columns = ['B1', 'B2', 'B3']>>> obj B1 B2 B3A1 -1.042909 -0.238236 -1.050308A2 0.587079 0.739683 -0.233624A3 -0.451254 -0.638496 1.708807A4 -0.620158 -1.875929 -0.432382A5 -1.093815 0.396965 -0.759479 【03x02】通过 dict 构建 DataFrame 通过 字典(dict) 构建 DataFrame,字典的键(key)会作为列标签(columns),字典的值(value)会作为数据(data),示例如下: >>> import pandas as pd>>> data = {'city': ['Wuhan', 'Wuhan', 'Wuhan', 'Beijing', 'Beijing', 'Beijing'], 'year': [2017, 2018, 2019, 2017, 2018, 2019], 'people': [10892900, 11081000, 11212000, 21707000, 21542000, 21536000]}>>> obj = pd.DataFrame(data)>>> obj city year people0 Wuhan 2017 108929001 Wuhan 2018 110810002 Wuhan 2019 112120003 Beijing 2017 217070004 Beijing 2018 215420005 Beijing 2019 21536000 如果指定了列序列,则 DataFrame 的列就会按照指定顺序进行排列,如果传入的列在数据中找不到,就会在结果中产生缺失值(NaN): >>> import pandas as pd>>> data = {'city': ['Wuhan', 'Wuhan', 'Wuhan', 'Beijing', 'Beijing', 'Beijing'], 'year': [2017, 2018, 2019, 2017, 2018, 2019], 'people': [10892900, 11081000, 11212000, 21707000, 21542000, 21536000]}>>> pd.DataFrame(data) city year people0 Wuhan 2017 108929001 Wuhan 2018 110810002 Wuhan 2019 112120003 Beijing 2017 217070004 Beijing 2018 215420005 Beijing 2019 21536000>>> pd.DataFrame(data, columns=['year', 'city', 'people']) year city people0 2017 Wuhan 108929001 2018 Wuhan 110810002 2019 Wuhan 112120003 2017 Beijing 217070004 2018 Beijing 215420005 2019 Beijing 21536000>>> pd.DataFrame(data, columns=['year', 'city', 'people', 'money']) year city people money0 2017 Wuhan 10892900 NaN1 2018 Wuhan 11081000 NaN2 2019 Wuhan 11212000 NaN3 2017 Beijing 21707000 NaN4 2018 Beijing 21542000 NaN5 2019 Beijing 21536000 NaN 注意:data 为字典,且未设置 columns 参数时: Python > = 3.6 且 Pandas > = 0.23,DataFrame 的列按字典的插入顺序排序。 Python < 3.6 或 Pandas < 0.23,DataFrame 的列按字典键的字母排序。 【03x03】获取其数据和索引 和 Series 一样,DataFrame 也可以通过其 values 和 index 属性获取其数据和索引对象: >>> import numpy as np>>> import pandas as pd>>> data = {'city': ['Wuhan', 'Wuhan', 'Wuhan', 'Beijing', 'Beijing', 'Beijing'], 'year': [2017, 2018, 2019, 2017, 2018, 2019], 'people': [10892900, 11081000, 11212000, 21707000, 21542000, 21536000]}>>> obj = pd.DataFrame(data)>>> obj.indexRangeIndex(start=0, stop=6, step=1)>>> obj.valuesarray([['Wuhan', 2017, 10892900], ['Wuhan', 2018, 11081000], ['Wuhan', 2019, 11212000], ['Beijing', 2017, 21707000], ['Beijing', 2018, 21542000], ['Beijing', 2019, 21536000]], dtype=object) 【03x04】通过索引获取数据 通过类似字典标记的方式或属性的方式,可以将 DataFrame 的列获取为一个 Series 对象; 行也可以通过位置或名称的方式进行获取,比如用 loc 属性; 对于特别大的 DataFrame,有一个 head 方法可以选取前五行数据。 用法示例: >>> import numpy as np>>> import pandas as pd>>> data = {'city': ['Wuhan', 'Wuhan', 'Wuhan', 'Beijing', 'Beijing', 'Beijing'], 'year': [2017, 2018, 2019, 2017, 2018, 2019], 'people': [10892900, 11081000, 11212000, 21707000, 21542000, 21536000]}>>> obj = pd.DataFrame(data)>>> obj city year people0 Wuhan 2017 108929001 Wuhan 2018 110810002 Wuhan 2019 112120003 Beijing 2017 217070004 Beijing 2018 215420005 Beijing 2019 21536000>>>>>> obj['city']0 Wuhan1 Wuhan2 Wuhan3 Beijing4 Beijing5 BeijingName: city, dtype: object>>>>>> obj.year0 20171 20182 20193 20174 20185 2019Name: year, dtype: int64>>>>>> type(obj.year)<class 'pandas.core.series.Series'>>>>>>> obj.loc[2]city Wuhanyear 2019people 11212000Name: 2, dtype: object>>>>>> obj.head() city year people0 Wuhan 2017 108929001 Wuhan 2018 110810002 Wuhan 2019 112120003 Beijing 2017 217070004 Beijing 2018 21542000 【03x05】修改列的值 列可以通过赋值的方式进行修改。在下面示例中,分别给"money"列赋上一个标量值和一组值: >>> import pandas as pd>>> import numpy as np>>> data = {'city': ['Wuhan', 'Wuhan', 'Wuhan', 'Beijing', 'Beijing', 'Beijing'], 'year': [2017, 2018, 2019, 2017, 2018, 2019], 'people': [10892900, 11081000, 11212000, 21707000, 21542000, 21536000], 'money':[np.NaN, np.NaN, np.NaN, np.NaN, np.NaN, np.NaN]}>>> obj = pd.DataFrame(data, index=['A', 'B', 'C', 'D', 'E', 'F'])>>> obj city year people moneyA Wuhan 2017 10892900 NaNB Wuhan 2018 11081000 NaNC Wuhan 2019 11212000 NaND Beijing 2017 21707000 NaNE Beijing 2018 21542000 NaNF Beijing 2019 21536000 NaN>>>>>> obj['money'] = 6666666666>>> obj city year people moneyA Wuhan 2017 10892900 6666666666B Wuhan 2018 11081000 6666666666C Wuhan 2019 11212000 6666666666D Beijing 2017 21707000 6666666666E Beijing 2018 21542000 6666666666F Beijing 2019 21536000 6666666666>>>>>> obj['money'] = np.arange(100000000, 700000000, 100000000)>>> obj city year people moneyA Wuhan 2017 10892900 100000000B Wuhan 2018 11081000 200000000C Wuhan 2019 11212000 300000000D Beijing 2017 21707000 400000000E Beijing 2018 21542000 500000000F Beijing 2019 21536000 600000000 将列表或数组赋值给某个列时,其长度必须跟 DataFrame 的长度相匹配。如果赋值的是一个 Series,就会精确匹配 DataFrame 的索引: >>> import pandas as pd>>> import numpy as np>>> data = {'city': ['Wuhan', 'Wuhan', 'Wuhan', 'Beijing', 'Beijing', 'Beijing'], 'year': [2017, 2018, 2019, 2017, 2018, 2019], 'people': [10892900, 11081000, 11212000, 21707000, 21542000, 21536000], 'money':[np.NaN, np.NaN, np.NaN, np.NaN, np.NaN, np.NaN]}>>> obj = pd.DataFrame(data, index=['A', 'B', 'C', 'D', 'E', 'F'])>>> obj city year people moneyA Wuhan 2017 10892900 NaNB Wuhan 2018 11081000 NaNC Wuhan 2019 11212000 NaND Beijing 2017 21707000 NaNE Beijing 2018 21542000 NaNF Beijing 2019 21536000 NaN>>> >>> new_data = pd.Series([5670000000, 6890000000, 7890000000], index=['A', 'C', 'E'])>>> obj['money'] = new_data>>> obj city year people moneyA Wuhan 2017 10892900 5.670000e+09B Wuhan 2018 11081000 NaNC Wuhan 2019 11212000 6.890000e+09D Beijing 2017 21707000 NaNE Beijing 2018 21542000 7.890000e+09F Beijing 2019 21536000 NaN 【03x06】增加 / 删除列 为不存在的列赋值会创建出一个新列,关键字 del 用于删除列: >>> import pandas as pd>>> data = {'city': ['Wuhan', 'Wuhan', 'Wuhan', 'Beijing', 'Beijing', 'Beijing'], 'year': [2017, 2018, 2019, 2017, 2018, 2019], 'people': [10892900, 11081000, 11212000, 21707000, 21542000, 21536000]}>>> obj = pd.DataFrame(data)>>> obj city year people0 Wuhan 2017 108929001 Wuhan 2018 110810002 Wuhan 2019 112120003 Beijing 2017 217070004 Beijing 2018 215420005 Beijing 2019 21536000>>> >>> obj['northern'] = obj['city'] == 'Beijing'>>> obj city year people northern0 Wuhan 2017 10892900 False1 Wuhan 2018 11081000 False2 Wuhan 2019 11212000 False3 Beijing 2017 21707000 True4 Beijing 2018 21542000 True5 Beijing 2019 21536000 True>>> >>> del obj['northern']>>> obj city year people0 Wuhan 2017 108929001 Wuhan 2018 110810002 Wuhan 2019 112120003 Beijing 2017 217070004 Beijing 2018 215420005 Beijing 2019 21536000 【03x07】name 属性 可以通过 index.name 和 columns.name 属性设置索引(index)和列标签(columns)的 name,注意 DataFrame 对象是没有 name 属性的: >>> import pandas as pd>>> data = {'city': ['Wuhan', 'Wuhan', 'Wuhan', 'Beijing', 'Beijing', 'Beijing'], 'year': [2017, 2018, 2019, 2017, 2018, 2019], 'people': [10892900, 11081000, 11212000, 21707000, 21542000, 21536000]}>>> obj = pd.DataFrame(data)>>> obj.index.name = 'index'>>> obj.columns.name = 'columns'>>> objcolumns city year peopleindex 0 Wuhan 2017 108929001 Wuhan 2018 110810002 Wuhan 2019 112120003 Beijing 2017 217070004 Beijing 2018 215420005 Beijing 2019 21536000 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106676693未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【1x00】介绍(Introduction) 【2x00】准备工作(Setup) 【3x00】关联(Correlation) 【01】散点图(Scatter plot) 【02】带边界的气泡图(Bubble plot with Encircling) 【03】带线性回归最佳拟合线的散点图(Scatter plot with linear regression line of best fit) 【04】抖动图(Jittering with stripplot) 【05】计数图(Counts Plot) 【06】边缘直方图(Marginal Histogram) 【07】边缘箱形图(Marginal Boxplot) 【08】相关图(Correllogram) 【09】成对图(Pairwise Plot) 【4x00】偏差(Deviation) 【10】发散型条形图(Diverging Bars) 【11】发散型文本图(Diverging Texts) 【12】发散型散点图(Diverging Dot Plot) 【13】带标记的发散型棒棒糖图(Diverging Lollipop Chart with Markers) 【14】面积图(Area Chart) 【5x00】排序(Ranking) 【15】有序条形图(Ordered Bar Chart) 【16】棒棒糖图(Lollipop Chart) 【17】点图(Dot Plot) 【18】坡度图(Slope Chart) 【19】哑铃图(Dumbbell Plot) 【6x00】分布(Distribution) 【20】连续变量的直方图(Histogram for Continuous Variable) 【21】分类变量的直方图(Histogram for Categorical Variable) 【22】密度图(Density Plot) 【23】直方图密度曲线(Density Curves with Histogram) 【24】山峰叠峦图 / 欢乐图(Joy Plot) 【25】分布式点图(Distributed Dot Plot) 【26】箱形图(Box Plot) 【27】点 + 箱形图(Dot + Box Plot) 【28】小提琴图(Violin Plot) 【29】人口金字塔图(Population Pyramid) 【30】分类图(Categorical Plots) 【7x00】组成(Composition) 【31】华夫饼图(Waffle Chart) 【32】饼图(Pie Chart) 【33】矩阵树形图(Treemap) 【34】条形图(Bar Chart) 【8x00】变化(Change) 【35】时间序列图(Time Series Plot) 【36】带波峰和波谷注释的时间序列图(Time Series with Peaks and Troughs Annotated) 【37】自相关 (ACF) 和部分自相关 (PACF) 图(Autocorrelation (ACF) and Partial Autocorrelation (PACF) Plot) 【38】交叉相关图(Cross Correlation plot) 【39】时间序列分解图(Time Series Decomposition Plot) 【40】多重时间序列(Multiple Time Series) 【41】使用次要的 Y 轴来绘制不同范围的图形(Plotting with different scales using secondary Y axis) 【42】带误差带的时间序列(Time Series with Error Bands) 【43】堆积面积图(Stacked Area Chart) 【44】未堆积面积图(Area Chart UnStacked) 【45】日历热力图(Calendar Heat Map) 【46】季节图(Seasonal Plot) 【9x00】分组( Groups) 【47】树状图(Dendrogram) 【48】聚类图(Cluster Plot) 【49】安德鲁斯曲线(Andrews Curve) 【50】平行坐标图(Parallel Coordinates) Matplotlib 系列文章: Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件 Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性 Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性 Python 数据分析三剑客之 Matplotlib(四):线性图的绘制 Python 数据分析三剑客之 Matplotlib(五):散点图的绘制 Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制 Python 数据分析三剑客之 Matplotlib(七):饼状图的绘制 Python 数据分析三剑客之 Matplotlib(八):等高线 / 等值线图的绘制 Python 数据分析三剑客之 Matplotlib(九):极区图 / 极坐标图 / 雷达图的绘制 Python 数据分析三剑客之 Matplotlib(十):3D 图的绘制 Python 数据分析三剑客之 Matplotlib(十一):最热门最常用的 50 个图表【译文】 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 翻译丨TRHX 作者丨Selva Prabhakaran 原文丨《Top 50 matplotlib Visualizations – The Master Plots (with full python code)》 ★ 本文中的示例原作者使用的编辑器为 Jupyter Notebook; ★ 译者使用 PyCharm 测试原文中有部分代码不太准确,部分已进行修改,对应有注释说明; ★ 运行本文代码,需要安装 Matplotlib 和 Seaborn 等可视化库,其他的一些辅助可视化库已在代码部分作标注; ★ 示例中用到的数据均储存在作者的 GitHub:https://github.com/selva86/datasets,因此运行程序可能需要FQ; ★ 译者英文水平有限,若遇到翻译模糊的词建议参考原文来理解。 ★ 本文50个示例代码已打包为 .py 文件,可直接下载:https://download.csdn.net/download/qq_36759224/12507219 这里是一段物理防爬虫文本,请读者忽略。本译文首发于 CSDN,作者 Selva Prabhakaran,译者 TRHX。本文链接:https://itrhx.blog.csdn.net/article/details/106558131原文链接:https://www.machinelearningplus.com/plots/top-50-matplotlib-visualizations-the-master-plots-python/ 【1x00】介绍(Introduction) 在数据分析和可视化中最常用的、最有价值的前 50 个 Matplotlib 图表。这些图表会让你懂得在不同情况下合理使用 Python 的 Matplotlib 和 Seaborn 库来达到数据可视化效果。 这些图表根据可视化目标的 7 个不同情景进行分组。 例如,如果要想象两个变量之间的关系,请查看“关联”部分下的图表。 或者,如果您想要显示值如何随时间变化,请查看“变化”部分,依此类推。 有效图表的重要特征: 在不歪曲事实的情况下传达正确和必要的信息; 设计简单,不必太费力就能理解它; 从审美角度支持信息而不是掩盖信息; 信息没有超负荷。 【2x00】准备工作(Setup) 在代码运行前先引入下面的基本设置,当然,个别图表可能会重新定义显示要素。 # !pip install brewer2mplimport numpy as npimport pandas as pdimport matplotlib as mplimport matplotlib.pyplot as pltimport seaborn as snsimport warnings; warnings.filterwarnings(action='once')large = 22; med = 16; small = 12params = {'axes.titlesize': large, 'legend.fontsize': med, 'figure.figsize': (16, 10), 'axes.labelsize': med, 'axes.titlesize': med, 'xtick.labelsize': med, 'ytick.labelsize': med, 'figure.titlesize': large}plt.rcParams.update(params)plt.style.use('seaborn-whitegrid')sns.set_style("white")%matplotlib inline# Versionprint(mpl.__version__) #> 3.0.0print(sns.__version__) #> 0.9.0 【3x00】关联(Correlation) 关联图用于可视化两个或多个变量之间的关系。也就是说,一个变量相对于另一个变量如何变化。 【01】散点图(Scatter plot) 散点图是研究两个变量之间关系的经典和基本的绘图。如果数据中有多个组,则可能需要以不同的颜色显示每个组。在 Matplotlib 中,您可以使用 plt.scatterplot() 方便地执行此操作。 # Import dataset midwest = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/midwest_filter.csv")# Prepare Data # Create as many colors as there are unique midwest['category']categories = np.unique(midwest['category'])colors = [plt.cm.tab10(i/float(len(categories)-1)) for i in range(len(categories))]# Draw Plot for Each Categoryplt.figure(figsize=(16, 10), dpi= 80, facecolor='w', edgecolor='k')for i, category in enumerate(categories): plt.scatter('area', 'poptotal', data=midwest.loc[midwest.category==category, :], s=20, cmap=colors[i], label=str(category))# 原文 c=colors[i] 已修改为 cmap=colors[i]# Decorationsplt.gca().set(xlim=(0.0, 0.1), ylim=(0, 90000), xlabel='Area', ylabel='Population')plt.xticks(fontsize=12); plt.yticks(fontsize=12)plt.title("Scatterplot of Midwest Area vs Population", fontsize=22)plt.legend(fontsize=12)plt.show() 【02】带边界的气泡图(Bubble plot with Encircling) 有时候您想在一个边界内显示一组点来强调它们的重要性。在本例中,您将从被包围的数据中获取记录,并将其传递给下面的代码中描述的 encircle()。 from matplotlib import patchesfrom scipy.spatial import ConvexHullimport warnings; warnings.simplefilter('ignore')sns.set_style("white")# Step 1: Prepare Datamidwest = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/midwest_filter.csv")# As many colors as there are unique midwest['category']categories = np.unique(midwest['category'])colors = [plt.cm.tab10(i/float(len(categories)-1)) for i in range(len(categories))]# Step 2: Draw Scatterplot with unique color for each categoryfig = plt.figure(figsize=(16, 10), dpi=80, facecolor='w', edgecolor='k')for i, category in enumerate(categories): plt.scatter('area', 'poptotal', data=midwest.loc[midwest.category == category, :], s='dot_size', cmap=colors[i], label=str(category), edgecolors='black', linewidths=.5)# 原文 c=colors[i] 已修改为 cmap=colors[i]# Step 3: Encircling# https://stackoverflow.com/questions/44575681/how-do-i-encircle-different-data-sets-in-scatter-plotdef encircle(x,y, ax=None, **kw): if not ax: ax = plt.gca() p = np.c_[x, y] hull = ConvexHull(p) poly = plt.Polygon(p[hull.vertices, :], **kw) ax.add_patch(poly)# Select data to be encircledmidwest_encircle_data = midwest.loc[midwest.state=='IN', :]# Draw polygon surrounding verticesencircle(midwest_encircle_data.area, midwest_encircle_data.poptotal, ec="k", fc="gold", alpha=0.1)encircle(midwest_encircle_data.area, midwest_encircle_data.poptotal, ec="firebrick", fc="none", linewidth=1.5)# Step 4: Decorationsplt.gca().set(xlim=(0.0, 0.1), ylim=(0, 90000), xlabel='Area', ylabel='Population')plt.xticks(fontsize=12); plt.yticks(fontsize=12)plt.title("Bubble Plot with Encircling", fontsize=22)plt.legend(fontsize=12)plt.show() 【03】带线性回归最佳拟合线的散点图(Scatter plot with linear regression line of best fit) 如果你想了解两个变量之间是如何变化的,那么最佳拟合线就是常用的方法。下图显示了数据中不同组之间的最佳拟合线的差异。若要禁用分组并只为整个数据集绘制一条最佳拟合线,请从 sns.lmplot() 方法中删除 hue ='cyl' 参数。 # Import Datadf = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/mpg_ggplot2.csv")df_select = df.loc[df.cyl.isin([4, 8]), :]# Plotsns.set_style("white")gridobj = sns.lmplot(x="displ", y="hwy", hue="cyl", data=df_select, height=7, aspect=1.6, robust=True, palette='tab10', scatter_kws=dict(s=60, linewidths=.7, edgecolors='black'))# Decorationsgridobj.set(xlim=(0.5, 7.5), ylim=(0, 50))plt.title("Scatterplot with line of best fit grouped by number of cylinders", fontsize=20)plt.show() 针对每一组数据绘制线性回归线(Each regression line in its own column),可以通过在 sns.lmplot() 中设置 col=groupingcolumn 参数来实现,如下: # Import Datadf = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/mpg_ggplot2.csv")df_select = df.loc[df.cyl.isin([4, 8]), :]# Each line in its own columnsns.set_style("white")gridobj = sns.lmplot(x="displ", y="hwy", data=df_select, height=7, robust=True, palette='Set1', col="cyl", scatter_kws=dict(s=60, linewidths=.7, edgecolors='black'))# Decorationsgridobj.set(xlim=(0.5, 7.5), ylim=(0, 50))plt.show() 【04】抖动图(Jittering with stripplot) 通常,多个数据点具有完全相同的 X 和 Y 值。 此时多个点绘制会重叠并隐藏。为避免这种情况,可以将数据点稍微抖动,以便可以直观地看到它们。 使用 seaborn 库的 stripplot() 方法可以很方便的实现这个功能。 # Import Datadf = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/mpg_ggplot2.csv")# Draw Stripplotfig, ax = plt.subplots(figsize=(16,10), dpi= 80)sns.stripplot(df.cty, df.hwy, jitter=0.25, size=8, ax=ax, linewidth=.5)# Decorationsplt.title('Use jittered plots to avoid overlapping of points', fontsize=22)plt.show() 【05】计数图(Counts Plot) 避免点重叠问题的另一个选择是根据点的位置增加点的大小。所以,点的大小越大,它周围的点就越集中。 # Import Datadf = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/mpg_ggplot2.csv")df_counts = df.groupby(['hwy', 'cty']).size().reset_index(name='counts')# Draw Stripplotfig, ax = plt.subplots(figsize=(16,10), dpi= 80) # 原文代码# sns.stripplot(df_counts.cty, df_counts.hwy, size=df_counts.counts*2, ax=ax)# 纠正代码sns.stripplot(df_counts.cty, df_counts.hwy, sizes=df_counts.counts*2, ax=ax)# Decorationsplt.title('Counts Plot - Size of circle is bigger as more points overlap', fontsize=22)plt.show() 【06】边缘直方图(Marginal Histogram) 边缘直方图是具有沿 X 和 Y 轴变量的直方图。 这用于可视化 X 和 Y 之间的关系以及单独的 X 和 Y 的单变量分布。 这种图经常用于探索性数据分析(EDA)。 # Import Datadf = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/mpg_ggplot2.csv")# Create Fig and gridspecfig = plt.figure(figsize=(16, 10), dpi= 80)grid = plt.GridSpec(4, 4, hspace=0.5, wspace=0.2)# Define the axesax_main = fig.add_subplot(grid[:-1, :-1])ax_right = fig.add_subplot(grid[:-1, -1], xticklabels=[], yticklabels=[])ax_bottom = fig.add_subplot(grid[-1, 0:-1], xticklabels=[], yticklabels=[])# Scatterplot on main axax_main.scatter('displ', 'hwy', s=df.cty*4, c=df.manufacturer.astype('category').cat.codes, alpha=.9, data=df, cmap="tab10", edgecolors='gray', linewidths=.5)# histogram on the rightax_bottom.hist(df.displ, 40, histtype='stepfilled', orientation='vertical', color='deeppink')ax_bottom.invert_yaxis()# histogram in the bottomax_right.hist(df.hwy, 40, histtype='stepfilled', orientation='horizontal', color='deeppink')# Decorationsax_main.set(title='Scatterplot with Histograms \n displ vs hwy', xlabel='displ', ylabel='hwy')ax_main.title.set_fontsize(20)for item in ([ax_main.xaxis.label, ax_main.yaxis.label] + ax_main.get_xticklabels() + ax_main.get_yticklabels()): item.set_fontsize(14)xlabels = ax_main.get_xticks().tolist()ax_main.set_xticklabels(xlabels)plt.show() 【07】边缘箱形图(Marginal Boxplot) 边缘箱形图与边缘直方图具有相似的用途。 然而,箱线图有助于精确定位 X 和 Y 的中位数、第25和第75百分位数。 # Import Datadf = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/mpg_ggplot2.csv")# Create Fig and gridspecfig = plt.figure(figsize=(16, 10), dpi= 80)grid = plt.GridSpec(4, 4, hspace=0.5, wspace=0.2)# Define the axesax_main = fig.add_subplot(grid[:-1, :-1])ax_right = fig.add_subplot(grid[:-1, -1], xticklabels=[], yticklabels=[])ax_bottom = fig.add_subplot(grid[-1, 0:-1], xticklabels=[], yticklabels=[])# Scatterplot on main axax_main.scatter('displ', 'hwy', s=df.cty*5, c=df.manufacturer.astype('category').cat.codes, alpha=.9, data=df, cmap="Set1", edgecolors='black', linewidths=.5)# Add a graph in each partsns.boxplot(df.hwy, ax=ax_right, orient="v")sns.boxplot(df.displ, ax=ax_bottom, orient="h")# Decorations ------------------# Remove x axis name for the boxplotax_bottom.set(xlabel='')ax_right.set(ylabel='')# Main Title, Xlabel and YLabelax_main.set(title='Scatterplot with Histograms \n displ vs hwy', xlabel='displ', ylabel='hwy')# Set font size of different componentsax_main.title.set_fontsize(20)for item in ([ax_main.xaxis.label, ax_main.yaxis.label] + ax_main.get_xticklabels() + ax_main.get_yticklabels()): item.set_fontsize(14)plt.show() 【08】相关图(Correllogram) 相关图用于直观地查看给定数据帧(或二维数组)中所有可能的数值变量对之间的相关性度量。 # Import Datasetdf = pd.read_csv("https://github.com/selva86/datasets/raw/master/mtcars.csv")# Plotplt.figure(figsize=(12, 10), dpi=80)sns.heatmap(df.corr(), xticklabels=df.corr().columns, yticklabels=df.corr().columns, cmap='RdYlGn', center=0, annot=True)# Decorationsplt.title('Correlogram of mtcars', fontsize=22)plt.xticks(fontsize=12)plt.yticks(fontsize=12)plt.show() 【09】成对图(Pairwise Plot) 成对图是探索性分析中最受欢迎的一种方法,用来理解所有可能的数值变量对之间的关系。它是二元分析的必备工具。 # Load Datasetdf = sns.load_dataset('iris')# Plotplt.figure(figsize=(10, 8), dpi=80)sns.pairplot(df, kind="scatter", hue="species", plot_kws=dict(s=80, edgecolor="white", linewidth=2.5))plt.show() # Load Datasetdf = sns.load_dataset('iris')# Plotplt.figure(figsize=(10, 8), dpi=80)sns.pairplot(df, kind="reg", hue="species")plt.show() 【4x00】偏差(Deviation) 【10】发散型条形图(Diverging Bars) 如果您想根据单个指标查看项目的变化情况,并可视化此差异的顺序和数量,那么散型条形图是一个很好的工具。 它有助于快速区分数据组的性能,并且非常直观,并且可以立即传达这一点。 # Prepare Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/mtcars.csv")x = df.loc[:, ['mpg']]df['mpg_z'] = (x - x.mean())/x.std()df['colors'] = ['red' if x < 0 else 'green' for x in df['mpg_z']]df.sort_values('mpg_z', inplace=True)df.reset_index(inplace=True)# Draw plotplt.figure(figsize=(14,10), dpi= 80)plt.hlines(y=df.index, xmin=0, xmax=df.mpg_z, color=df.colors, alpha=0.4, linewidth=5)# Decorationsplt.gca().set(ylabel='$Model$', xlabel='$Mileage$')plt.yticks(df.index, df.cars, fontsize=12)plt.title('Diverging Bars of Car Mileage', fontdict={'size':20})plt.grid(linestyle='--', alpha=0.5)plt.show() 【11】发散型文本图(Diverging Texts) 发散型文本图与发散型条形图相似,如果你希望以一种美观的方式显示图表中每个项目的值,就可以使用这种方法。 # Prepare Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/mtcars.csv")x = df.loc[:, ['mpg']]df['mpg_z'] = (x - x.mean())/x.std()df['colors'] = ['red' if x < 0 else 'green' for x in df['mpg_z']]df.sort_values('mpg_z', inplace=True)df.reset_index(inplace=True)# Draw plotplt.figure(figsize=(14, 14), dpi=80)plt.hlines(y=df.index, xmin=0, xmax=df.mpg_z)for x, y, tex in zip(df.mpg_z, df.index, df.mpg_z): t = plt.text(x, y, round(tex, 2), horizontalalignment='right' if x < 0 else 'left', verticalalignment='center', fontdict={'color':'red' if x < 0 else 'green', 'size':14})# Decorationsplt.yticks(df.index, df.cars, fontsize=12)plt.title('Diverging Text Bars of Car Mileage', fontdict={'size':20})plt.grid(linestyle='--', alpha=0.5)plt.xlim(-2.5, 2.5)plt.show() 【12】发散型散点图(Diverging Dot Plot) 发散型散点图类似于发散型条形图。 但是,与发散型条形图相比,没有条形会减少组之间的对比度和差异。 # Prepare Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/mtcars.csv")x = df.loc[:, ['mpg']]df['mpg_z'] = (x - x.mean())/x.std()df['colors'] = ['red' if x < 0 else 'darkgreen' for x in df['mpg_z']]df.sort_values('mpg_z', inplace=True)df.reset_index(inplace=True)# Draw plotplt.figure(figsize=(14, 16), dpi=80)plt.scatter(df.mpg_z, df.index, s=450, alpha=.6, color=df.colors)for x, y, tex in zip(df.mpg_z, df.index, df.mpg_z): t = plt.text(x, y, round(tex, 1), horizontalalignment='center', verticalalignment='center', fontdict={'color': 'white'})# Decorations# Lighten bordersplt.gca().spines["top"].set_alpha(.3)plt.gca().spines["bottom"].set_alpha(.3)plt.gca().spines["right"].set_alpha(.3)plt.gca().spines["left"].set_alpha(.3)plt.yticks(df.index, df.cars)plt.title('Diverging Dotplot of Car Mileage', fontdict={'size': 20})plt.xlabel('$Mileage$')plt.grid(linestyle='--', alpha=0.5)plt.xlim(-2.5, 2.5)plt.show() 【13】带标记的发散型棒棒糖图(Diverging Lollipop Chart with Markers) 带有标记的棒棒糖提供了一种灵活的方式,强调您想要引起注意的任何重要数据点并在图表中适当地给出推理。 # Prepare Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/mtcars.csv")x = df.loc[:, ['mpg']]df['mpg_z'] = (x - x.mean())/x.std()df['colors'] = 'black'# color fiat differentlydf.loc[df.cars == 'Fiat X1-9', 'colors'] = 'darkorange'df.sort_values('mpg_z', inplace=True)df.reset_index(inplace=True)# Draw plotimport matplotlib.patches as patchesplt.figure(figsize=(14, 16), dpi=80)plt.hlines(y=df.index, xmin=0, xmax=df.mpg_z, color=df.colors, alpha=0.4, linewidth=1)plt.scatter(df.mpg_z, df.index, color=df.colors, s=[600 if x == 'Fiat X1-9' else 300 for x in df.cars], alpha=0.6)plt.yticks(df.index, df.cars)plt.xticks(fontsize=12)# Annotateplt.annotate('Mercedes Models', xy=(0.0, 11.0), xytext=(1.0, 11), xycoords='data', fontsize=15, ha='center', va='center', bbox=dict(boxstyle='square', fc='firebrick'), arrowprops=dict(arrowstyle='-[, widthB=2.0, lengthB=1.5', lw=2.0, color='steelblue'), color='white')# Add Patchesp1 = patches.Rectangle((-2.0, -1), width=.3, height=3, alpha=.2, facecolor='red')p2 = patches.Rectangle((1.5, 27), width=.8, height=5, alpha=.2, facecolor='green')plt.gca().add_patch(p1)plt.gca().add_patch(p2)# Decorateplt.title('Diverging Bars of Car Mileage', fontdict={'size': 20})plt.grid(linestyle='--', alpha=0.5)plt.show() 【14】面积图(Area Chart) 通过对轴和线之间的区域进行着色,面积图不仅强调波峰和波谷,还强调波峰和波谷的持续时间。 高点持续时间越长,线下面积越大。 import numpy as npimport pandas as pd# Prepare Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/economics.csv", parse_dates=['date']).head(100)x = np.arange(df.shape[0])y_returns = (df.psavert.diff().fillna(0)/df.psavert.shift(1)).fillna(0) * 100# Plotplt.figure(figsize=(16, 10), dpi=80)plt.fill_between(x[1:], y_returns[1:], 0, where=y_returns[1:] >= 0, facecolor='green', interpolate=True, alpha=0.7)plt.fill_between(x[1:], y_returns[1:], 0, where=y_returns[1:] <= 0, facecolor='red', interpolate=True, alpha=0.7)# Annotateplt.annotate('Peak \n1975', xy=(94.0, 21.0), xytext=(88.0, 28), bbox=dict(boxstyle='square', fc='firebrick'), arrowprops=dict(facecolor='steelblue', shrink=0.05), fontsize=15, color='white')# Decorationsxtickvals = [str(m)[:3].upper()+"-"+str(y) for y, m in zip(df.date.dt.year, df.date.dt.month_name())]plt.gca().set_xticks(x[::6])plt.gca().set_xticklabels(xtickvals[::6], rotation=90, fontdict={'horizontalalignment': 'center', 'verticalalignment': 'center_baseline'})plt.ylim(-35, 35)plt.xlim(1, 100)plt.title("Month Economics Return %", fontsize=22)plt.ylabel('Monthly returns %')plt.grid(alpha=0.5)plt.show() 【5x00】排序(Ranking) 【15】有序条形图(Ordered Bar Chart) 有序条形图有效地传达了项目的排序顺序。在图表上方添加度量标准的值,用户就可以从图表本身获得精确的信息。 # Prepare Datadf_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")df = df_raw[['cty', 'manufacturer']].groupby('manufacturer').apply(lambda x: x.mean())df.sort_values('cty', inplace=True)df.reset_index(inplace=True)# Draw plotimport matplotlib.patches as patchesfig, ax = plt.subplots(figsize=(16,10), facecolor='white', dpi= 80)ax.vlines(x=df.index, ymin=0, ymax=df.cty, color='firebrick', alpha=0.7, linewidth=20)# Annotate Textfor i, cty in enumerate(df.cty): ax.text(i, cty+0.5, round(cty, 1), horizontalalignment='center')# Title, Label, Ticks and Ylimax.set_title('Bar Chart for Highway Mileage', fontdict={'size':22})ax.set(ylabel='Miles Per Gallon', ylim=(0, 30))plt.xticks(df.index, df.manufacturer.str.upper(), rotation=60, horizontalalignment='right', fontsize=12)# Add patches to color the X axis labelsp1 = patches.Rectangle((.57, -0.005), width=.33, height=.13, alpha=.1, facecolor='green', transform=fig.transFigure)p2 = patches.Rectangle((.124, -0.005), width=.446, height=.13, alpha=.1, facecolor='red', transform=fig.transFigure)fig.add_artist(p1)fig.add_artist(p2)plt.show() 【16】棒棒糖图(Lollipop Chart) 棒棒糖图表以一种视觉上令人愉悦的方式提供与有序条形图类似的目的。 # Prepare Datadf_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")df = df_raw[['cty', 'manufacturer']].groupby('manufacturer').apply(lambda x: x.mean())df.sort_values('cty', inplace=True)df.reset_index(inplace=True)# Draw plotfig, ax = plt.subplots(figsize=(16, 10), dpi=80)ax.vlines(x=df.index, ymin=0, ymax=df.cty, color='firebrick', alpha=0.7, linewidth=2)ax.scatter(x=df.index, y=df.cty, s=75, color='firebrick', alpha=0.7)# Title, Label, Ticks and Ylimax.set_title('Lollipop Chart for Highway Mileage', fontdict={'size': 22})ax.set_ylabel('Miles Per Gallon')ax.set_xticks(df.index)ax.set_xticklabels(df.manufacturer.str.upper(), rotation=60, fontdict={'horizontalalignment': 'right', 'size': 12})ax.set_ylim(0, 30)# Annotatefor row in df.itertuples(): ax.text(row.Index, row.cty+.5, s=round(row.cty, 2), horizontalalignment='center', verticalalignment='bottom', fontsize=14)plt.show() 【17】点图(Dot Plot) 点图可以表示项目的排名顺序。由于它是沿水平轴对齐的,所以可以更容易地看到点之间的距离。 # Prepare Datadf_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")df = df_raw[['cty', 'manufacturer']].groupby('manufacturer').apply(lambda x: x.mean())df.sort_values('cty', inplace=True)df.reset_index(inplace=True)# Draw plotfig, ax = plt.subplots(figsize=(16, 10), dpi=80)ax.hlines(y=df.index, xmin=11, xmax=26, color='gray', alpha=0.7, linewidth=1, linestyles='dashdot')ax.scatter(y=df.index, x=df.cty, s=75, color='firebrick', alpha=0.7)# Title, Label, Ticks and Ylimax.set_title('Dot Plot for Highway Mileage', fontdict={'size': 22})ax.set_xlabel('Miles Per Gallon')ax.set_yticks(df.index)ax.set_yticklabels(df.manufacturer.str.title(), fontdict={'horizontalalignment': 'right'})ax.set_xlim(10, 27)plt.show() 【18】坡度图(Slope Chart) 坡度图最适合比较给定人员/项目的“前”和“后”位置。 import matplotlib.lines as mlines# Import Datadf = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/gdppercap.csv")left_label = [str(c) + ', ' + str(round(y)) for c, y in zip(df.continent, df['1952'])]right_label = [str(c) + ', ' + str(round(y)) for c, y in zip(df.continent, df['1957'])]klass = ['red' if (y1 - y2) < 0 else 'green' for y1, y2 in zip(df['1952'], df['1957'])]# draw line# https://stackoverflow.com/questions/36470343/how-to-draw-a-line-with-matplotlib/36479941def newline(p1, p2, color='black'): ax = plt.gca() l = mlines.Line2D([p1[0], p2[0]], [p1[1], p2[1]], color='red' if p1[1] - p2[1] > 0 else 'green', marker='o', markersize=6) ax.add_line(l) return lfig, ax = plt.subplots(1, 1, figsize=(14, 14), dpi=80)# Vertical Linesax.vlines(x=1, ymin=500, ymax=13000, color='black', alpha=0.7, linewidth=1, linestyles='dotted')ax.vlines(x=3, ymin=500, ymax=13000, color='black', alpha=0.7, linewidth=1, linestyles='dotted')# Pointsax.scatter(y=df['1952'], x=np.repeat(1, df.shape[0]), s=10, color='black', alpha=0.7)ax.scatter(y=df['1957'], x=np.repeat(3, df.shape[0]), s=10, color='black', alpha=0.7)# Line Segmentsand Annotationfor p1, p2, c in zip(df['1952'], df['1957'], df['continent']): newline([1, p1], [3, p2]) ax.text(1 - 0.05, p1, c + ', ' + str(round(p1)), horizontalalignment='right', verticalalignment='center', fontdict={'size': 14}) ax.text(3 + 0.05, p2, c + ', ' + str(round(p2)), horizontalalignment='left', verticalalignment='center', fontdict={'size': 14})# 'Before' and 'After' Annotationsax.text(1 - 0.05, 13000, 'BEFORE', horizontalalignment='right', verticalalignment='center', fontdict={'size': 18, 'weight': 700})ax.text(3 + 0.05, 13000, 'AFTER', horizontalalignment='left', verticalalignment='center', fontdict={'size': 18, 'weight': 700})# Decorationax.set_title("Slopechart: Comparing GDP Per Capita between 1952 vs 1957", fontdict={'size': 22})ax.set(xlim=(0, 4), ylim=(0, 14000), ylabel='Mean GDP Per Capita')ax.set_xticks([1, 3])ax.set_xticklabels(["1952", "1957"])plt.yticks(np.arange(500, 13000, 2000), fontsize=12)# Lighten bordersplt.gca().spines["top"].set_alpha(.0)plt.gca().spines["bottom"].set_alpha(.0)plt.gca().spines["right"].set_alpha(.0)plt.gca().spines["left"].set_alpha(.0)plt.show() 【19】哑铃图(Dumbbell Plot) 哑铃图传达了各种项目的“前”和“后”位置以及项目的等级顺序。如果您希望可视化特定项目/计划对不同对象的影响,那么它非常有用。 import matplotlib.lines as mlines# Import Datadf = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/health.csv")df.sort_values('pct_2014', inplace=True)df.reset_index(inplace=True)# Func to draw line segmentdef newline(p1, p2, color='black'): ax = plt.gca() l = mlines.Line2D([p1[0], p2[0]], [p1[1], p2[1]], color='skyblue') ax.add_line(l) return l# Figure and Axesfig, ax = plt.subplots(1, 1, figsize=(14, 14), facecolor='#f7f7f7', dpi=80)# Vertical Linesax.vlines(x=.05, ymin=0, ymax=26, color='black', alpha=1, linewidth=1, linestyles='dotted')ax.vlines(x=.10, ymin=0, ymax=26, color='black', alpha=1, linewidth=1, linestyles='dotted')ax.vlines(x=.15, ymin=0, ymax=26, color='black', alpha=1, linewidth=1, linestyles='dotted')ax.vlines(x=.20, ymin=0, ymax=26, color='black', alpha=1, linewidth=1, linestyles='dotted')# Pointsax.scatter(y=df['index'], x=df['pct_2013'], s=50, color='#0e668b', alpha=0.7)ax.scatter(y=df['index'], x=df['pct_2014'], s=50, color='#a3c4dc', alpha=0.7)# Line Segmentsfor i, p1, p2 in zip(df['index'], df['pct_2013'], df['pct_2014']): newline([p1, i], [p2, i])# Decorationax.set_facecolor('#f7f7f7')ax.set_title("Dumbell Chart: Pct Change - 2013 vs 2014", fontdict={'size': 22})ax.set(xlim=(0, .25), ylim=(-1, 27), ylabel='Mean GDP Per Capita')ax.set_xticks([.05, .1, .15, .20])ax.set_xticklabels(['5%', '15%', '20%', '25%'])ax.set_xticklabels(['5%', '15%', '20%', '25%'])plt.show() 【6x00】分布(Distribution) 【20】连续变量的直方图(Histogram for Continuous Variable) 连续变量的直方图显示给定变量的频率分布。下面的图表基于分类变量对频率条进行分组,从而更深入地了解连续变量和分类变量。 # Import Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Prepare datax_var = 'displ'groupby_var = 'class'df_agg = df.loc[:, [x_var, groupby_var]].groupby(groupby_var)vals = [df[x_var].values.tolist() for i, df in df_agg]# Drawplt.figure(figsize=(16, 9), dpi=80)colors = [plt.cm.Spectral(i / float(len(vals) - 1)) for i in range(len(vals))]n, bins, patches = plt.hist(vals, 30, stacked=True, density=False, color=colors[:len(vals)])# Decorationplt.legend({group: col for group, col in zip(np.unique(df[groupby_var]).tolist(), colors[:len(vals)])})plt.title(f"Stacked Histogram of ${x_var}$ colored by ${groupby_var}$", fontsize=22)plt.xlabel(x_var)plt.ylabel("Frequency")plt.ylim(0, 25)plt.xticks(ticks=bins[::3], labels=[round(b, 1) for b in bins[::3]])plt.show() 【21】分类变量的直方图(Histogram for Categorical Variable) 分类变量的直方图显示该变量的频率分布。通过给条形图上色,您可以将分布与表示颜色的另一个类型变量相关联。 # Import Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Prepare datax_var = 'manufacturer'groupby_var = 'class'df_agg = df.loc[:, [x_var, groupby_var]].groupby(groupby_var)vals = [df[x_var].values.tolist() for i, df in df_agg]# Drawplt.figure(figsize=(16, 9), dpi=80)colors = [plt.cm.Spectral(i / float(len(vals) - 1)) for i in range(len(vals))]n, bins, patches = plt.hist(vals, df[x_var].unique().__len__(), stacked=True, density=False, color=colors[:len(vals)])# Decorationplt.legend({group: col for group, col in zip(np.unique(df[groupby_var]).tolist(), colors[:len(vals)])})plt.title(f"Stacked Histogram of ${x_var}$ colored by ${groupby_var}$", fontsize=22)plt.xlabel(x_var)plt.ylabel("Frequency")plt.ylim(0, 40)plt.xticks(ticks=bins, labels=np.unique(df[x_var]).tolist(), rotation=90, horizontalalignment='left')plt.show() 【22】密度图(Density Plot) 密度图是连续变量分布可视化的常用工具。通过按“response”变量对它们进行分组,您可以检查 X 和 Y 之间的关系。如果出于代表性目的来描述城市里程分布如何随气缸数而变化,请参见下面的情况。 # Import Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Draw Plotplt.figure(figsize=(16, 10), dpi=80)sns.kdeplot(df.loc[df['cyl'] == 4, "cty"], shade=True, color="g", label="Cyl=4", alpha=.7)sns.kdeplot(df.loc[df['cyl'] == 5, "cty"], shade=True, color="deeppink", label="Cyl=5", alpha=.7)sns.kdeplot(df.loc[df['cyl'] == 6, "cty"], shade=True, color="dodgerblue", label="Cyl=6", alpha=.7)sns.kdeplot(df.loc[df['cyl'] == 8, "cty"], shade=True, color="orange", label="Cyl=8", alpha=.7)# Decorationplt.title('Density Plot of City Mileage by n_Cylinders', fontsize=22)plt.legend()plt.show() 【23】直方图密度曲线(Density Curves with Histogram) 具有直方图的密度曲线将两个图所传达的信息集合在一起,因此您可以将它们都放在一个图形中,而不是放在两个图形中。 # Import Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Draw Plotplt.figure(figsize=(13, 10), dpi=80)sns.distplot(df.loc[df['class'] == 'compact', "cty"], color="dodgerblue", label="Compact", hist_kws={'alpha': .7}, kde_kws={'linewidth': 3})sns.distplot(df.loc[df['class'] == 'suv', "cty"], color="orange", label="SUV", hist_kws={'alpha': .7}, kde_kws={'linewidth': 3})sns.distplot(df.loc[df['class'] == 'minivan', "cty"], color="g", label="minivan", hist_kws={'alpha': .7}, kde_kws={'linewidth': 3})plt.ylim(0, 0.35)# Decorationplt.title('Density Plot of City Mileage by Vehicle Type', fontsize=22)plt.legend()plt.show() 【24】山峰叠峦图 / 欢乐图(Joy Plot) Joy Plot 允许不同组的密度曲线重叠,这是一种很好的可视化方法,可以直观地显示大量分组之间的关系。它看起来赏心悦目,清楚地传达了正确的信息。它可以使用基于 matplotlib 的 joypy 包轻松构建。 【译者 TRHX 注:Joy Plot 看起来就像是山峰叠峦,山峦起伏,层次分明,但取名为 Joy,欢乐的意思,所以不太好翻译,在使用该方法时要先安装 joypy 库】 # !pip install joypy# Import Dataimport joypy# 原文没有 import joypy,译者 TRHX 添加mpg = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Draw Plotplt.figure(figsize=(16, 10), dpi=80)fig, axes = joypy.joyplot(mpg, column=['hwy', 'cty'], by="class", ylim='own', figsize=(14, 10))# Decorationplt.title('Joy Plot of City and Highway Mileage by Class', fontsize=22)plt.show() 【25】分布式点图(Distributed Dot Plot) 分布点图显示按组分割的点的单变量分布。点越暗,数据点在该区域的集中程度就越高。通过对中值进行不同的着色,这些组的真实位置立即变得明显。 import matplotlib.patches as mpatches# Prepare Datadf_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")cyl_colors = {4: 'tab:red', 5: 'tab:green', 6: 'tab:blue', 8: 'tab:orange'}df_raw['cyl_color'] = df_raw.cyl.map(cyl_colors)# Mean and Median city mileage by makedf = df_raw[['cty', 'manufacturer']].groupby('manufacturer').apply(lambda x: x.mean())df.sort_values('cty', ascending=False, inplace=True)df.reset_index(inplace=True)df_median = df_raw[['cty', 'manufacturer']].groupby('manufacturer').apply(lambda x: x.median())# Draw horizontal linesfig, ax = plt.subplots(figsize=(16, 10), dpi=80)ax.hlines(y=df.index, xmin=0, xmax=40, color='gray', alpha=0.5, linewidth=.5, linestyles='dashdot')# Draw the Dotsfor i, make in enumerate(df.manufacturer): df_make = df_raw.loc[df_raw.manufacturer == make, :] # 原文代码 # ax.scatter(y=np.repeat(i, df_make.shape[0]), x='cty', data=df_make, s=75, edgecolors='gray', c='w', alpha=0.5) # 纠正代码 ax.scatter(y=list(np.repeat(i, df_make.shape[0])), x='cty', data=df_make, s=75, edgecolors='gray', c='w', alpha=0.5) ax.scatter(y=i, x='cty', data=df_median.loc[df_median.index == make, :], s=75, c='firebrick')# Annotateax.text(33, 13, "$red \; dots \; are \; the \: median$", fontdict={'size': 12}, color='firebrick')# Decorationsred_patch = plt.plot([], [], marker="o", ms=10, ls="", mec=None, color='firebrick', label="Median")plt.legend(handles=red_patch)ax.set_title('Distribution of City Mileage by Make', fontdict={'size': 22})ax.set_xlabel('Miles Per Gallon (City)', alpha=0.7)ax.set_yticks(df.index)ax.set_yticklabels(df.manufacturer.str.title(), fontdict={'horizontalalignment': 'right'}, alpha=0.7)ax.set_xlim(1, 40)plt.xticks(alpha=0.7)plt.gca().spines["top"].set_visible(False)plt.gca().spines["bottom"].set_visible(False)plt.gca().spines["right"].set_visible(False)plt.gca().spines["left"].set_visible(False)plt.grid(axis='both', alpha=.4, linewidth=.1)plt.show() 【26】箱形图(Box Plot) 箱形图是可视化分布的一种好方法,同时牢记中位数,第 25 个第 75 个四分位数和离群值。 但是,在解释方框的大小时需要小心,这可能会扭曲该组中包含的点数。 因此,手动提供每个框中的观察次数可以帮助克服此缺点。 例如,左侧的前两个框,尽管它们分别具有 5 和 47 个 obs,但是却具有相同大小, 因此,有必要写下该组中的观察数。 # Import Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Draw Plotplt.figure(figsize=(13, 10), dpi=80)sns.boxplot(x='class', y='hwy', data=df, notch=False)# Add N Obs inside boxplot (optional)def add_n_obs(df, group_col, y): medians_dict = {grp[0]: grp[1][y].median() for grp in df.groupby(group_col)} xticklabels = [x.get_text() for x in plt.gca().get_xticklabels()] n_obs = df.groupby(group_col)[y].size().values for (x, xticklabel), n_ob in zip(enumerate(xticklabels), n_obs): plt.text(x, medians_dict[xticklabel] * 1.01, "#obs : " + str(n_ob), horizontalalignment='center', fontdict={'size': 14}, color='white')add_n_obs(df, group_col='class', y='hwy')# Decorationplt.title('Box Plot of Highway Mileage by Vehicle Class', fontsize=22)plt.ylim(10, 40)plt.show() 【27】点 + 箱形图(Dot + Box Plot) 点 + 箱形图传达类似于分组的箱形图信息。此外,这些点还提供了每组中有多少数据点的含义。 # Import Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Draw Plotplt.figure(figsize=(13,10), dpi= 80)sns.boxplot(x='class', y='hwy', data=df, hue='cyl')sns.stripplot(x='class', y='hwy', data=df, color='black', size=3, jitter=1)for i in range(len(df['class'].unique())-1): plt.vlines(i+.5, 10, 45, linestyles='solid', colors='gray', alpha=0.2)# Decorationplt.title('Box Plot of Highway Mileage by Vehicle Class', fontsize=22)plt.legend(title='Cylinders')plt.show() 【28】小提琴图(Violin Plot) 小提琴图是箱形图在视觉上令人愉悦的替代品。 小提琴的形状或面积取决于它所持有的观察次数。 但是,小提琴图可能更难以阅读,并且在专业设置中不常用。 # Import Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Draw Plotplt.figure(figsize=(13, 10), dpi=80)sns.violinplot(x='class', y='hwy', data=df, scale='width', inner='quartile')# Decorationplt.title('Violin Plot of Highway Mileage by Vehicle Class', fontsize=22)plt.show() 【29】人口金字塔图(Population Pyramid) 人口金字塔可用于显示按体积排序的组的分布。或者它也可以用于显示人口的逐级过滤,因为它是用来显示有多少人通过一个营销漏斗(Marketing Funnel)的每个阶段。 # Read datadf = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/email_campaign_funnel.csv")# Draw Plotplt.figure(figsize=(13, 10), dpi=80)group_col = 'Gender'order_of_bars = df.Stage.unique()[::-1]colors = [plt.cm.Spectral(i / float(len(df[group_col].unique()) - 1)) for i in range(len(df[group_col].unique()))]for c, group in zip(colors, df[group_col].unique()): sns.barplot(x='Users', y='Stage', data=df.loc[df[group_col] == group, :], order=order_of_bars, color=c, label=group)# Decorationsplt.xlabel("$Users$")plt.ylabel("Stage of Purchase")plt.yticks(fontsize=12)plt.title("Population Pyramid of the Marketing Funnel", fontsize=22)plt.legend()plt.show() 【30】分类图(Categorical Plots) 由 seaborn 库提供的分类图可用于可视化彼此相关的两个或更多分类变量的计数分布。 # Load Datasettitanic = sns.load_dataset("titanic")# Plotg = sns.catplot("alive", col="deck", col_wrap=4, data=titanic[titanic.deck.notnull()], kind="count", height=3.5, aspect=.8, palette='tab20')# 译者 TRHX 注释掉了这一行代码# fig.suptitle('sf')plt.show() # Load Datasettitanic = sns.load_dataset("titanic")# Plotsns.catplot(x="age", y="embark_town", hue="sex", col="class", data=titanic[titanic.embark_town.notnull()], orient="h", height=5, aspect=1, palette="tab10", kind="violin", dodge=True, cut=0, bw=.2)# 译者 TRHX 添加了这行代码plt.show() 【7x00】组成(Composition) 【31】华夫饼图(Waffle Chart) 华夫饼图可以使用 pywaffle 包创建,用于显示较大群体中的组的组成。 【译者 TRHX 注:在使用该方法时要先安装 pywaffle 库】 # ! pip install pywaffle# Reference: https://stackoverflow.com/questions/41400136/how-to-do-waffle-charts-in-python-square-piechartfrom pywaffle import Waffle# Importdf_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Prepare Datadf = df_raw.groupby('class').size().reset_index(name='counts')n_categories = df.shape[0]colors = [plt.cm.inferno_r(i / float(n_categories)) for i in range(n_categories)]# Draw Plot and Decoratefig = plt.figure( FigureClass=Waffle, plots={ '111': { 'values': df['counts'], 'labels': ["{0} ({1})".format(n[0], n[1]) for n in df[['class', 'counts']].itertuples()], 'legend': {'loc': 'upper left', 'bbox_to_anchor': (1.05, 1), 'fontsize': 12}, 'title': {'label': '# Vehicles by Class', 'loc': 'center', 'fontsize': 18} }, }, rows=7, colors=colors, figsize=(16, 9))# 译者 TRHX 添加了这行代码plt.show() # ! pip install pywafflefrom pywaffle import Waffle# Import# 译者 TRHX 取消注释了这行代码df_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Prepare Data# By Class Datadf_class = df_raw.groupby('class').size().reset_index(name='counts_class')n_categories = df_class.shape[0]colors_class = [plt.cm.Set3(i / float(n_categories)) for i in range(n_categories)]# By Cylinders Datadf_cyl = df_raw.groupby('cyl').size().reset_index(name='counts_cyl')n_categories = df_cyl.shape[0]colors_cyl = [plt.cm.Spectral(i / float(n_categories)) for i in range(n_categories)]# By Make Datadf_make = df_raw.groupby('manufacturer').size().reset_index(name='counts_make')n_categories = df_make.shape[0]colors_make = [plt.cm.tab20b(i / float(n_categories)) for i in range(n_categories)]# Draw Plot and Decoratefig = plt.figure( FigureClass=Waffle, plots={ '311': { 'values': df_class['counts_class'], 'labels': ["{1}".format(n[0], n[1]) for n in df_class[['class', 'counts_class']].itertuples()], 'legend': {'loc': 'upper left', 'bbox_to_anchor': (1.05, 1), 'fontsize': 12, 'title': 'Class'}, 'title': {'label': '# Vehicles by Class', 'loc': 'center', 'fontsize': 18}, 'colors': colors_class }, '312': { 'values': df_cyl['counts_cyl'], 'labels': ["{1}".format(n[0], n[1]) for n in df_cyl[['cyl', 'counts_cyl']].itertuples()], 'legend': {'loc': 'upper left', 'bbox_to_anchor': (1.05, 1), 'fontsize': 12, 'title': 'Cyl'}, 'title': {'label': '# Vehicles by Cyl', 'loc': 'center', 'fontsize': 18}, 'colors': colors_cyl }, '313': { 'values': df_make['counts_make'], 'labels': ["{1}".format(n[0], n[1]) for n in df_make[['manufacturer', 'counts_make']].itertuples()], 'legend': {'loc': 'upper left', 'bbox_to_anchor': (1.05, 1), 'fontsize': 12, 'title': 'Manufacturer'}, 'title': {'label': '# Vehicles by Make', 'loc': 'center', 'fontsize': 18}, 'colors': colors_make } }, rows=9, figsize=(16, 14))# 译者 TRHX 添加了这行代码plt.show() 【32】饼图(Pie Chart) 饼图是显示组成的经典方法。然而,现在一般不宜使用,因为馅饼部分的面积有时会产生误导。因此,如果要使用饼图,强烈建议您显式地记下饼图每个部分的百分比或数字。 # Importdf_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Prepare Datadf = df_raw.groupby('class').size()# Make the plot with pandas'''原代码:df.plot(kind='pie', subplots=True, figsize=(8, 8), dpi=80)译者 TRHX 删除了 dpi= 80'''df.plot(kind='pie', subplots=True, figsize=(8, 8))plt.title("Pie Chart of Vehicle Class - Bad")plt.ylabel("")plt.show() # Importdf_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Prepare Datadf = df_raw.groupby('class').size().reset_index(name='counts')# Draw Plotfig, ax = plt.subplots(figsize=(12, 7), subplot_kw=dict(aspect="equal"), dpi=80)data = df['counts']categories = df['class']explode = [0, 0, 0, 0, 0, 0.1, 0]def func(pct, allvals): absolute = int(pct / 100. * np.sum(allvals)) return "{:.1f}% ({:d} )".format(pct, absolute)wedges, texts, autotexts = ax.pie(data, autopct=lambda pct: func(pct, data), textprops=dict(color="w"), colors=plt.cm.Dark2.colors, startangle=140, explode=explode)# Decorationax.legend(wedges, categories, title="Vehicle Class", loc="center left", bbox_to_anchor=(1, 0, 0.5, 1))plt.setp(autotexts, size=10, weight=700)ax.set_title("Class of Vehicles: Pie Chart")plt.show() 【33】矩阵树形图(Treemap) 矩阵树形图类似于饼图,它可以更好地完成工作而不会误导每个组的贡献。 【译者 TRHX 注:在使用该方法时要先安装 squarify 库】 # pip install squarifyimport squarify# Import Datadf_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Prepare Datadf = df_raw.groupby('class').size().reset_index(name='counts')labels = df.apply(lambda x: str(x[0]) + "\n (" + str(x[1]) + ")", axis=1)sizes = df['counts'].values.tolist()colors = [plt.cm.Spectral(i / float(len(labels))) for i in range(len(labels))]# Draw Plotplt.figure(figsize=(12, 8), dpi=80)squarify.plot(sizes=sizes, label=labels, color=colors, alpha=.8)# Decorateplt.title('Treemap of Vechile Class')plt.axis('off')plt.show() 【34】条形图(Bar Chart) 条形图是一种基于计数或任何给定度量的可视化项的经典方法。在下面的图表中,我为每个项目使用了不同的颜色,但您通常可能希望为所有项目选择一种颜色,除非您按组对它们进行着色。颜色名称存储在下面代码中的 all_colors 中。您可以通过在 plt.plot() 中设置 color 参数来更改条形的颜色。 import random# Import Datadf_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Prepare Datadf = df_raw.groupby('manufacturer').size().reset_index(name='counts')n = df['manufacturer'].unique().__len__()+1all_colors = list(plt.cm.colors.cnames.keys())random.seed(100)c = random.choices(all_colors, k=n)# Plot Barsplt.figure(figsize=(16,10), dpi= 80)plt.bar(df['manufacturer'], df['counts'], color=c, width=.5)for i, val in enumerate(df['counts'].values): plt.text(i, val, float(val), horizontalalignment='center', verticalalignment='bottom', fontdict={'fontweight':500, 'size':12})# Decorationplt.gca().set_xticklabels(df['manufacturer'], rotation=60, horizontalalignment= 'right')plt.title("Number of Vehicles by Manaufacturers", fontsize=22)plt.ylabel('# Vehicles')plt.ylim(0, 45)plt.show() 【8x00】变化(Change) 【35】时间序列图(Time Series Plot) 时间序列图用于可视化给定指标随时间的变化。在这里你可以看到 1949 年到 1969 年间的航空客运量是如何变化的。 # Import Datadf = pd.read_csv('https://github.com/selva86/datasets/raw/master/AirPassengers.csv')# Draw Plotplt.figure(figsize=(16, 10), dpi=80)plt.plot('date', 'traffic', data=df, color='tab:red')# Decorationplt.ylim(50, 750)xtick_location = df.index.tolist()[::12]xtick_labels = [x[-4:] for x in df.date.tolist()[::12]]plt.xticks(ticks=xtick_location, labels=xtick_labels, rotation=0, fontsize=12, horizontalalignment='center', alpha=.7)plt.yticks(fontsize=12, alpha=.7)plt.title("Air Passengers Traffic (1949 - 1969)", fontsize=22)plt.grid(axis='both', alpha=.3)# Remove bordersplt.gca().spines["top"].set_alpha(0.0)plt.gca().spines["bottom"].set_alpha(0.3)plt.gca().spines["right"].set_alpha(0.0)plt.gca().spines["left"].set_alpha(0.3)plt.show() 【36】带波峰和波谷注释的时间序列图(Time Series with Peaks and Troughs Annotated) 下面的时间序列绘制了所有的波峰和波谷,并注释了所选特殊事件的发生。 # Import Datadf = pd.read_csv('https://github.com/selva86/datasets/raw/master/AirPassengers.csv')# Get the Peaks and Troughsdata = df['traffic'].valuesdoublediff = np.diff(np.sign(np.diff(data)))peak_locations = np.where(doublediff == -2)[0] + 1doublediff2 = np.diff(np.sign(np.diff(-1 * data)))trough_locations = np.where(doublediff2 == -2)[0] + 1# Draw Plotplt.figure(figsize=(16, 10), dpi=80)plt.plot('date', 'traffic', data=df, color='tab:blue', label='Air Traffic')plt.scatter(df.date[peak_locations], df.traffic[peak_locations], marker=mpl.markers.CARETUPBASE, color='tab:green', s=100, label='Peaks')plt.scatter(df.date[trough_locations], df.traffic[trough_locations], marker=mpl.markers.CARETDOWNBASE, color='tab:red', s=100, label='Troughs')# Annotatefor t, p in zip(trough_locations[1::5], peak_locations[::3]): plt.text(df.date[p], df.traffic[p] + 15, df.date[p], horizontalalignment='center', color='darkgreen') plt.text(df.date[t], df.traffic[t] - 35, df.date[t], horizontalalignment='center', color='darkred')# Decorationplt.ylim(50, 750)xtick_location = df.index.tolist()[::6]xtick_labels = df.date.tolist()[::6]plt.xticks(ticks=xtick_location, labels=xtick_labels, rotation=90, fontsize=12, alpha=.7)plt.title("Peak and Troughs of Air Passengers Traffic (1949 - 1969)", fontsize=22)plt.yticks(fontsize=12, alpha=.7)# Lighten bordersplt.gca().spines["top"].set_alpha(.0)plt.gca().spines["bottom"].set_alpha(.3)plt.gca().spines["right"].set_alpha(.0)plt.gca().spines["left"].set_alpha(.3)plt.legend(loc='upper left')plt.grid(axis='y', alpha=.3)plt.show() 【37】自相关 (ACF) 和部分自相关 (PACF) 图(Autocorrelation (ACF) and Partial Autocorrelation (PACF) Plot) 自相关图(ACF图)显示了时间序列与其自身滞后的相关性。 每条垂直线(在自相关图上)表示系列与滞后 0 之间的滞后的相关性。图中的蓝色阴影区域是显著性级别。 那些位于蓝线之上的滞后是显著的滞后。 那么如何解释呢? 对于航空乘客来说,我们看到超过 14 个滞后已经越过蓝线,因此意义重大。这意味着,14 年前的航空客运量对今天的交通量产生了影响。 另一方面,部分自相关图(PACF)显示了任何给定滞后(时间序列)相对于当前序列的自相关,但消除了中间滞后的贡献。 from statsmodels.graphics.tsaplots import plot_acf, plot_pacf# Import Datadf = pd.read_csv('https://github.com/selva86/datasets/raw/master/AirPassengers.csv')# Draw Plotfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 6), dpi=80)plot_acf(df.traffic.tolist(), ax=ax1, lags=50)plot_pacf(df.traffic.tolist(), ax=ax2, lags=20)# Decorate# lighten the bordersax1.spines["top"].set_alpha(.3); ax2.spines["top"].set_alpha(.3)ax1.spines["bottom"].set_alpha(.3); ax2.spines["bottom"].set_alpha(.3)ax1.spines["right"].set_alpha(.3); ax2.spines["right"].set_alpha(.3)ax1.spines["left"].set_alpha(.3); ax2.spines["left"].set_alpha(.3)# font size of tick labelsax1.tick_params(axis='both', labelsize=12)ax2.tick_params(axis='both', labelsize=12)plt.show() 【38】交叉相关图(Cross Correlation plot) 交叉相关图显示了两个时间序列相互之间的滞后。 import statsmodels.tsa.stattools as stattools# Import Datadf = pd.read_csv('https://github.com/selva86/datasets/raw/master/mortality.csv')x = df['mdeaths']y = df['fdeaths']# Compute Cross Correlationsccs = stattools.ccf(x, y)[:100]nlags = len(ccs)# Compute the Significance level# ref: https://stats.stackexchange.com/questions/3115/cross-correlation-significance-in-r/3128#3128conf_level = 2 / np.sqrt(nlags)# Draw Plotplt.figure(figsize=(12, 7), dpi=80)plt.hlines(0, xmin=0, xmax=100, color='gray') # 0 axisplt.hlines(conf_level, xmin=0, xmax=100, color='gray')plt.hlines(-conf_level, xmin=0, xmax=100, color='gray')plt.bar(x=np.arange(len(ccs)), height=ccs, width=.3)# Decorationplt.title('$Cross\; Correlation\; Plot:\; mdeaths\; vs\; fdeaths$', fontsize=22)plt.xlim(0, len(ccs))plt.show() 【39】时间序列分解图(Time Series Decomposition Plot) 时间序列分解图将时间序列分解为趋势、季节和残差分量。 from statsmodels.tsa.seasonal import seasonal_decomposefrom dateutil.parser import parse# Import Datadf = pd.read_csv('https://github.com/selva86/datasets/raw/master/AirPassengers.csv')dates = pd.DatetimeIndex([parse(d).strftime('%Y-%m-01') for d in df['date']])df.set_index(dates, inplace=True)# Decomposeresult = seasonal_decompose(df['traffic'], model='multiplicative')# Plotplt.rcParams.update({'figure.figsize': (10, 10)})result.plot().suptitle('Time Series Decomposition of Air Passengers')plt.show() 【40】多重时间序列(Multiple Time Series) 您可以在同一图表上绘制多个测量相同值的时间序列,如下所示。 # Import Datadf = pd.read_csv('https://github.com/selva86/datasets/raw/master/mortality.csv')# Define the upper limit, lower limit, interval of Y axis and colorsy_LL = 100y_UL = int(df.iloc[:, 1:].max().max() * 1.1)y_interval = 400mycolors = ['tab:red', 'tab:blue', 'tab:green', 'tab:orange']# Draw Plot and Annotatefig, ax = plt.subplots(1, 1, figsize=(16, 9), dpi=80)columns = df.columns[1:]for i, column in enumerate(columns): plt.plot(df.date.values, df[column].values, lw=1.5, color=mycolors[i]) plt.text(df.shape[0] + 1, df[column].values[-1], column, fontsize=14, color=mycolors[i])# Draw Tick linesfor y in range(y_LL, y_UL, y_interval): plt.hlines(y, xmin=0, xmax=71, colors='black', alpha=0.3, linestyles="--", lw=0.5)# Decorationsplt.tick_params(axis="both", which="both", bottom=False, top=False, labelbottom=True, left=False, right=False, labelleft=True)# Lighten bordersplt.gca().spines["top"].set_alpha(.3)plt.gca().spines["bottom"].set_alpha(.3)plt.gca().spines["right"].set_alpha(.3)plt.gca().spines["left"].set_alpha(.3)plt.title('Number of Deaths from Lung Diseases in the UK (1974-1979)', fontsize=22)plt.yticks(range(y_LL, y_UL, y_interval), [str(y) for y in range(y_LL, y_UL, y_interval)], fontsize=12)plt.xticks(range(0, df.shape[0], 12), df.date.values[::12], horizontalalignment='left', fontsize=12)plt.ylim(y_LL, y_UL)plt.xlim(-2, 80)plt.show() 【41】使用次要的 Y 轴来绘制不同范围的图形(Plotting with different scales using secondary Y axis) 如果要显示在同一时间点测量两个不同数量的两个时间序列,则可以在右侧的次要 Y 轴上再绘制第二个系列。 # Import Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/economics.csv")x = df['date']y1 = df['psavert']y2 = df['unemploy']# Plot Line1 (Left Y Axis)fig, ax1 = plt.subplots(1, 1, figsize=(16, 9), dpi=80)ax1.plot(x, y1, color='tab:red')# Plot Line2 (Right Y Axis)ax2 = ax1.twinx() # instantiate a second axes that shares the same x-axisax2.plot(x, y2, color='tab:blue')# Decorations# ax1 (left Y axis)ax1.set_xlabel('Year', fontsize=20)ax1.tick_params(axis='x', rotation=0, labelsize=12)ax1.set_ylabel('Personal Savings Rate', color='tab:red', fontsize=20)ax1.tick_params(axis='y', rotation=0, labelcolor='tab:red')ax1.grid(alpha=.4)# ax2 (right Y axis)ax2.set_ylabel("# Unemployed (1000's)", color='tab:blue', fontsize=20)ax2.tick_params(axis='y', labelcolor='tab:blue')ax2.set_xticks(np.arange(0, len(x), 60))ax2.set_xticklabels(x[::60], rotation=90, fontdict={'fontsize': 10})ax2.set_title("Personal Savings Rate vs Unemployed: Plotting in Secondary Y Axis", fontsize=22)fig.tight_layout()plt.show() 【42】带误差带的时间序列(Time Series with Error Bands) 如果您有一个时间序列数据集,其中每个时间点(日期/时间戳)有多个观测值,则可以构造具有误差带的时间序列。下面您可以看到一些基于一天中不同时间的订单的示例。还有一个关于45天内到达的订单数量的例子。 在这种方法中,订单数量的平均值用白线表示。并计算95%的置信区间,并围绕平均值绘制。 from scipy.stats import sem# Import Datadf = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/user_orders_hourofday.csv")df_mean = df.groupby('order_hour_of_day').quantity.mean()df_se = df.groupby('order_hour_of_day').quantity.apply(sem).mul(1.96)# Plotplt.figure(figsize=(16, 10), dpi=80)plt.ylabel("# Orders", fontsize=16)x = df_mean.indexplt.plot(x, df_mean, color="white", lw=2)plt.fill_between(x, df_mean - df_se, df_mean + df_se, color="#3F5D7D")# Decorations# Lighten bordersplt.gca().spines["top"].set_alpha(0)plt.gca().spines["bottom"].set_alpha(1)plt.gca().spines["right"].set_alpha(0)plt.gca().spines["left"].set_alpha(1)plt.xticks(x[::2], [str(d) for d in x[::2]], fontsize=12)plt.title("User Orders by Hour of Day (95% confidence)", fontsize=22)plt.xlabel("Hour of Day")s, e = plt.gca().get_xlim()plt.xlim(s, e)# Draw Horizontal Tick linesfor y in range(8, 20, 2): plt.hlines(y, xmin=s, xmax=e, colors='black', alpha=0.5, linestyles="--", lw=0.5)plt.show() "Data Source: https://www.kaggle.com/olistbr/brazilian-ecommerce#olist_orders_dataset.csv"from dateutil.parser import parsefrom scipy.stats import sem# Import Datadf_raw = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/orders_45d.csv', parse_dates=['purchase_time', 'purchase_date'])# Prepare Data: Daily Mean and SE Bandsdf_mean = df_raw.groupby('purchase_date').quantity.mean()df_se = df_raw.groupby('purchase_date').quantity.apply(sem).mul(1.96)# Plotplt.figure(figsize=(16, 10), dpi=80)plt.ylabel("# Daily Orders", fontsize=16)x = [d.date().strftime('%Y-%m-%d') for d in df_mean.index]plt.plot(x, df_mean, color="white", lw=2)plt.fill_between(x, df_mean - df_se, df_mean + df_se, color="#3F5D7D")# Decorations# Lighten bordersplt.gca().spines["top"].set_alpha(0)plt.gca().spines["bottom"].set_alpha(1)plt.gca().spines["right"].set_alpha(0)plt.gca().spines["left"].set_alpha(1)plt.xticks(x[::6], [str(d) for d in x[::6]], fontsize=12)plt.title("Daily Order Quantity of Brazilian Retail with Error Bands (95% confidence)", fontsize=20)# Axis limitss, e = plt.gca().get_xlim()plt.xlim(s, e - 2)plt.ylim(4, 10)# Draw Horizontal Tick linesfor y in range(5, 10, 1): plt.hlines(y, xmin=s, xmax=e, colors='black', alpha=0.5, linestyles="--", lw=0.5)plt.show() 【43】堆积面积图(Stacked Area Chart) 堆积面积图提供了多个时间序列的贡献程度的可视化表示,以便相互比较。 # Import Datadf = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/nightvisitors.csv')# Decide Colorsmycolors = ['tab:red', 'tab:blue', 'tab:green', 'tab:orange', 'tab:brown', 'tab:grey', 'tab:pink', 'tab:olive']# Draw Plot and Annotatefig, ax = plt.subplots(1, 1, figsize=(16, 9), dpi=80)columns = df.columns[1:]labs = columns.values.tolist()# Prepare datax = df['yearmon'].values.tolist()y0 = df[columns[0]].values.tolist()y1 = df[columns[1]].values.tolist()y2 = df[columns[2]].values.tolist()y3 = df[columns[3]].values.tolist()y4 = df[columns[4]].values.tolist()y5 = df[columns[5]].values.tolist()y6 = df[columns[6]].values.tolist()y7 = df[columns[7]].values.tolist()y = np.vstack([y0, y2, y4, y6, y7, y5, y1, y3])# Plot for each columnlabs = columns.values.tolist()ax = plt.gca()ax.stackplot(x, y, labels=labs, colors=mycolors, alpha=0.8)# Decorationsax.set_title('Night Visitors in Australian Regions', fontsize=18)ax.set(ylim=[0, 100000])ax.legend(fontsize=10, ncol=4)plt.xticks(x[::5], fontsize=10, horizontalalignment='center')plt.yticks(np.arange(10000, 100000, 20000), fontsize=10)plt.xlim(x[0], x[-1])# Lighten bordersplt.gca().spines["top"].set_alpha(0)plt.gca().spines["bottom"].set_alpha(.3)plt.gca().spines["right"].set_alpha(0)plt.gca().spines["left"].set_alpha(.3)plt.show() 【44】未堆积面积图(Area Chart UnStacked) 未堆积的面积图用于可视化两个或多个序列彼此之间的进度(起伏)。在下面的图表中,你可以清楚地看到,随着失业持续时间的中位数增加,个人储蓄率是如何下降的。未堆积面积图很好地展示了这一现象。 # Import Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/economics.csv")# Prepare Datax = df['date'].values.tolist()y1 = df['psavert'].values.tolist()y2 = df['uempmed'].values.tolist()mycolors = ['tab:red', 'tab:blue', 'tab:green', 'tab:orange', 'tab:brown', 'tab:grey', 'tab:pink', 'tab:olive']columns = ['psavert', 'uempmed']# Draw Plotfig, ax = plt.subplots(1, 1, figsize=(16, 9), dpi=80)ax.fill_between(x, y1=y1, y2=0, label=columns[1], alpha=0.5, color=mycolors[1], linewidth=2)ax.fill_between(x, y1=y2, y2=0, label=columns[0], alpha=0.5, color=mycolors[0], linewidth=2)# Decorationsax.set_title('Personal Savings Rate vs Median Duration of Unemployment', fontsize=18)ax.set(ylim=[0, 30])ax.legend(loc='best', fontsize=12)plt.xticks(x[::50], fontsize=10, horizontalalignment='center')plt.yticks(np.arange(2.5, 30.0, 2.5), fontsize=10)plt.xlim(-10, x[-1])# Draw Tick linesfor y in np.arange(2.5, 30.0, 2.5): plt.hlines(y, xmin=0, xmax=len(x), colors='black', alpha=0.3, linestyles="--", lw=0.5)# Lighten bordersplt.gca().spines["top"].set_alpha(0)plt.gca().spines["bottom"].set_alpha(.3)plt.gca().spines["right"].set_alpha(0)plt.gca().spines["left"].set_alpha(.3)plt.show() 【45】日历热力图(Calendar Heat Map) 与时间序列相比,日历地图是另一种基于时间的数据可视化的不太受欢迎的方法。虽然在视觉上很吸引人,但数值并不十分明显。然而,它能很好地描绘极端值和假日效果。 【译者 TRHX 注:在使用该方法时要先安装 calmap 库】 import matplotlib as mplimport calmap# Import Datadf = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/yahoo.csv", parse_dates=['date'])df.set_index('date', inplace=True)# Plotplt.figure(figsize=(16, 10), dpi=80)calmap.calendarplot(df['2014']['VIX.Close'], fig_kws={'figsize': (16, 10)}, yearlabel_kws={'color': 'black', 'fontsize': 14}, subplot_kws={'title': 'Yahoo Stock Prices'})plt.show() 【46】季节图(Seasonal Plot) 季节图可用于比较上一季度同一天(年/月/周等)时间序列的表现。 from dateutil.parser import parse# Import Datadf = pd.read_csv('https://github.com/selva86/datasets/raw/master/AirPassengers.csv')# Prepare datadf['year'] = [parse(d).year for d in df.date]df['month'] = [parse(d).strftime('%b') for d in df.date]years = df['year'].unique()# 译者 TRHX 添加了该行代码df.rename(columns={'value': 'traffic'}, inplace=True)# Draw Plotmycolors = ['tab:red', 'tab:blue', 'tab:green', 'tab:orange', 'tab:brown', 'tab:grey', 'tab:pink', 'tab:olive', 'deeppink', 'steelblue', 'firebrick', 'mediumseagreen']plt.figure(figsize=(16, 10), dpi=80)for i, y in enumerate(years): plt.plot('month', 'traffic', data=df.loc[df.year == y, :], color=mycolors[i], label=y) plt.text(df.loc[df.year == y, :].shape[0] - .9, df.loc[df.year == y, 'traffic'][-1:].values[0], y, fontsize=12, color=mycolors[i])# Decorationplt.ylim(50, 750)plt.xlim(-0.3, 11)plt.ylabel('$Air Traffic$')plt.yticks(fontsize=12, alpha=.7)plt.title("Monthly Seasonal Plot: Air Passengers Traffic (1949 - 1969)", fontsize=22)plt.grid(axis='y', alpha=.3)# Remove bordersplt.gca().spines["top"].set_alpha(0.0)plt.gca().spines["bottom"].set_alpha(0.5)plt.gca().spines["right"].set_alpha(0.0)plt.gca().spines["left"].set_alpha(0.5)# plt.legend(loc='upper right', ncol=2, fontsize=12)plt.show() 【9x00】分组( Groups) 【47】树状图(Dendrogram) 树状图根据给定的距离度量将相似的点组合在一起,并根据点的相似性将它们组织成树状链接。 import scipy.cluster.hierarchy as shc# Import Datadf = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/USArrests.csv')# Plotplt.figure(figsize=(16, 10), dpi=80)plt.title("USArrests Dendograms", fontsize=22)dend = shc.dendrogram(shc.linkage(df[['Murder', 'Assault', 'UrbanPop', 'Rape']], method='ward'), labels=df.State.values, color_threshold=100)plt.xticks(fontsize=12)plt.show() 【48】聚类图(Cluster Plot) 聚类图可以用来划分属于同一个聚类的点。下面是一个基于 USArrests 数据集将美国各州分成 5 组的代表性示例。这个聚类图使用 ‘murder’ 和 ‘assault’ 作为 X 轴和 Y 轴。或者,您可以将第一个主元件用作 X 轴和 Y 轴。 【译者 TRHX 注:在使用该方法时要先安装 sklearn 库】 from sklearn.cluster import AgglomerativeClusteringfrom scipy.spatial import ConvexHull# Import Datadf = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/USArrests.csv')# Agglomerative Clusteringcluster = AgglomerativeClustering(n_clusters=5, affinity='euclidean', linkage='ward')cluster.fit_predict(df[['Murder', 'Assault', 'UrbanPop', 'Rape']])# Plotplt.figure(figsize=(14, 10), dpi=80)plt.scatter(df.iloc[:, 0], df.iloc[:, 1], c=cluster.labels_, cmap='tab10')# Encircledef encircle(x, y, ax=None, **kw): if not ax: ax = plt.gca() p = np.c_[x, y] hull = ConvexHull(p) poly = plt.Polygon(p[hull.vertices,:], **kw) ax.add_patch(poly)# Draw polygon surrounding verticesencircle(df.loc[cluster.labels_ == 0, 'Murder'], df.loc[cluster.labels_ == 0, 'Assault'], ec="k", fc="gold", alpha=0.2, linewidth=0)encircle(df.loc[cluster.labels_ == 1, 'Murder'], df.loc[cluster.labels_ == 1, 'Assault'], ec="k", fc="tab:blue", alpha=0.2, linewidth=0)encircle(df.loc[cluster.labels_ == 2, 'Murder'], df.loc[cluster.labels_ == 2, 'Assault'], ec="k", fc="tab:red", alpha=0.2, linewidth=0)encircle(df.loc[cluster.labels_ == 3, 'Murder'], df.loc[cluster.labels_ == 3, 'Assault'], ec="k", fc="tab:green", alpha=0.2, linewidth=0)encircle(df.loc[cluster.labels_ == 4, 'Murder'], df.loc[cluster.labels_ == 4, 'Assault'], ec="k", fc="tab:orange", alpha=0.2, linewidth=0)# Decorationsplt.xlabel('Murder'); plt.xticks(fontsize=12)plt.ylabel('Assault'); plt.yticks(fontsize=12)plt.title('Agglomerative Clustering of USArrests (5 Groups)', fontsize=22)plt.show() 【49】安德鲁斯曲线(Andrews Curve) 安德鲁斯曲线有助于可视化是否存在基于给定分组的数值特征的固有分组。如果特征(数据集中的列)不能帮助区分组(cyl),则行将不会像下图所示被很好地分隔开。 from pandas.plotting import andrews_curves# Importdf = pd.read_csv("https://github.com/selva86/datasets/raw/master/mtcars.csv")df.drop(['cars', 'carname'], axis=1, inplace=True)# Plotplt.figure(figsize=(12, 9), dpi=80)andrews_curves(df, 'cyl', colormap='Set1')# Lighten bordersplt.gca().spines["top"].set_alpha(0)plt.gca().spines["bottom"].set_alpha(.3)plt.gca().spines["right"].set_alpha(0)plt.gca().spines["left"].set_alpha(.3)plt.title('Andrews Curves of mtcars', fontsize=22)plt.xlim(-3, 3)plt.grid(alpha=0.3)plt.xticks(fontsize=12)plt.yticks(fontsize=12)plt.show() 【50】平行坐标图(Parallel Coordinates) 平行坐标有助于可视化功能是否有助于有效地隔离组。如果一个分离受到影响,则该特征可能在预测该组时非常有用。 from pandas.plotting import parallel_coordinates# Import Datadf_final = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/diamonds_filter.csv")# Plotplt.figure(figsize=(12, 9), dpi=80)parallel_coordinates(df_final, 'cut', colormap='Dark2')# Lighten bordersplt.gca().spines["top"].set_alpha(0)plt.gca().spines["bottom"].set_alpha(.3)plt.gca().spines["right"].set_alpha(0)plt.gca().spines["left"].set_alpha(.3)plt.title('Parallel Coordinated of Diamonds', fontsize=22)plt.grid(alpha=0.3)plt.xticks(fontsize=12)plt.yticks(fontsize=12)plt.show() 这里是一段物理防爬虫文本,请读者忽略。本译文首发于 CSDN,作者 Selva Prabhakaran,译者 TRHX。本文链接:https://itrhx.blog.csdn.net/article/details/106558131原文链接:https://www.machinelearningplus.com/plots/top-50-matplotlib-visualizations-the-master-plots-python/
文章目录 【01x00】了解 mplot3d Toolkit 【01x01】Axes3D 对象创建方法一:Axes3D(fig) 【01x02】Axes3D 对象创建方法二:add_subplot 【01x03】Axes3D 对象创建方法三:gca 【02x00】cmap 与 colorbar 【03x00】3D 线性图:Axes3D.plot 【04x00】3D 散点图:Axes3D.scatter 【05x00】3D 线框图:Axes3D.plot_wireframe 【06x00】3D 曲面图:Axes3D.plot_surface 【07x00】3D 柱状图:Axes3D.bar 【08x00】3D 箭头图:Axes3D.quiver 【09x00】3D 等高线图:Axes3D.contour 【10x00】3D 等高线填充图:Axes3D.contourf 【11x00】3D 三角曲面图:Axes3D.plot_trisurf 【12x00】将 2D 图像聚合到 3D 图像中:Axes3D.add_collection3d 【13x00】3D 图添加文本描述:Axes3D.text Matplotlib 系列文章: Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件 Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性 Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性 Python 数据分析三剑客之 Matplotlib(四):线性图的绘制 Python 数据分析三剑客之 Matplotlib(五):散点图的绘制 Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制 Python 数据分析三剑客之 Matplotlib(七):饼状图的绘制 Python 数据分析三剑客之 Matplotlib(八):等高线 / 等值线图的绘制 Python 数据分析三剑客之 Matplotlib(九):极区图 / 极坐标图 / 雷达图的绘制 Python 数据分析三剑客之 Matplotlib(十):3D 图的绘制 Python 数据分析三剑客之 Matplotlib(十一):最热门最常用的 50 个图表【译文】 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106558131未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【01x00】了解 mplot3d Toolkit mplot3d Toolkit 即 mplot3d 工具包,在 matplotlib 中使用 mplot3d 工具包可以绘制 3D 图。 mplot3d 官方文档:https://matplotlib.org/tutorials/toolkits/mplot3d.html 在 matplotlib 中,figure 为画布,axes 为绘图区,fig.add_subplot()、plt.subplot() 方法均可以创建子图,在绘制 3D 图时,某些 2D 图的参数也适用于 3D 图,在本文的示例中,可能会用到的一些没有具体解释的函数或者参数,其用法均可在前面的系列文章中找到: 《Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件》 《Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性》 《Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性》 绘制 3D 图的步骤:创建 Axes3D 对象,然后调用 Axes3D 的不同方法来绘制不同类型的 3D 图。以下介绍三种 Axes3D 对象创建的方法。 【01x01】Axes3D 对象创建方法一:Axes3D(fig) 在 Matplotlib 1.0.0 版本中,绘制 3D 图需要先导入 Axes3D 包,获取 figure 画布对象 fig 后,通过 Axes3D(fig) 方法来创建 Axes3D 对象,具体方法如下: import numpy as npimport matplotlib.pyplot as pltfrom mpl_toolkits.mplot3d import Axes3D# 获取 figure 画布并创建 Axes3D 对象fig = plt.figure()ax = Axes3D(fig)# 数据坐标z = np.linspace(0, 15, 1000)x = np.sin(z)y = np.cos(z)# 绘制线性图ax.plot(x, y, z)plt.show() 【01x02】Axes3D 对象创建方法二:add_subplot 在 Matplotlib 3.2.0 版本中,绘制 3D 图可以通过创建子图,然后指定 projection 参数 为 3d 即可,返回的 ax 为 Axes3D 对象,以下两种方法均可: import numpy as npimport matplotlib.pyplot as plt# 获取 figure 画布并通过子图创建 Axes3D 对象fig = plt.figure()ax = fig.add_subplot(111, projection='3d')# 数据坐标z = np.linspace(0, 15, 1000)x = np.sin(z)y = np.cos(z)# 绘制线性图ax.plot(x, y, z)plt.show() import numpy as npimport matplotlib.pyplot as plt# 通过子图创建 Axes3D 对象ax = plt.subplot(111, projection='3d')# 数据坐标z = np.linspace(0, 15, 1000)x = np.sin(z)y = np.cos(z)# 绘制线性图ax.plot(x, y, z)plt.show() 【01x03】Axes3D 对象创建方法三:gca 除了以上两种方法以外,还可以先获取画布对象 fig,再通过 fig.gca() 方法获取当前绘图区(gca = Get Current Axes),然后指定 projection 参数 为 3d 即可,返回的 ax 为 Axes3D 对象。 import numpy as npimport matplotlib.pyplot as plt# 依次获取画布和绘图区并创建 Axes3D 对象fig = plt.figure()ax = fig.gca(projection='3d')# 数据坐标z = np.linspace(0, 15, 1000)x = np.sin(z)y = np.cos(z)# 绘制线性图ax.plot(x, y, z)plt.show() 以上三种方法运行结果均为下图: 【02x00】cmap 与 colorbar 默认情况下,散点图、线性图、曲面图等将以纯色着色,但可以通过提供 cmap 参数支持颜色映射。cmap 参数用于设置一些特殊的颜色组合,如渐变色等,参数取值通常为 Colormap 中的值,具体取值可参见下图: 官方文档:https://matplotlib.org/tutorials/colors/colormaps.html 如果使用了 cmap 参数,则可以使用 pyplot.colorbar() 函数来绘制一个色条,即颜色对照条。 基本语法:matplotlib.pyplot.colorbar([mappable=None, cax=None, ax=None, **kw]) 部分参数解释如下表,其他参数,如长度,宽度等请参考官方文档。 参数描述 mappable要设置色条的图像对象,该参数对于 Figure.colorbar 方法是必需的,但对于 pyplot.colorbar 函数是可选的 cax可选项,要绘制色条的轴 ax可选项,设置色条的显示位置,通常在一个画布上有多个子图时使用 **kw可选项,其他关键字参数,参考官方文档 【03x00】3D 线性图:Axes3D.plot 基本方法:Axes3D.plot(xs, ys[, zs, zdir='z', *args, **kwargs]) 参数描述 xs一维数组,点的 x 轴坐标 ys一维数组,点的 y 轴坐标 zs一维数组,可选项,点的 z 轴坐标 zdir可选项,在 3D 轴上绘制 2D 数据时,数据必须以 xs,ys 的形式传递, 若此时将 zdir 设置为 ‘y’,数据将会被绘制到 x-z 轴平面上,默认为 ‘z’ **kwargs其他关键字参数,可选项,可参见 matplotlib.axes.Axes.plot import numpy as npimport matplotlib.pyplot as plt# 设置中文显示plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']# 依次获取画布和绘图区并创建 Axes3D 对象fig = plt.figure()ax = fig.gca(projection='3d')# 第一条3D线性图数据theta = np.linspace(-4 * np.pi, 4 * np.pi, 100)z1 = np.linspace(-2, 2, 100)r = z1**2 + 1x1 = r * np.sin(theta)y1 = r * np.cos(theta)# 第二条3D线性图数据z2 = np.linspace(-3, 3, 100)x2 = np.sin(z2)y2 = np.cos(z2)# 绘制3D线性图ax.plot(x1, y1, z1, color='b', label='3D 线性图一')ax.plot(x2, y2, z2, color='r', label='3D 线性图二')# 设置标题、轴标签、图例,也可以直接使用 plt.title、plt.xlabel、plt.legend...ax.set_title('绘制 3D 线性图示例', pad=15, fontsize='12')ax.set_xlabel('x 轴', color='r', fontsize='12')ax.set_ylabel('y 轴', color='g', fontsize='12')ax.set_zlabel('z 轴', color='b', fontsize='12')ax.legend()plt.show() 【04x00】3D 散点图:Axes3D.scatter 基本方法:Axes3D.scatter(xs, ys[, zs=0, zdir='z', s=20, c=None, depthshade=True, *args, **kwargs]) 参数描述 xs一维数组,点的 x 轴坐标 ys一维数组,点的 y 轴坐标 zs一维数组,可选项,点的 z 轴坐标 zdir可选项,在 3D 轴上绘制 2D 数据时,数据必须以 xs,ys 的形式传递, 若此时将 zdir 设置为 ‘y’,数据将会被绘制到 x-z 轴平面上,默认为 ‘z’ s标量或数组类型,可选项,标记的大小,默认 20 c标记的颜色,可选项,可以是单个颜色或者一个颜色列表 支持英文颜色名称及其简写、十六进制颜色码等,更多颜色示例参见官网 Color Demo depthshadebool 值,可选项,默认 True,是否为散点标记着色以提供深度外观 **kwargs其他关键字参数,可选项,可参见 scatter import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']# 依次获取画布和绘图区并创建 Axes3D 对象fig = plt.figure()ax = fig.gca(projection='3d')n = 100def randrange(n, vmin, vmax): return (vmax - vmin)*np.random.rand(n) + vmin'''定义绘制 n 个随机点,设置每一组数据点的样式和范围x轴数据位于[23,32]区间,y轴数据位于[0,100]区间,z轴数据位于[zlow,zhigh]区间'''for m, zlow, zhigh in [('o', -50, -25), ('^', -30, -5)]: xs = randrange(n, 23, 32) ys = randrange(n, 0, 100) zs = randrange(n, zlow, zhigh) ax.scatter(xs, ys, zs, marker=m)# 设置标题、轴标签、图例,也可以直接使用 plt.title、plt.xlabel...ax.set_title('绘制 3D 散点图示例', pad=15, fontsize='12')ax.set_xlabel('x 轴', color='b')ax.set_ylabel('y 轴', color='b')ax.set_zlabel('z 轴', color='b')plt.show() 【05x00】3D 线框图:Axes3D.plot_wireframe 基本方法:Axes3D.plot_wireframe(X, Y, Z[, *args, **kwargs]) 参数描述 X二维数组,x 轴数据 Y二维数组,y 轴数据 Z二维数组,z 轴数据 **kwargs其他关键字参数,可选项,如线条样式颜色等,可参见 Line3DCollection import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']# 获取 figure 画布并通过子图创建 Axes3D 对象fig = plt.figure()ax = fig.add_subplot(111, projection='3d')# 定义Z轴坐标的生成方法def f(m, n): return np.sin(np.sqrt(m ** 2 + n ** 2))# 设置3D线框图数据x = np.linspace(-6, 6, 30)y = np.linspace(-6, 6, 30)# 生成网格点坐标矩阵,该方法在系列文章八中有具体介绍X, Y = np.meshgrid(x, y)Z = f(X, Y)# 绘制3D线框图ax.plot_wireframe(X, Y, Z, color='c')# 设置标题、轴标签、图例,也可以直接使用 plt.title、plt.xlabel...ax.set_title('绘制 3D 线框图示例', pad=15, fontsize='12')ax.set_xlabel('x 轴')ax.set_ylabel('y 轴')ax.set_zlabel('z 轴')plt.show() 【06x00】3D 曲面图:Axes3D.plot_surface 基本方法:Axes3D.plot_surface(X, Y, Z[, *args, vmin=None, vmax=None, **kwargs]) 参数描述 X二维数组,x 轴数据 Y二维数组,y 轴数据 Z二维数组,z 轴数据 vmin / vmax规定数据界限 **kwargs其他关键字参数,可选项,如线条样式颜色等,可参见 Line3DCollection import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']# 获取 figure 画布并通过子图创建 Axes3D 对象fig = plt.figure()ax = fig.add_subplot(111, projection='3d')# 设置3D曲面图数据X = np.arange(-5, 5, 0.25)Y = np.arange(-5, 5, 0.25)# 生成网格点坐标矩阵,该方法在系列文章八中有具体介绍X, Y = np.meshgrid(X, Y)R = np.sqrt(X**2 + Y**2)Z = np.sin(R)# 绘制3D曲面图并添加色条(长度0.8)surface = ax.plot_surface(X, Y, Z, cmap='rainbow', antialiased=False)fig.colorbar(surface, shrink=0.8)# 设置标题、轴标签、图例,也可以直接使用 plt.title、plt.xlabel...ax.set_title('绘制 3D 曲面图示例', pad=15, fontsize='12')ax.set_xlabel('x 轴')ax.set_ylabel('y 轴')ax.set_zlabel('z 轴')# 调整观察角度和方位角,俯仰角25度,方位角40度ax.view_init(25, 40)# 设置Z轴刻度界限ax.set_zlim(-2, 2)plt.show() 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106558131未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【07x00】3D 柱状图:Axes3D.bar 基本方法:Axes3D.bar(left, height, zs=0, zdir='z', *args, **kwargs) 参数描述 left一维数组,柱状图最左侧位置的 x 坐标 height一维数组,柱状图的高度(y 坐标) zs第 i 个多边形将出现在平面 y=zs[i] 上 zdir可选项,在 3D 轴上绘制 2D 数据时,数据必须以 xs,ys 的形式传递, 若此时将 zdir 设置为 ‘y’,数据将会被绘制到 x-z 轴平面上,默认为 ‘z’ **kwargs其他关键字参数,参见 matplotlib.axes.Axes.bar import matplotlib.pyplot as pltimport numpy as npplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']# 获取 figure 画布并通过子图创建 Axes3D 对象fig = plt.figure()ax = fig.add_subplot(111, projection='3d')colors = ['r', 'g', 'b', 'y']yticks = [3, 2, 1, 0]# 设置3D柱状图数据并绘制图像for c, k in zip(colors, yticks): xs = np.arange(20) ys = np.random.rand(20) cs = [c] * len(xs) ax.bar(xs, ys, zs=k, zdir='y', color=cs, alpha=0.8)# 设置图像标题、坐标标签以及范围ax.set_title('绘制 3D 柱状图示例', pad=15, fontsize='12')ax.set_xlabel('X 轴')ax.set_ylabel('Y 轴')ax.set_zlabel('Z 轴')ax.set_yticks(yticks)plt.show() 【08x00】3D 箭头图:Axes3D.quiver 基本方法:Axes3D.quiver(X, Y, Z, U, V, W, length=1, arrow_length_ratio=0.3, pivot='tail', normalize=False, **kwargs) 参数描述 X, Y, Z数组形式,箭头位置的 x、y 和 z 轴坐标(默认为箭头尾部) U, V, W数组形式,箭头向量的 x、y 和 z 轴分量 lengthfloat 类型,每个箭筒的长度,默认为 1.0 arrow_length_ratiofloat 类型,箭头相对于箭身的比率,默认为 0.3 pivot箭头在网格点上的位置;箭头围绕该点旋转,因此命名为 pivot,默认为 ‘tail’ 可选项:'tail':尾部;'middle':中间;'tip':尖端 normalizebool 类型,如果为 True,则所有箭头的长度都将相同 默认为 False,即箭头的长度取决于 U、V、W 的值 **kwargs其他关键字参数,参见 LineCollection import matplotlib.pyplot as pltimport numpy as npplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']# 依次获取画布和绘图区并创建 Axes3D 对象fig = plt.figure()ax = fig.gca(projection='3d')# 设置箭头位置x, y, z = np.meshgrid(np.arange(-0.8, 1, 0.2), np.arange(-0.8, 1, 0.2), np.arange(-0.8, 1, 0.8))# 设置箭头数据u = np.sin(np.pi * x) * np.cos(np.pi * y) * np.cos(np.pi * z)v = -np.cos(np.pi * x) * np.sin(np.pi * y) * np.cos(np.pi * z)w = (np.sqrt(2.0 / 3.0) * np.cos(np.pi * x) * np.cos(np.pi * y) * np.sin(np.pi * z))# 绘制 3D 箭头图ax.quiver(x, y, z, u, v, w, length=0.1, normalize=True)# 设置图像标题、坐标标签ax.set_title('绘制 3D 箭头图示例', pad=15, fontsize='12')ax.set_xlabel('X 轴')ax.set_ylabel('Y 轴')ax.set_zlabel('Z 轴')# 调整观察角度,俯仰角20度ax.view_init(20)plt.show() 【09x00】3D 等高线图:Axes3D.contour 基本方法:Axes3D.contour(X, Y, Z[, *args, extend3d=False, stride=5, zdir='z', offset=None, **kwargs]) 参数描述 X一维数组,x 轴数据 Y一维数组,y 轴数据 Z一维数组,z 轴数据 extend3dbool 值,可选项,是否以 3D 延伸轮廓,默认 False strideint 类型,可选项,用于延伸轮廓的步长 zdir可选项,在 3D 轴上绘制 2D 数据时,数据必须以 xs,ys 的形式传递, 若此时将 zdir 设置为 ‘y’,数据将会被绘制到 x-z 轴平面上,默认为 ‘z’ offset标量,可选项,如果指定,则在垂直于 zdir 的平面上的位置绘制轮廓线的投影 **kwargs其他关键字参数,可选项,可参见 matplotlib.axes.Axes.contour import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']# 获取 figure 画布并通过子图创建 Axes3D 对象fig = plt.figure(figsize=(8, 4.8))ax = fig.add_subplot(111, projection='3d')# 设置等高线数据X = np.arange(-2.0, 2.0, 0.01)Y = np.arange(-2.0, 2.0, 0.01)# 生成网格点坐标矩阵m, n = np.meshgrid(X, Y)# 指定一个函数用于计算每个点的高度,也可以直接使用二维数组储存每个点的高度def f(a, b): return (1 - b ** 5 + a ** 5) * np.exp(-a ** 2 - b ** 2)# 绘制3D等高线图并添加色条图(长度0.8)contour = ax.contour(X, Y, f(m, n), cmap='rainbow')fig.colorbar(contour, shrink=0.8)# 设置标题、轴标签、图例,也可以直接使用 plt.title、plt.xlabel...ax.set_title('绘制 3D 等高线图示例', pad=15, fontsize='12')ax.set_xlabel('x 轴')ax.set_ylabel('y 轴')ax.set_zlabel('z 轴')plt.show() 【10x00】3D 等高线填充图:Axes3D.contourf 基本语法:Axes3D.contourf(X, Y, Z[, *args, zdir='z', offset=None, **kwargs]) 参数描述 X一维数组,x 轴数据 Y一维数组,y 轴数据 Z一维数组,z 轴数据 zdir可选项,在 3D 轴上绘制 2D 数据时,数据必须以 xs,ys 的形式传递, 若此时将 zdir 设置为 ‘y’,数据将会被绘制到 x-z 轴平面上,默认为 ‘z’ offset标量,可选项,如果指定,则在垂直于 zdir 的平面上的位置绘制轮廓线的投影 **kwargs其他关键字参数,可选项,可参见 matplotlib.axes.Axes.contourf import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']# 获取 figure 画布并通过子图创建 Axes3D 对象fig = plt.figure(figsize=(8, 4.8))ax = fig.add_subplot(111, projection='3d')# 设置等高线数据X = np.arange(-2.0, 2.0, 0.01)Y = np.arange(-2.0, 2.0, 0.01)# 生成网格点坐标矩阵m, n = np.meshgrid(X, Y)# 指定一个函数用于计算每个点的高度,也可以直接使用二维数组储存每个点的高度def f(a, b): return (1 - b ** 5 + a ** 5) * np.exp(-a ** 2 - b ** 2)# 绘制3D等高线图并添加色条图(长度0.8)contourf = ax.contourf(X, Y, f(m, n), cmap='rainbow')fig.colorbar(contourf, shrink=0.8)# 设置标题、轴标签、图例,也可以直接使用 plt.title、plt.xlabel...ax.set_title('绘制 3D 等高线填充图示例', pad=15, fontsize='12')ax.set_xlabel('x 轴')ax.set_ylabel('y 轴')ax.set_zlabel('z 轴')plt.show() 【11x00】3D 三角曲面图:Axes3D.plot_trisurf 基本方法:Axes3D.plot_trisurf(X, Y, Z[, *args, color=None, vmin=None, vmax=None, **kwargs]) 参数描述 X一维数组,x 轴数据 Y一维数组,y 轴数据 Z一维数组,z 轴数据 color曲面表面的颜色 vmin / vmax规定数据界限 **kwargs可选项,其他关键字参数,可参见 Poly3DCollection import matplotlib.pyplot as pltimport numpy as npplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']# 获取 figure 画布并通过子图创建 Axes3D 对象fig = plt.figure()ax = fig.add_subplot(111, projection='3d')n_radii = 8n_angles = 36radii = np.linspace(0.125, 1.0, n_radii)angles = np.linspace(0, 2*np.pi, n_angles, endpoint=False)[..., np.newaxis]x = np.append(0, (radii*np.cos(angles)).flatten())y = np.append(0, (radii*np.sin(angles)).flatten())z = np.sin(-x*y)# 绘制3D三角曲面图并添加色条(长度0.8)trisurf = ax.plot_trisurf(x, y, z, cmap='rainbow')fig.colorbar(trisurf, shrink=0.8)# 设置标题、轴标签、图例,也可以直接使用 plt.title、plt.xlabel...ax.set_title('绘制 3D 三角曲面图示例', pad=15, fontsize='12')ax.set_xlabel('x 轴')ax.set_ylabel('y 轴')ax.set_zlabel('z 轴')plt.show() import numpy as npimport matplotlib.pyplot as pltimport matplotlib.tri as mtriplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']fig = plt.figure(figsize=(15, 6))# ============ 第一个示例图 ============ #ax = fig.add_subplot(1, 2, 1, projection='3d')u = np.linspace(0, 2.0 * np.pi, endpoint=True, num=50)v = np.linspace(-0.5, 0.5, endpoint=True, num=10)u, v = np.meshgrid(u, v)u, v = u.flatten(), v.flatten()x = (1 + 0.5 * v * np.cos(u / 2.0)) * np.cos(u)y = (1 + 0.5 * v * np.cos(u / 2.0)) * np.sin(u)z = 0.5 * v * np.sin(u / 2.0)tri = mtri.Triangulation(u, v)trisurf_1 = ax.plot_trisurf(x, y, z, triangles=tri.triangles, cmap='cool')fig.colorbar(trisurf_1, shrink=0.8)ax.set_zlim(-1, 1)ax.set_title('绘制 3D 三角曲面图示例一', pad=15, fontsize='12')ax.set_xlabel('x 轴')ax.set_ylabel('y 轴')ax.set_zlabel('z 轴')# ============ 第二个示例图 ============ #ax = fig.add_subplot(1, 2, 2, projection='3d')n_angles = 36n_radii = 8min_radius = 0.25radii = np.linspace(min_radius, 0.95, n_radii)angles = np.linspace(0, 2*np.pi, n_angles, endpoint=False)angles = np.repeat(angles[..., np.newaxis], n_radii, axis=1)angles[:, 1::2] += np.pi/n_anglesx = (radii*np.cos(angles)).flatten()y = (radii*np.sin(angles)).flatten()z = (np.cos(radii)*np.cos(3*angles)).flatten()triang = mtri.Triangulation(x, y)xmid = x[triang.triangles].mean(axis=1)ymid = y[triang.triangles].mean(axis=1)mask = xmid**2 + ymid**2 < min_radius**2triang.set_mask(mask)trisurf_2 = ax.plot_trisurf(triang, z, cmap='hsv')fig.colorbar(trisurf_2, shrink=0.8)ax.set_title('绘制 3D 三角曲面图示例二', pad=15, fontsize='12')ax.set_xlabel('x 轴')ax.set_ylabel('y 轴')ax.set_zlabel('z 轴')plt.show() 【12x00】将 2D 图像聚合到 3D 图像中:Axes3D.add_collection3d 基本方法:Axes3D.add_collection3d(col, zs=0, zdir='z') 参数描述 colPolyCollection / LineCollection / PatchCollection 对象 zs第 i 个多边形将出现在平面 y=zs[i] 上 zdir可选项,在 3D 轴上绘制 2D 数据时,数据必须以 xs,ys 的形式传递, 若此时将 zdir 设置为 ‘y’,数据将会被绘制到 x-z 轴平面上,默认为 ‘z’ 该函数一般用来向图形中添加 3D 集合对象,以下用一个示例来展示某个地区在不同年份和不同月份的降水量: import numpy as npimport matplotlib.pyplot as pltfrom matplotlib.collections import PolyCollectionplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']fig = plt.figure()ax = fig.gca(projection='3d')np.random.seed(59)month = np.arange(0, 13)years = [2017, 2018, 2019, 2020]precipitation = []for year in years: value = np.random.rand(len(month)) * 300 value[0], value[-1] = 0, 0 precipitation.append(list(zip(month, value)))poly = PolyCollection(precipitation, facecolors=['r', 'g', 'b', 'y'], alpha=.6)ax.add_collection3d(poly, zs=years, zdir='y')ax.set_title('2D 图像聚合到 3D 图像示例', pad=15, fontsize='12')ax.set_xlabel('月份')ax.set_ylabel('年份')ax.set_zlabel('降水量')ax.set_xlim3d(0, 12)ax.set_ylim3d(2016, 2021)ax.set_zlim3d(0, 300)plt.show() 此外,该方法也常被用于绘制 3D 多边形图,即多边体,示例如下: import matplotlib.pyplot as pltfrom mpl_toolkits.mplot3d.art3d import Poly3DCollection, Line3DCollectionplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']fig = plt.figure()ax = fig.gca(projection='3d')# 六面体顶点和面verts = [(0, 0, 0), (0, 1, 0), (1, 1, 0), (1, 0, 0), (0, 0, 1), (0, 1, 1), (1, 1, 1), (1, 0, 1)]faces = [[0, 1, 2, 3], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [0, 3, 7, 4]]# 获取每个面的顶点poly3d = [[verts[vert_id] for vert_id in face] for face in faces]# 绘制顶点x, y, z = zip(*verts)ax.scatter(x, y, z)# 绘制多边形面ax.add_collection3d(Poly3DCollection(poly3d, facecolors='w', linewidths=1, alpha=0.5))# 绘制多边形的边ax.add_collection3d(Line3DCollection(poly3d, colors='k', linewidths=0.5, linestyles=':'))# 设置图像标题、坐标标签以及范围ax.set_title('绘制多边体示例', pad=15, fontsize='12')ax.set_xlabel('X 轴')ax.set_ylabel('Y 轴')ax.set_zlabel('Z 轴')ax.set_xlim3d(-0.5, 1.5)ax.set_ylim3d(-0.5, 1.5)ax.set_zlim3d(-0.5, 1.5)plt.show() 【13x00】3D 图添加文本描述:Axes3D.text 基本方法:Axes3D.text(x, y, z, s[, zdir=None, **kwargs]) 参数描述 x, y, z文本位置的 x、y、z 轴坐标 s要添加的文本 zdir可选项,若将 zdir 设置为 ‘y’,文本将会被投影到 x-z 轴平面上,默认为 None **kwargs其他关键字参数,参见 matplotlib.text import matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']# 依次获取画布和绘图区并创建 Axes3D 对象fig = plt.figure()ax = fig.gca(projection='3d')# Demo 1: zdir 参数用法zdirs = (None, 'x', 'y', 'z', (1, 1, 0), (1, 1, 1))xs = (1, 4, 4, 9, 4, 1)ys = (2, 5, 8, 10, 1, 2)zs = (10, 3, 8, 9, 1, 8)for zdir, x, y, z in zip(zdirs, xs, ys, zs): label = '(%d, %d, %d), dir=%s' % (x, y, z, zdir) ax.text(x, y, z, label, zdir)# Demo 2:设置颜色ax.text(9, 0, 0, "red", color='red')# Demo 3: text2D,位置(0,0)为左下角,(1,1)为右上角。ax.text2D(0.05, 0.95, "2D Text", transform=ax.transAxes)# 设置坐标轴界限和标签ax.set_xlim(0, 10)ax.set_ylim(0, 10)ax.set_zlim(0, 10)ax.set_xlabel('X 轴')ax.set_ylabel('Y 轴')ax.set_zlabel('Z 轴')plt.show() 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106558131未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【1x00】了解极坐标 【2x00】基本方法 matplotlib.pyplot.polar() 【3x00】绘制极坐标 【4x00】绘制雷达图 【4x01】理解 numpy.concatenate() 【4x02】理解 pyplot.thetagrids() 【4x03】绘制雷达图 【5x00】高级用法:绘制极坐标散点图 【5x01】方法一:pyplot.scatter() 与 pyplot.polar() 【5x02】方法二:pyplot.scatter() 与 pyplot.subplot() 【5x03】方法三:pyplot.scatter() 与 pyplot.axes() 【6x00】高级用法:绘制极坐标柱状图 【6x01】方法一:pyplot.bar() 与 pyplot.polar() 【6x02】方法二:pyplot.bar() 与 pyplot.subplot() 【6x03】方法三:pyplot.bar() 与 pyplot.axes() Matplotlib 系列文章: Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件 Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性 Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性 Python 数据分析三剑客之 Matplotlib(四):线性图的绘制 Python 数据分析三剑客之 Matplotlib(五):散点图的绘制 Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制 Python 数据分析三剑客之 Matplotlib(七):饼状图的绘制 Python 数据分析三剑客之 Matplotlib(八):等高线 / 等值线图的绘制 Python 数据分析三剑客之 Matplotlib(九):极区图 / 极坐标图 / 雷达图的绘制 Python 数据分析三剑客之 Matplotlib(十):3D 图的绘制 Python 数据分析三剑客之 Matplotlib(十一):最热门最常用的 50 个图表【译文】 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106162412未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【1x00】了解极坐标 参考百度百科:极坐标,属于二维坐标系统,创始人是牛顿,主要应用于数学领域。极坐标是指在平面内取一个定点 O,叫极点,引一条射线 Ox,叫做极轴,再选定一个长度单位和角度的正方向(通常取逆时针方向)。对于平面内任何一点 M,用 ρ 表示线段 OM 的长度(有时也用 r 表示),θ 表示从 Ox 到 OM 的角度,ρ 叫做点 M 的极径,θ 叫做点 M 的极角,有序数对 (ρ,θ) 就叫点 M 的极坐标,这样建立的坐标系叫做极坐标系。通常情况下,M 的极径坐标单位为 1(长度单位),极角坐标单位为 rad(或°)。 【2x00】基本方法 matplotlib.pyplot.polar() matplotlib.pyplot.polar() 方法可用于绘制极坐标图。 基本语法:polar(theta, r, **kwargs) theta:点的角坐标,以弧度单位传入参数; r:点的半径坐标; **kwargs:可选项,其他 Line2D 属性,常用属性见表一。 拓展:数学上通常是用弧度而非角度,弧度单位缩写为 rad,2π rad = 360°,1° ≈ 0.0174533 rad,1 rad ≈ 57.29578°。 角度转换为弧度公式:弧度 = 角度 ÷ 180 × π 弧度转换为角度公式:角度 = 弧度 × 180 ÷ π 表一:Line2D 部分属性,完整属性参见官方文档: https://matplotlib.org/api/_as_gen/matplotlib.lines.Line2D.html 属性描述 alpha线条透明度,float 类型,取值范围:[0, 1],默认为 1.0,即不透明 antialiased / aa是否使用抗锯齿渲染,默认为 True color / c线条颜色,支持英文颜色名称及其简写、十六进制颜色码等,更多颜色示例参见官网 Color Demo fillstyle点的填充样式,'full'、'left'、'right'、'bottom'、'top'、'none' label图例,具体参数参见: 《Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性》 linestyle / ls连接的线条样式:'-' or 'solid', '--' or 'dashed', '-.' or 'dashdot' ':' or 'dotted', 'none' or ' ' or '' linewidth / lw连接的线条宽度,float 类型,默认 0.8 marker标记样式,具体样式参见表二 markeredgecolor / mecmarker 标记的边缘颜色 markeredgewidth / mewmarker 标记的边缘宽度 markerfacecolor / mfcmarker 标记的颜色 markerfacecoloralt / mfcaltmarker 标记的备用颜色 markersize / msmarker 标记的大小 表二:marker 标记的样式,官方文档: https://matplotlib.org/api/markers_api.html 标记描述 "."点 ","像素点 "o"圆圈 "v"倒三角 "^"正三角 "<"左三角 ">"右三角 "1"倒三叉星 "2"正三叉星(类似奔驰车标形状) "3"左三叉星 "4"右三叉星 "8"八边形 "s"正方形 "p"五边形 "P"填充的加号(粗加号) "+"加号 "*"星形 "h"六边形(底部是角) "H"六边形(底部是边) "x"x 号 "X"填充的 x 号(粗 x 号) "D"粗菱形(对角线相等) "d"细菱形(对角线不等) `""` "_"水平线 0水平线靠左 1水平线靠右 2垂直线靠上 3垂直线靠下 4左三角(比 "<" 更细) 5右三角(比 ">" 更细) 6正三角(比 "^" 更细) 7倒三角(比 "v" 更细) 8左三角(比 "<" 更细,靠左显示) 9右三角(比 ">" 更细,靠右显示) 10正三角(比 "^" 更细,靠上显示) 11倒三角(比 "v" 更细,靠下显示) "None" / " " / ""无样式 '$...$'支持 LaTeX 数学公式,表达式用美元符号包围起来 【3x00】绘制极坐标 import numpy as npimport matplotlib.pyplot as plt# 设置中文显示plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']# 设置画布大小plt.figure(figsize=(8.0, 6.0))# 设置三个数据,theta 为点位置的弧度参数,r 为点的半径坐标theta1 = np.array([1.25*np.pi, np.pi/2, 0])theta2 = np.array([-np.pi/6, -np.pi/2, 0, np.pi/2, np.pi])theta3 = np.arange(0., 2*np.pi, 0.5)r1 = np.array([4, 2, 3])r2 = np.array([5, 2, 4, 5, 3])r3 = np.random.randint(0, 5, 13)# 绘制第一个极坐标图,点的标记样式为细菱形,大小为8,点之间的连接线条样式为:plt.polar(theta1, r1, marker='d', ms=8, ls=':', label='数据一')# 填充第一个极坐标图,填充颜色为蓝色,透明度0.3plt.fill(theta1, r1, color='b', alpha=0.3)# 绘制第二个极坐标图,marker、linestyle、color 三个参数可以组合以字符串形式传入plt.polar(theta2, r2, '*-g', ms=10, label='数据二')# 绘制第三个极坐标图,设置 linestyle 为 none,即点与点之间不相连plt.polar(theta3, r3, marker='o', ls='none', ms=8, color='r', label='数据三')plt.title('matplotlib.pyplot.polar 用法示例', pad=25, fontsize=15)plt.legend(bbox_to_anchor=(1.3, 1))plt.show() 示例中 figure、title、legend 等其他方法的解释可参见我的系列文章: 《Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件》 《Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性》 《Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性》 绘制结果如下图: 【4x00】绘制雷达图 雷达图是以从同一点开始的轴上表示的三个或更多个定量变量的二维图表的形式显示多变量数据的图形方法。轴的相对位置和角度通常是无信息的。 雷达图也称为网络图,蜘蛛图,星图,蜘蛛网图,不规则多边形,极坐标图或 Kiviat 图。它相当于平行坐标图,轴径向排列。 在前面的示例中,使用了 matplotlib.pyplot.fill() 方法对三个极坐标点围成的图形进行了填充,这就有点儿接近于雷达图了,仔细观察前面的示例,在填充时第一个点和最后一个点之间没有连线,即没有闭合,而更精确的雷达图应该是闭合的,且外围应该是文字描述而不是度数。 在绘制雷达图之前需要提前了解一些函数。这些函数可以帮助我们实现闭合、自定义文字标签等。 【4x01】理解 numpy.concatenate() numpy.concatenate() 方法用于沿现有轴连接一系列数组,我们可以利用此方法来实现闭合操作。 基本语法:numpy.concatenate((a1, a2, ...)[, axis=0, out=None]) 参数描述 a1, a2, …要连接的数组,必须拥有相同的维度 axis沿指定轴连接数组,可选项,如果 axis 为 None,则数组在使用前被展平,默认值为 0 out用于接收连接后的数组,可选项 用法示例: import numpy as npa = np.array([1, 2, 3, 4])b = np.array(['a', 'b', 'c', 'd'])print(np.concatenate((a, b))) 输出结果如下: ['1' '2' '3' '4' 'a' 'b' 'c' 'd'] 如果要实现数组的闭合,则可以传入原数组和一个新数组,其中新数组中的元素为原数组中的第一个元素,示例如下: import numpy as npa = np.array([1, 2, 3, 4])print(np.concatenate((a, [a[0]]))) 输出结果如下: [1 2 3 4 1] 【4x02】理解 pyplot.thetagrids() matplotlib.pyplot.thetagrids() 方法用于获取并设置当前极区图上的极轴。 基本语法:matplotlib.pyplot.thetagrids(angles, labels=None, fmt=None, **kwargs) 参数描述 angles网格线的角度,浮点数、度数组成的元组 labels每个极轴要使用的文本标签,字符串组成的元组 fmt格式化 angles 参数,如 '%1.2f' 保留两位小数,注意,将使用以弧度为单位的角度 **kwargs其他关键字参数,参见官方文档 应用举例: import matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']plt.polar()angles = range(0, 360, 45)labels = ('东', '东北', '北', '西北', '西', '西南', '南', '东南')plt.thetagrids(angles, labels)plt.title('matplotlib.pyplot.thetagrids() 用法示例', pad=15)plt.show() 【4x03】绘制雷达图 numpy.concatenate() 方法能够解决闭合问题,matplotlib.pyplot.thetagrids() 能够解决自定义极轴和极轴的文本标记问题,因此就可以绘制一个标准的雷达图了。示例如下: import numpy as npimport matplotlib.pyplot as plt# 设置中文显示、画布大小plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']plt.figure(figsize=(8.0, 6.0))# 分割圆并执行闭合操作(0-2π之间返回间隔均匀的6个弧度:π/3、2π/3、π、4π/3、5π/3、2π)theta = np.linspace(0, 2*np.pi, 6, endpoint=False)theta = np.concatenate((theta, [theta[0]]))# 设置两组数据并执行闭合操作data1 = np.array([9, 4, 3, 5, 2, 8])data2 = np.array([3, 6, 9, 6, 3, 2])data1 = np.concatenate((data1, [data1[0]]))data2 = np.concatenate((data2, [data2[0]]))# 绘制并填充两组数据plt.polar(theta, data1, 'bo-', label='小王')plt.polar(theta, data2, 'ro:', label='小张')plt.fill(theta, data1, color='b', alpha=0.3)plt.fill(theta, data2, color='r', alpha=0.3)# 将六个弧度(π/3、2π/3、π、4π/3、5π/3、2π)转换成角度,并分别设置标签labels = np.array(['Python', 'Golang', 'Java', 'C++', 'PHP', 'JavaScript'])plt.thetagrids(theta * 180/np.pi, labels)# 设置刻度范围、标题、图例plt.ylim(0, 10)plt.title('编程语言掌握程度')plt.legend(bbox_to_anchor=(1.3, 1))plt.show() 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106162412未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【5x00】高级用法:绘制极坐标散点图 matplotlib.pyplot.polar() 方法可以实现极坐标散点图,但仅用这一个函数的话实现的样式效果并不多,以下介绍另外三种绘制极坐标散点图的方法: matplotlib.pyplot.polar() 和 matplotlib.pyplot.scatter() 结合,前者绘制极坐标图,后者在极坐标图上绘制散点图; matplotlib.pyplot.subplot() 和 matplotlib.pyplot.scatter() 结合,前者添加子图,其中指定 projection='polar' 即为极坐标图, 后者在极坐标图上绘制散点图; matplotlib.pyplot.axes() 与 matplotlib.pyplot.scatter() 结合,前者设置绘图区参数,其中指定 projection='polar' 或 polar=True 即为极坐标图, 后者在极坐标图上绘制散点图。 【5x01】方法一:pyplot.scatter() 与 pyplot.polar() 以下用到的 matplotlib.pyplot.scatter() 函数,各参数含义以及支持的其他参数可以参见前文: 《Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性》 《Python 数据分析三剑客之 Matplotlib(五):散点图的绘制》 import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']N = 50r = 2 * np.random.rand(N)theta = 2 * np.pi * np.random.rand(N)size = 200 * r ** 2colors = N * np.random.rand(N)plt.polar()plt.scatter(theta, r, s=size, c=colors, alpha=0.8)plt.title('极坐标散点图示例一', pad=15)plt.show() 【5x02】方法二:pyplot.scatter() 与 pyplot.subplot() matplotlib.pyplot.subplot() 方法用于添加子图,如果想要子图为极坐标图,则需要指定 projection 参数为 polar,有关此函数的具体介绍可参见官方文档。其他函数的参数解释可参考前文: 《Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性》 《Python 数据分析三剑客之 Matplotlib(五):散点图的绘制》 import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']N = 50r = 2 * np.random.rand(N)theta = 2 * np.pi * np.random.rand(N)size = 200 * r ** 2colors = N * np.random.rand(N)# 一行一列第一个子图plt.subplot(111, projection='polar')plt.scatter(theta, r, s=size, c=colors, alpha=0.8)plt.title('极坐标散点图示例二', pad=15)plt.show() 【5x03】方法三:pyplot.scatter() 与 pyplot.axes() axes 为 Matplotlib 图像中的绘图区,matplotlib.pyplot.axes() 方法可以对绘图区进行设置,同样的也可以设置 projection 参数为 polar 来实现极坐标图,设置 polar=True 也行。示例中其他函数的参数解释可参考前文: 《Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件》 《Python 数据分析三剑客之 Matplotlib(五):散点图的绘制》 import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']N = 50r = 2 * np.random.rand(N)theta = 2 * np.pi * np.random.rand(N)size = 200 * r ** 2colors = N * np.random.rand(N)# plt.axes(polar=True)plt.axes(projection='polar')plt.scatter(theta, r, s=size, c=colors, alpha=0.8)plt.title('极坐标散点图示例三', pad=15)plt.show() 【6x00】高级用法:绘制极坐标柱状图 和极坐标散点图的绘制类似,matplotlib.pyplot.polar() 方法可以实现极坐标图,但仅用这一个函数的话实现的样式效果并不多,以下介绍另外三种绘制极坐标柱状图的方法: matplotlib.pyplot.polar() 和 matplotlib.pyplot.bar() 结合,前者绘制极坐标图,后者在极坐标图上绘制柱状图; matplotlib.pyplot.subplot() 和 matplotlib.pyplot.bar() 结合,前者添加子图,其中指定 projection='polar' 即为极坐标图, 后者在极坐标图上绘制柱状图; matplotlib.pyplot.axes() 与 matplotlib.pyplot.bar() 结合,前者设置绘图区参数,其中指定 projection='polar' 或 polar=True 即为极坐标图, 后者在极坐标图上绘制柱状图。 【6x01】方法一:pyplot.bar() 与 pyplot.polar() 以下用到的 matplotlib.pyplot.bar() 函数,各参数含义以及支持的其他参数可以参见前文: 《Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性》 《Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制》 import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']r = np.random.rand(8)theta = np.arange(0, 2 * np.pi, 2 * np.pi / 8)colors = np.array(['#4bb2c5', '#c5b47f', '#EAA228', '#579575', '#839557', '#958c12', '#953579', '#4b5de4'])plt.polar()plt.bar(theta, r, color=colors, alpha=0.8)plt.title('极坐标柱状图示例一', pad=15)plt.show() 【6x02】方法二:pyplot.bar() 与 pyplot.subplot() matplotlib.pyplot.subplot() 方法用于添加子图,如果想要子图为极坐标图,则需要指定 projection 参数为 polar,有关此函数的具体介绍可参见官方文档。其他函数的参数解释可参考前文: 《Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性》 《Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制》 import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']r = np.random.rand(8)theta = np.arange(0, 2 * np.pi, 2 * np.pi / 8)colors = np.array(['#4bb2c5', '#c5b47f', '#EAA228', '#579575', '#839557', '#958c12', '#953579', '#4b5de4'])plt.subplot(111, projection='polar')plt.bar(theta, r, color=colors, alpha=0.8)plt.title('极坐标柱状图示例二', pad=15)plt.show() 【6x03】方法三:pyplot.bar() 与 pyplot.axes() axes 为 Matplotlib 图像中的绘图区,matplotlib.pyplot.axes() 方法可以对绘图区进行设置,同样的也可以设置 projection 参数为 polar 来实现极坐标图,设置 polar=True 也行。示例中其他函数的参数解释可参考前文: 《Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件》 《Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制》 import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']r = np.random.rand(8)theta = np.arange(0, 2 * np.pi, 2 * np.pi / 8)colors = np.array(['#4bb2c5', '#c5b47f', '#EAA228', '#579575', '#839557', '#958c12', '#953579', '#4b5de4'])# plt.axes(polar=True)plt.axes(projection='polar')plt.bar(theta, r, color=colors, alpha=0.8)plt.title('极坐标柱状图示例三', pad=15)plt.show() 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106162412未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【1x00】等高线概念 【2x00】理解 numpy.meshgrid() 【3x00】绘制方法 matplotlib.pyplot.contour() 【4x00】填充方法 matplotlib.pyplot.contourf() 【5x00】标记方法 matplotlib.pyplot.clabel() 【6x00】Colormap 取值 【7x00】简单示例 【8x00】添加标记 【9x00】轮廓线颜色和样式 【10x00】颜色填充 Matplotlib 系列文章: Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件 Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性 Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性 Python 数据分析三剑客之 Matplotlib(四):线性图的绘制 Python 数据分析三剑客之 Matplotlib(五):散点图的绘制 Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制 Python 数据分析三剑客之 Matplotlib(七):饼状图的绘制 Python 数据分析三剑客之 Matplotlib(八):等高线 / 等值线图的绘制 Python 数据分析三剑客之 Matplotlib(九):极区图 / 极坐标图 / 雷达图的绘制 Python 数据分析三剑客之 Matplotlib(十):3D 图的绘制 Python 数据分析三剑客之 Matplotlib(十一):最热门最常用的 50 个图表【译文】 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106066852未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【1x00】等高线概念 参考百度百科,等高线概念总结如下:等高线指的是地形图上高程相等的相邻各点所连成的闭合曲线。把地面上海拔高度相同的点连成的闭合曲线,并垂直投影到一个水平面上,并按比例缩绘在图纸上,就得到等高线。等高线也可以看作是不同海拔高度的水平面与实际地面的交线,所以等高线是闭合曲线。在等高线上标注的数字为该等高线的海拔。 位于同一等高线上的地面点,海拔高度相同。但海拔高度相同的点不一定位于同一条等高线上; 在同一幅图内,除了陡崖以外,不同高程的等高线不能相交; 在图廓内相邻等高线的高差一般是相同的,因此地面坡度与等高线之间的等高线平距成反比,等高线平距愈小,等高线排列越密,说明地面坡度越大;等高线平距愈大,等高线排列越稀,则说明地面坡度愈小; 等高线是一条闭合的曲线,如果不能在同一幅内闭合,则必在相邻或者其他图幅内闭合。 等高线经过山脊或山谷时改变方向,因此,山脊线或者山谷线应垂直于等高线转折点处的切线,即等高线与山脊线或者山谷线正交。 在 Matplotlib 等高线的绘制中,需要传递三个基本参数:某个点的 x、y 轴坐标以及其高度。 【2x00】理解 numpy.meshgrid() numpy.meshgrid() 方法用于生成网格点坐标矩阵。 import numpy as npa = np.array([1, 2, 3])b = np.array([7, 8, 9])res = np.meshgrid(a, b)print(res) 输出结果: [array([[1, 2, 3], [1, 2, 3], [1, 2, 3]]), array([[7, 7, 7], [8, 8, 8], [9, 9, 9]])] 给定两个数组,a[1, 2, 3] 和 b[7, 8, 9],a 作为 x 轴数据,b 作为 y 轴数据,那么一共可以绘制出 9 个点: (1,7)、(1,8)、(1,9)、(2,7)、(2,8)、(2,9)、(3,7)、(3,8)、(3,9),而 numpy.meshgrid() 方法就是起这样的作用,返回的两个二维数组,横坐标矩阵 a 中的每个元素,与纵坐标矩阵 b 中对应位置元素,共同构成一个点的完整坐标。 因为在 matplotlib.pyplot.contour() 等高线绘制函数中接收的是二维坐标信息,所以在绘制等高线图之前要将原数据经过 numpy.meshgrid() 方法处理,也可以自己构建类似于上述的二维数组。 【3x00】绘制方法 matplotlib.pyplot.contour() matplotlib.pyplot.contour() 方法可用于绘制等高线图。 基本语法:matplotlib.pyplot.contour(\*args, data=None, \*\*kwargs) 通用格式:matplotlib.pyplot.contour([X, Y,] Z, [levels], **kwargs) 基本参数: 参数描述 X, Y数组形式的点的 x 和 y 轴坐标,两者都必须是二维的,形状与 Z 相同 Z绘制轮廓的高度值,二维数组,每个元素是其对应点的高度 levels确定等高线的数目和位置,如果是整数 N,则使用 N 个数据间隔,即绘制 N+1 条等高线 如果是数组形式,则绘制指定的等高线。值必须按递增顺序排列 其他参数: 参数描述 colors等高线的颜色,颜色字符串或颜色序列 cmap等高线的颜色,字符串或者 Colormap 通常包含一系列的渐变色或其他颜色组合,取值参见【6x00】Colormap 取值 alpha透明度,介于0(透明)和1(不透明)之间 origin通过指定 Z[0,0] 的位置来确定 Z 的方向和确切位置,仅当未指定 X, Y 时才有意义 None:Z[0,0] 位于左下角的 X=0, Y=0 处 'lower':Z [0, 0] 位于左下角的 X = 0.5, Y = 0.5 处 'upper':Z[0,0] 位于左上角的 X=N+0.5, Y=0.5 处 'image':使用 rcParams[“image.origin”] = 'upper'的值 antialiased是否启用抗锯齿渲染,默认 True linewidths等高线的线宽,如果是数字,则所有等高线都将使用此线宽 如果是序列,则将按指定的顺序以升序打印线宽 默认为 rcParams[“lines.linewidth”] = 1.5 linestyles等高线的样式,如果线条颜色为单色,则负等高线默认为虚线 '-' or 'solid', '--' or 'dashed', '-.' or 'dashdot' ':' or 'dotted', 'none' or ' ' or '' 【4x00】填充方法 matplotlib.pyplot.contourf() matplotlib.pyplot.contourf() 方法与 matplotlib.pyplot.contour() 的区别在于:contourf() 会对等高线间的区域进行颜色填充(filled contours)。除此之外两者的函数签名和返回值都相同。 基本语法:matplotlib.pyplot.contourf(\*args, data=None, \*\*kwargs) 通用格式:matplotlib.pyplot.contour([X, Y,] Z, [levels], **kwargs) 基本参数: 参数描述 X, Y数组形式的点的 x 和 y 轴坐标,两者都必须是二维的,形状与 Z 相同 Z绘制轮廓的高度值,二维数组,每个元素是其对应点的高度 levels确定等高线的数目和位置,如果是整数 N,则使用 N 个数据间隔,即绘制 N+1 条等高线 如果是数组形式,则绘制指定的等高线。值必须按递增顺序排列 其他参数: 参数描述 colors等高线的填充颜色,颜色字符串或颜色序列 cmap等高线的填充颜色,字符串或者 Colormap 通常包含一系列的渐变色或其他颜色组合,取值参见【6x00】Colormap 取值 alpha透明度,介于0(透明)和1(不透明)之间 origin通过指定 Z[0,0] 的位置来确定 Z 的方向和确切位置,仅当未指定 X, Y 时才有意义 None:Z[0,0] 位于左下角的 X=0, Y=0 处 'lower':Z [0, 0] 位于左下角的 X = 0.5, Y = 0.5 处 'upper':Z[0,0] 位于左上角的 X=N+0.5, Y=0.5 处 'image':使用 rcParams[“image.origin”] = 'upper'的值 antialiased是否启用抗锯齿渲染,默认 True linewidths等高线的线宽,如果是数字,则所有等高线都将使用此线宽 如果是序列,则将按指定的顺序以升序打印线宽 默认为 rcParams[“lines.linewidth”] = 1.5 linestyles等高线的样式,如果线条颜色为单色,则负等高线默认为虚线 '-' or 'solid', '--' or 'dashed', '-.' or 'dashdot' ':' or 'dotted', 'none' or ' ' or '' 【5x00】标记方法 matplotlib.pyplot.clabel() matplotlib.pyplot.clabel(CS, \*args, \*\*kwargs) 方法可用于标记等高线图。 参数描述 CSContourSet(等高线集)对象,即 pyplot.contour() 返回的对象 levels需要标记的等高线集,数组类型,如果未指定则默认标记所有等高线 fontsize标记的字体大小,可选项: 'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large' colors标记的颜色,颜色字符串或颜色序列 inline是否在标签位置移除轮廓显示,bool 类型,默认 True inline_spacing标签位置移除轮廓的宽度,float 类型,默认为 5 fmt标签的格式字符串。str 或 dict 类型,默认值为 %1.3f rightside_up是否将标签旋转始终与水平面成正负90度,bool 类型,默认 True use_clabeltext默认为 False,如果为 True,则使用 ClabelText 类(而不是 Text)创建标签 ClabelText 在绘图期间重新计算文本的旋转角度,如果轴的角度发生变化,则可以使用此功能 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106066852未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【6x00】Colormap 取值 matplotlib.pyplot.contour() 和 matplotlib.pyplot.contourf() 中 cmap 参数用于设置等高线的颜色,取值通常为 Colormap 中的值,通常包含一系列的渐变色或其他颜色组合。具体参加下图。 官方文档:https://matplotlib.org/tutorials/colors/colormaps.html 【7x00】简单示例 import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']x = np.arange(-2.0, 2.0, 0.01)y = np.arange(-2.0, 2.0, 0.01)m, n = np.meshgrid(x, y) # 生成网格点坐标矩阵# 指定一个函数用于计算每个点的高度,也可以直接使用二维数组储存每个点的高度def f(a, b): return (1 - b ** 5 + a ** 5) * np.exp(-a ** 2 - b ** 2)# 绘制等高线图,8 个数据间隔,颜色为黑色plt.contour(m, n, f(m, n), 8, colors='k')plt.title('等高线图简单示例')plt.xlabel('x axis label')plt.ylabel('y axis label')plt.show() 【8x00】添加标记 matplotlib.pyplot.clabel() 方法用于给等高线添加标记。 import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']x = np.arange(-2.0, 2.0, 0.01)y = np.arange(-2.0, 2.0, 0.01)m, n = np.meshgrid(x, y) # 生成网格点坐标矩阵# 指定一个函数用于计算每个点的高度,也可以直接使用二维数组储存每个点的高度def f(a, b): return (1 - b ** 5 + a ** 5) * np.exp(-a ** 2 - b ** 2)# 绘制等高线图,8 个数据间隔,颜色为黑色C = plt.contour(m, n, f(m, n), 8, colors='k')# 添加标记,标记处不显示轮廓线,颜色为黑红绿蓝四种,保留两位小数plt.clabel(C, inline=True, colors=['k', 'r', 'g', 'b'], fmt='%1.2f')plt.title('等高线图添加标记示例')plt.xlabel('x axis label')plt.ylabel('y axis label')plt.show() 【9x00】轮廓线颜色和样式 matplotlib.pyplot.contour() 方法中,colors 参数即可为等高线轮廓设置颜色,可以是单色,也可以是一个颜色列表,linestyles 参数可以设置轮廓线样式,注意,如果线条颜色为单色,则负等高线(高度值为负)默认为虚线。 import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']x = np.arange(-2.0, 2.0, 0.01)y = np.arange(-2.0, 2.0, 0.01)m, n = np.meshgrid(x, y) # 生成网格点坐标矩阵# 指定一个函数用于计算每个点的高度,也可以直接使用二维数组储存每个点的高度def f(a, b): return (1 - b ** 5 + a ** 5) * np.exp(-a ** 2 - b ** 2)colors = ['k', 'r', 'g', 'b']# 绘制等高线图,8 个数据间隔,颜色为黑色,线条样式为 --C = plt.contour(m, n, f(m, n), 8, colors=colors, linestyles='--')# 添加标记,标记处不显示轮廓线,颜色为黑红绿蓝四种,保留两位小数plt.clabel(C, inline=True, colors=colors, fmt='%1.2f')plt.title('等高线图设置颜色/样式示例')plt.xlabel('x axis label')plt.ylabel('y axis label')plt.show() 如果想启用渐变色,则可以设置 cmap,取值参见【6x00】Colormap 取值,colorbar() 方法可以显示颜色对照条。 import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']x = np.arange(-2.0, 2.0, 0.01)y = np.arange(-2.0, 2.0, 0.01)m, n = np.meshgrid(x, y) # 生成网格点坐标矩阵# 指定一个函数用于计算每个点的高度,也可以直接使用二维数组储存每个点的高度def f(a, b): return (1 - b ** 5 + a ** 5) * np.exp(-a ** 2 - b ** 2)# 绘制等高线图,8 个数据间隔,颜色为 plasmaC = plt.contour(m, n, f(m, n), 8, cmap='plasma')# 添加标记,标记处不显示轮廓线,颜色为黑色,保留两位小数plt.clabel(C, inline=True, colors='k', fmt='%1.2f')# 显示颜色条plt.colorbar()plt.title('等高线图设置渐变色示例')plt.xlabel('x axis label')plt.ylabel('y axis label')plt.show() 【10x00】颜色填充 matplotlib.pyplot.contourf() 方法用于对等高线之间的地方进行颜色填充。 import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']x = np.arange(-2.0, 2.0, 0.01)y = np.arange(-2.0, 2.0, 0.01)m, n = np.meshgrid(x, y) # 生成网格点坐标矩阵# 指定一个函数用于计算每个点的高度,也可以直接使用二维数组储存每个点的高度def f(a, b): return (1 - b ** 5 + a ** 5) * np.exp(-a ** 2 - b ** 2)# 绘制等高线图,8 个数据间隔,颜色为 plasmaplt.contourf(m, n, f(m, n), 8, cmap='plasma')C = plt.contour(m, n, f(m, n), 8, cmap='plasma')# 添加标记,标记处不显示轮廓线,颜色为黑色,保留两位小数plt.clabel(C, inline=True, colors='k', fmt='%1.2f')# 显示颜色条plt.colorbar()plt.title('等高线图颜色填充示例')plt.xlabel('x axis label')plt.ylabel('y axis label')plt.show() 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106066852未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【1x00】方法描述 【2x00】简单示例 【3x00】按角度调整扇形标签 【4x00】显示图例 【5x00】突出显示扇形块 【6x00】显示各扇区所占百分比 【7x00】旋转饼状图 【8x00】自定义每个扇形和文字属性 Matplotlib 系列文章: Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件 Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性 Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性 Python 数据分析三剑客之 Matplotlib(四):线性图的绘制 Python 数据分析三剑客之 Matplotlib(五):散点图的绘制 Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制 Python 数据分析三剑客之 Matplotlib(七):饼状图的绘制 Python 数据分析三剑客之 Matplotlib(八):等高线 / 等值线图的绘制 Python 数据分析三剑客之 Matplotlib(九):极区图 / 极坐标图 / 雷达图的绘制 Python 数据分析三剑客之 Matplotlib(十):3D 图的绘制 Python 数据分析三剑客之 Matplotlib(十一):最热门最常用的 50 个图表【译文】 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106025845未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【1x00】方法描述 matplotlib.pyplot.pie() 方法用于绘制饼状图。 基本语法: matplotlib.pyplot.pie( x[, explode=None, labels=None, colors=None, autopct=None, pctdistance=0.6, shadow=False, labeldistance=1.1, startangle=None, radius=None, counterclock=True, wedgeprops=None, textprops=None, center=(0, 0), frame=False, rotatelabels=False, \*, data=None] ) 参数描述 x每个扇形块的大小,数组形式,大小单位是比例 explode指定对应扇形块脱离饼图的半径大小,数组形式,其中元素个数应该是 len(x) labels每个扇形块上的文本标签,列表形式 labeldistance每个扇形块上的文本标签与扇形中心的距离,float 类型,默认 1.1 colors每个扇形块对应的颜色,数组形式 autopct用于计算每个扇形块所占比例,字符串或者函数类型 例如:autopct='%1.1f%%' 表示浮点数,保留一位小数,并添加百分比符号 pctdistance每个扇形块的中心与 autopct 生成的文本之间的距离,float 类型,默认 0.6 shadow是否为扇形添加阴影效果 startangle将饼图按照逆时针旋转指定的角度,float 类型 radius饼图的半径,如果是 None,则将被设置为 1,float 类型 counterclock是否按照逆时针对扇形图进行排列,bool 类型,默认 True wedgeprops传递给绘制每个扇形图对象的参数,字典形式,参数值参见 Wedge 例如:wedgeprops = {'linewidth': 3} 设置扇形边框线宽度为 3 textprops传递给文本对象的参数,字典形式 例如:textprops={'color': 'r', 'fontsize': 15} 设置文字为红色,大小为15 center饼图圆心在画布上是坐标,默认 (0, 0) frame是否显示 x, y 坐标轴外框,默认 False rotatelabels是否按照角度进行调整每块饼的 label 文本标签,默认 False 【2x00】简单示例 import matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']x = [10, 30, 45, 15]labels = ['Java', 'Golang', 'Python', 'C++']colors = ['red', 'yellow', 'blue', 'green']# 指定4个扇区所占比例以及扇区的颜色,扇区文本标签距离扇区中心1.1plt.pie(x, labels=labels, colors=colors, labeldistance=1.1)plt.title('饼状图简单示例')plt.show() 【3x00】按角度调整扇形标签 rotatelabels 属性可以设置是否按照角度调整每块饼的 label(标签)显示方式。 import matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']x = [10, 30, 45, 15]labels = ['Java', 'Go', 'Python', 'C++']colors = ['red', 'yellow', 'blue', 'green']# 指定4个扇区所占比例以及扇区的颜色,扇区文本标签距离扇区中心1.1,按角度调整 labelsplt.pie(x, labels=labels, colors=colors, labeldistance=1.1, rotatelabels=True)plt.title('饼状图按角度调整 labels 示例')plt.show() 【4x00】显示图例 与前面文章中绘制线性图、散点图、条形图一样,调用 matplotlib.pyplot.legend() 方法可绘制图例,该方法的参数解释参见前文《Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性》 import matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']x = [10, 30, 45, 15]labels = ['Java', 'Go', 'Python', 'C++']colors = ['red', 'yellow', 'blue', 'green']plt.pie(x, labels=labels, colors=colors, labeldistance=1.1)plt.title('饼状图显示图例示例')plt.legend(bbox_to_anchor=(1, 1))plt.show() 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106025845未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【5x00】突出显示扇形块 explode 参数可以实现突出显示某一块扇区,接收数组形式的参数,这个数组中的元素个数应该是 len(x),即和扇区块的数量相同。 import matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']x = [10, 30, 45, 15]labels = ['Java', 'Golang', 'Python', 'C++']colors = ['red', 'yellow', 'blue', 'green']# 指定第一个扇区块脱离饼图的半径大小为0.3,其它扇区不脱离plt.pie(x, labels=labels, colors=colors, labeldistance=1.1, explode=[0.3, 0, 0, 0])plt.title('饼状图突出显示扇形块示例')plt.legend(bbox_to_anchor=(1, 1))plt.show() 【6x00】显示各扇区所占百分比 autopct 参数可用于计算每个扇形块所占比例,接收字符串或者函数类型,例如:autopct='%1.1f%%' 表示浮点数,保留一位小数,并添加百分比符号。pctdistance 参数用于调整每个扇形块的中心与 autopct 生成的文本之间的距离,float 类型,默认 0.6。 import matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']x = [10, 30, 45, 15]labels = ['Java', 'Golang', 'Python', 'C++']colors = ['red', 'yellow', 'blue', 'green']plt.pie( x, # 每个扇形块所占比例 labels=labels, # 扇形块文本标签 colors=colors, # 扇形块颜色 labeldistance=1.1, # 扇形块标签距离中心的距离 explode=[0.3, 0, 0, 0], # 第一个扇形块突出显示 autopct='%1.1f%%', # 显示百分比,保留一位小数 pctdistance=0.5 # 百分比文本距离饼状图中心的距离)plt.title('饼状图显示各扇区所占百分比示例')plt.legend(bbox_to_anchor=(1, 1)) # 显示图例plt.show() 【7x00】旋转饼状图 startangle 参数可以选择饼状图,改变饼状图放置的角度。注意是按照逆时针旋转。 import matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']x = [10, 30, 45, 15]labels = ['Java', 'Golang', 'Python', 'C++']colors = ['red', 'yellow', 'blue', 'green']plt.pie( x, # 每个扇形块所占比例 labels=labels, # 扇形块文本标签 colors=colors, # 扇形块颜色 labeldistance=1.1, # 扇形块标签距离中心的距离 explode=[0.3, 0, 0, 0], # 第一个扇形块突出显示 autopct='%1.1f%%', # 显示百分比,保留一位小数 pctdistance=0.5, # 百分比文本距离饼状图中心的距离 startangle=-90 # 逆时针旋转-90°,即顺时针旋转90°)plt.title('饼状图旋转角度示例')plt.legend(bbox_to_anchor=(1, 1)) # 显示图例plt.show() 【8x00】自定义每个扇形和文字属性 wedgeprops 参数以字典形式为每个扇形添加自定义属性,例如:wedgeprops = {'linewidth': 3} 设置扇形边框线宽度为 3,更多其他参数值参见 Wedge; textprops 参数同样以字典形式为文本对象添加自定义属性,例如:textprops={'color': 'r', 'fontsize': 15} 设置文字为红色,大小为15,更多其他参数值参见 Text。 import matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']x = [10, 30, 45, 15]labels = ['Java', 'Golang', 'Python', 'C++']colors = ['red', 'yellow', 'blue', 'green']plt.pie( x, # 每个扇形块所占比例 labels=labels, # 扇形块文本标签 colors=colors, # 扇形块颜色 labeldistance=1.1, # 扇形块标签距离中心的距离 explode=[0.3, 0, 0, 0], # 第一个扇形块突出显示 autopct='%1.1f%%', # 显示百分比,保留一位小数 pctdistance=0.6, # 百分比文本距离饼状图中心的距离 shadow=True, # 显示阴影效果 wedgeprops={ # 为每个扇形添加属性 'width': 0.7, # 扇形宽度0.7 'edgecolor': '#98F5FF', # 扇形边缘线颜色 'linewidth': 3 # 扇形边缘线宽度 }, textprops={ # 为文字添加属性 'fontsize': 13, # 文字大小 'fontweight': 'bold', # 文字粗细 'color': 'k' # 文字颜色,黑色 })plt.title('饼状图自定义每个扇形和文字属性示例', fontweight='bold')plt.legend(bbox_to_anchor=(1, 1), borderpad=0.6) # 显示图例plt.show() 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106025845未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
本文已收到抖音的律师函,CSDN 和本站的文章都已经做下架处理。 欢迎加入爬虫逆向微信交流群:添加微信 IT-BOB(备注交流群)
文章目录 栈的概念 栈的特点 栈的操作 Python 实现栈 栈的简单应用:括号匹配问题 栈的简单应用:倒序输出一组元素 栈的概念 栈(stack)又名堆栈,栈是一种线性数据结构,用先进后出或者是后进先出的方式存储数据,栈中数据的插入删除操作都是在栈的顶端进行,这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。 栈的特点 元素后进先出(Last in First Out,LIFO) 栈的操作 push(item):进栈(向栈顶添加元素) pop():出栈(删除栈顶元素) top():查看栈顶元素 empty():判断栈是否为空 Python 实现栈 栈并不是 Python 的内建类型,在必要的时候可以使用列表来模拟基于数组的栈。如果将列表的末尾看作是栈的顶,列表方法 append() 就是将元素压入到栈中(进栈),而列表方法 pop() 会删除并返回栈顶的元素(出栈),列表索引的方式 arr[-1] 可以查看栈顶元素。具体代码实现如下: class Stack: def __init__(self): self.stack = [] def push(self, item): self.stack.append(item) def pop(self): if self.empty(): return None else: return self.stack.pop() def top(self): if self.empty(): return None else: return self.stack[-1] def empty(self): return len(self.stack) == 0 栈的简单应用:括号匹配问题 问题描述: 给定一个字符串,字符串中只包含小括号 ()、中括号 []、大括号 {},求该字符串中的括号是否匹配。匹配规则:成对出现或者左右对称出现,例如: ()[]{}:匹配;{[()]}:匹配;({}]:不匹配;()]:不匹配;({)}:不匹配 通过栈来解决: 有字符串 ()[{}],依次取每个括号,只要是左括号就进栈,只要是右括号就判断栈顶是否为对应的左括号,具体步骤如下: ① 遇到左小括号 (,执行进栈操作; ② 遇到右小括号 ),判断此时栈顶是否为左小括号 (,是则让左小括号 ( 出栈,此时栈为空; ③ 遇到左中括号 [,执行进栈操作; ④ 遇到左大括号 {,执行进栈操作; ⑤ 遇到右大括号 },判断此时栈顶是否为左大括号 {,是则让左大括号 { 出栈,此时栈为空; ⑥ 遇到右中括号 ],判断此时栈顶是否为左中括号 [,是则让左中括号 [ 出栈,此时栈为空; ⑦ 判断最终的栈是否为空,是则表示匹配,不是则表示不匹配。其中第 ② ⑤ ⑥ 步中,若判断为不是,则直接表示不匹配。 Python 代码实现: class Stack: def __init__(self): self.stack = [] def push(self, item): self.stack.append(item) def pop(self): if self.empty(): return None else: return self.stack.pop() def top(self): if self.empty(): return None else: return self.stack[-1] def empty(self): return len(self.stack) == 0def brackets_match(s): match_dict = {'}': '{', ']': "[", ')': '('} stack = Stack() for ch in s: if ch in ['(', '[', '{']: # 如果为左括号,则执行进栈操作 stack.push(ch) else: # 如果为右括号 if stack.empty(): # 如果栈为空,则不匹配,即多了一个右括号,没有左括号匹配 return False elif stack.top() == match_dict[ch]: # 如果栈顶的元素为对应的左括号,则让栈顶出栈 stack.pop() else: # 如果栈顶元素不是对应的左括号,则不匹配 return False if stack.empty(): # 最后的栈如果为空,则匹配,否则不匹配 return True else: return Falseprint(brackets_match('[{()}(){()}[]({}){}]'))print(brackets_match('()[{}]'))print(brackets_match('({)}'))print(brackets_match('[]}')) 输出结果: TrueTrueFalseFalse 栈的简单应用:倒序输出一组元素 把元素存入栈,再顺序取出: class Stack: def __init__(self): self.stack = [] def push(self, item): self.stack.append(item) def pop(self): if self.empty(): return None else: return self.stack.pop() def top(self): if self.empty(): return None else: return self.stack[-1] def empty(self): return len(self.stack) == 0def reverse_list(s): stack = Stack() for ch in s: stack.push(ch) new_list = [] while not stack.empty(): new_list.append(stack.pop()) return new_listprint(reverse_list(['A', 'B', 'C', 'D', 'E'])) 输出结果: ['E', 'D', 'C', 'B', 'A']
文章目录 递归概念 递归要素 递归与迭代的区别 示例一:阶乘 示例二:斐波那契数列 示例三:汉诺塔问题 尾递归 Python 中尾递归的解决方案 递归概念 递归:程序调用自身的编程技巧称为递归( recursion)。用一种通俗的话来说就是自己调用自己,它通常把一个大型复杂的问题层层转化为一个与原问题相似的、但是规模较小的问题来求解,当问题小到一定规模的时候,需要一个递归出口返回。递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。 递归函数:在编程语言中,函数直接或间接调用函数本身,则该函数称为递归函数;在数学上的定义如下:对于某一函数 f(x)f(x)f(x),其定义域是集合 A,那么若对于 A 集合中的某一个值 X0X_0X0,其函数值 f(x0)f(x_0)f(x0) 由 f(f(x0))f(f(x_0))f(f(x0)) 决定,那么就称 f(x)f(x)f(x) 为递归函数。 递归要素 递归必须包含一个基本的出口(结束条件),否则就会无限递归,最终导致栈溢出; 递归必须包含一个可以分解的问题,例如要想求得 fact(n)fact(n)fact(n),就需要用 n∗fact(n−1)n * fact(n-1)n∗fact(n−1); 递归必须必须要向着递归出口靠近,例如每次递归调用都会 n−1n-1n−1,向着递归出口 n==0n == 0n==0 靠近。 递归与迭代的区别 递归(recursion):递归则是一步一步往前递推,直到递归基础,寻找一条路径, 然后再由前向后计算。(A调用A) 迭代(iteration):迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果。每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值,因此迭代是从前往后计算的。(A重复调用B) 示例一:阶乘 一个正整数的阶乘(factorial)是所有小于及等于该数的正整数的积,并且 0 的阶乘为 1。即 n!=1×2×3×...×(n−1)×nn!=1×2×3×...×(n-1)×nn!=1×2×3×...×(n−1)×n,以递归方式定义:n!=(n−1)!×nn!=(n-1)!×nn!=(n−1)!×n def factorial(n): if n == 0: return 1 else: return n * factorial(n-1) 示例二:斐波那契数列 斐波那契数列(Fibonacci sequence),又称黄金分割数列、因数学家莱昂纳多·斐波那契以兔子繁殖为例子而引入,故又称为“兔子数列”。 有一个数列:0、1、1、2、3、5、8、13、21、34、55、89…,这个数列从第3项开始,每一项都等于前两项之和。以递推的方法定义:F(n)=F(n−1)+F(n−2)(n≥3,n∈N∗)F(n)=F(n - 1)+F(n - 2) (n ≥ 3, n ∈ N^*)F(n)=F(n−1)+F(n−2)(n≥3,n∈N∗) def fibonacc(n): if n == 1 or n == 2: return 1 else: return fibonacc(n-1) + fibonacc(n-2) 以上方法的时间复杂度为O(2n)O(2^n)O(2n),稍微大一点的数都会算很久,有一个简单的解决方案,使用 lru_cache 缓存装饰器,缓存一些中间结果: from functools import lru_cache# 缓存斐波那契函数已经计算出的结果,最多占用1024字节内存@lru_cache(maxsize=1024)def fibonacc(n): if n == 1 or n == 2: return 1 else: return fibonacc(n-1) + fibonacc(n-2) 另外还有更加节省时间和空间的方法: def fibonacc(n, current=0, next=1): if n == 0: return current else: return fibonacc(n-1, next, current+next) 示例三:汉诺塔问题 汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。64片黄金圆盘移动完毕之日,就是世界毁灭之时。 对于 n 个盘子,移动步骤如下: 把 n-1 个盘子由 A 经过 C 移动到 B 把最后一个盘子移动到 C 把 n-1 个盘子由 B 经过 A 移动到 C 递归代码实现: def hanoi(n, a, b, c): # n 个盘子,a,b,c三个柱子 if n > 0: hanoi(n-1, a, c, b) # 把 n-1 个盘子由 a 经过 c 移动到 b print('moving from {0} to {1}'.format(a, c)) # 把最后一个盘子移动到 c hanoi(n-1, b, a, c) # 把 n-1 个盘子由 b 经过 a 移动到 c 示例: def hanoi(n, a, b, c): if n > 0: hanoi(n-1, a, c, b) print('moving from {0} to {1}'.format(a, c)) hanoi(n-1, b, a, c)hanoi(3, 'A', 'B', 'C') moving from A to Cmoving from A to Bmoving from C to Bmoving from A to Cmoving from B to Amoving from B to Cmoving from A to C 尾递归 如果一个函数中所有递归形式的调用都出现在函数的末尾,我们称这个递归函数是尾递归的。通俗来讲就是递归调用放在了函数的最后。 # 一般递归def func(n): if n > 0: func(n-1) print(n)# 一般递归def func(n): if n > 0: return func(n-1) + n# 尾递归def func(n): a = n if n > 0: a += 1 print(a, n) return func(n-1) 对于普通的递归,每一级递归都产生了新的局部变量,必须创建新的调用栈,随着递归深度的增加,创建的栈越来越多,容易造成爆栈。 def normal_recursion(n): if n == 1: return 1 else: return n + normal_recursion(n-1) normal_recursion(5) 执行: normal_recursion(5)5 + normal_recursion(4)5 + 4 + normal_recursion(3)5 + 4 + 3 + normal_recursion(2)5 + 4 + 3 + 2 + normal_recursion(1)5 + 4 + 3 + 35 + 4 + 65 + 1015 尾递归基于函数的尾调用,每一级调用直接返回递归函数更新调用栈,没有新局部变量的产生,类似迭代的实现。 def tail_recursion(n, total=0): if n == 0: return total else: return tail_recursion(n-1, total+n) normal_recursion(5) 执行: tail_recursion(5, 0)tail_recursion(4, 5)tail_recursion(3, 9)tail_recursion(2, 12)tail_recursion(1, 14)tail_recursion(0, 15)15 在 Python,Java,Pascal 等语言中是无法实现尾递归优化的,所以采用了 for,while,goto 等特殊结构以迭代的方式来代替尾递归。 Python 中尾递归的解决方案 使用普通的递归来实现斐波那契数列的计算,代码段如下: def fibonacc(n, current=0, next=1): if n == 0: return current else: return fibonacc(n-1, next, current+next)a = fibonacc(1000)print(a) 此时会报错,因为超过了最大递归深度(默认深度900-1000左右): Traceback (most recent call last): File "F:/PycharmProjects/algorithm/fibonacc_test.py", line 57, in <module> a = fibonacc(1000) File "F:/PycharmProjects/algorithm/fibonacc_test.py", line 47, in fibonacc return fibonacc(n-1, next, current+next) File "F:/PycharmProjects/algorithm/fibonacc_test.py", line 47, in fibonacc return fibonacc(n-1, next, current+next) File "F:/PycharmProjects/algorithm/fibonacc_test.py", line 47, in fibonacc return fibonacc(n-1, next, current+next) [Previous line repeated 995 more times] File "F:/PycharmProjects/algorithm/fibonacc_test.py", line 44, in fibonacc if n == 0:RecursionError: maximum recursion depth exceeded in comparison 如果是递归深度不是很大的情况,可以手动重设递归深度来解决: import syssys.setrecursionlimit(10000) # 递归深度设置为 10000 如果递归深度非常大,那么就可以采用尾递归优化,但是 Python 官方是并不支持尾递归的(不知道为啥),然而这难不到广大的程序员们,早在 2006 年 Crutcher Dunnavant 就想出了一个解决办法,实现一个 tail_call_optimized 装饰器,原文链接:https://code.activestate.com/recipes/474088/,原代码是 Python 2.4 实现的,用 Python 3.x 实现如下: # This program shows off a python decorator# which implements tail call optimization. It# does this by throwing an exception if it is# it's own grandparent, and catching such# exceptions to recall the stack.import sysclass TailRecurseException(BaseException): def __init__(self, args, kwargs): self.args = args self.kwargs = kwargsdef tail_call_optimized(g): """ This function decorates a function with tail call optimization. It does this by throwing an exception if it is it's own grandparent, and catching such exceptions to fake the tail call optimization. This function fails if the decorated5 function recurses in a non-tail context. """ def func(*args, **kwargs): f = sys._getframe() if f.f_back and f.f_back.f_back and f.f_back.f_back.f_code == f.f_code: raise TailRecurseException(args, kwargs) else: while 1: try: return g(*args, **kwargs) except TailRecurseException as e: args = e.args kwargs = e.kwargs func.__doc__ = g.__doc__ return func 使用该装饰器再来实现比较大的斐波那契数列的计算: @tail_call_optimizeddef fibonacc(n, current=0, next=1): if n == 0: return current else: return fibonacc(n-1, next, current+next)a = fibonacc(1000)print(a) 输出结果: 43466557686937456435688527675040625802564660517371780402481729089536555417949051890403879840079255169295922593080322634775209689623239873322471161642996440906533187938298969649928516003704476137795166849228875 tail_call_optimized 实现尾递归优化的原理:当递归函数被该装饰器修饰后,递归调用在装饰器while循环内部进行,每当产生新的递归调用栈帧时,f.f_back.f_back.f_code == f.f_code: 就捕获当前尾调用函数的参数,并抛出异常,从而销毁递归栈并使用捕获的参数手动调用递归函数,所以递归的过程中始终只存在一个栈帧对象,达到优化的目的。 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 TRHX•鲍勃。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/109322815未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 排序算法分类 一、冒泡排序(Bubble Sort) 1、原理 2、步骤 3、动画演示 4、代码实现 5、具体示例 二、选择排序(Selection Sort) 1、原理 2、步骤 3、动画演示 4、代码实现 5、具体示例 三、插入排序(Insertion Sort) 1、原理 2、步骤 3、动画演示 4、代码实现 5、具体示例 四、希尔排序(Shell Sort) 1、原理 2、步骤 3、动画演示 4、代码实现 5、具体示例 五、归并排序(Merge Sort) 1、原理 2、步骤 3、动画演示 4、代码实现 5、具体示例 六、快速排序(Quick Sort) 1、原理 2、步骤 3、动画演示 4、代码实现 5、具体示例 七、堆排序(Heap Sort) 1、原理 2、步骤 3、动画演示 4、代码实现 5、具体示例 八、计数排序(Counting Sort) 1、原理 2、步骤 3、动画演示 4、代码实现 5、具体示例 九、桶排序(Bucket Sort) 1、原理 2、步骤 3、动画演示 4、代码实现 5、具体示例 十、基数排序(Radix Sort) 1、原理 2、步骤 3、动画演示 4、代码实现 5、具体示例 参考资料:https://www.bilibili.com/video/BV1mp4y1D7UP 本文动图演示来源:https://visualgo.net/ 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/108987300未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 排序算法分类 内部排序:指在排序期间,元素全部存放在内存中的排序,常见的内部排序算法有:冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序、堆排序、基数排序等。 外部排序:指在排序期间,元素无法完全全部同时存放在内存中,必须在排序的过程中根据要求不断地在内、外存之间移动的排序; 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。 非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。 常见的非比较类排序算法有:基数排序、计数排序、桶排序等 一般情况下,内部排序算法在执行过程中都要进行两种操作:比较和移动。通过比较两个关键字的大小,确定对应元素的前后关系,然后通过移动元素以达到有序。但是,并非所有的内部排序算法都要基于比较操作。 每种排序算法都有各自的优缺点,适合在不同的环境下使用,就其全面性能而言,很难提出一种被认为是最好的算法。通常可以将排序算法分为插入排序、交换排序、选择排序、归并排序和基数排序五大类,内部排序算法的性能取决于算法的时间复杂度和空间复杂度,而时间复杂度一般是由比较和移动的次数决定的。 排序算法时间复杂度(平均)时间复杂度(最好)时间复杂度(最坏)空间复杂度稳定性 冒泡排序O(n2)O(n^2)O(n2)O(n)O(n)O(n)O(n2)O(n^2)O(n2)O(1)O(1)O(1)稳定 选择排序O(n2)O(n^2)O(n2)O(n2)O(n^2)O(n2)O(n2)O(n^2)O(n2)O(1)O(1)O(1)不稳定 插入排序O(n2)O(n^2)O(n2)O(n)O(n)O(n)O(n2)O(n^2)O(n2)O(1)O(1)O(1)稳定 希尔排序O(nlogn)O(nlogn)O(nlogn)O(nlog2n)O(nlog^2n)O(nlog2n)O(nlog2n)O(nlog^2n)O(nlog2n)O(1)O(1)O(1)不稳定 归并排序O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(n)O(n)O(n)稳定 快速排序O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(n2)O(n^2)O(n2)O(logn)O(logn)O(logn)不稳定 堆排序O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(nlogn)O(1)O(1)O(1)不稳定 计数排序O(n+k)O(n+k)O(n+k)O(n+k)O(n+k)O(n+k)O(n+k)O(n+k)O(n+k)O(k)O(k)O(k)稳定 桶排序O(n+k)O(n+k)O(n+k)O(n+k)O(n+k)O(n+k)O(n2)O(n^2)O(n2)O(n+k)O(n+k)O(n+k)稳定 基数排序O(n∗k)O(n*k)O(n∗k)O(n∗k)O(n*k)O(n∗k)O(n∗k)O(n*k)O(n∗k)O(n+k)O(n+k)O(n+k)稳定 稳定性:排序后 2 个相等键值的顺序和排序之前它们的顺序是否相同。例:如果 a 原本在 b 前面,且 a=b,排序之后 a 仍然在 b 的前面,则表示具有稳定性。 常见时间复杂度大小比较: O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<...<O(2n)<O(n!)O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) <...< O(2^n)<O (n!)O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<...<O(2n)<O(n!) 一、冒泡排序(Bubble Sort) 1、原理 重复地走访要排序的元素,依次比较两个相邻的元素,如果顺序(如从大到小)错误就把他们交换过来。走访元素的工作是重复地进行,直到没有相邻元素需要交换,也就是说该元素列已经排序完成。冒泡的意思其实就是每一轮冒泡一个最大的元素就会通过不断比较和交换相邻元素使它转移到最右边。 假如有 10 个小盆友从左到右站成一排,个头不等。老师想让他们按照个头从低到高站好,于是他开始喊口号。 每喊一次,从第一个小盆友开始,相邻的小朋友如果身高不是正序就会两两调换,就这样第一轮个头最高的排到了最右边(冒泡到最右边),第二轮依次这么来,从第一个小朋友开始两两交换,这样次高的小盆友又排到了倒数第二个位置。依次类推。 2、步骤 ① 比较相邻的元素。如果第一个比第二个大,就交换它们两个; ② 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数; ③ 针对所有的元素重复步骤 ① ~ ②,除了最后一个元素,直到排序完成。 3、动画演示 4、代码实现 def bubbleSort(arr): for i in range(len(arr)-1): # 循环第 i 趟 for j in range(len(arr)-i-1): # j 为下标 if arr[j] > arr[j+1]: # 如果这个数大于后面的数就交换两者的位置 arr[j], arr[j+1] = arr[j+1], arr[j] return arr 冒泡排序还有一种优化算法,就是立一个 flag,当某一趟序列遍历中元素没有发生交换,则证明该序列已经有序,就不再进行后续的排序。动画演示里就是改进后的算法,改进后的代码如下: def bubbleSort(arr): for i in range(len(arr)-1): # 循环第 i 趟 flag = False for j in range(len(arr)-i-1): # j 为下标 if arr[j] > arr[j+1]: # 如果这个数大于后面的数就交换两者的位置 arr[j], arr[j+1] = arr[j+1], arr[j] flag = True if not flag: return return arr 冒泡排序最快的情况:当输入的数据是正序时;最慢的情况:当输入的数据是反序时。 5、具体示例 未改进版本: def bubble_sort(arr): for i in range(len(arr)-1): # 循环第 i 趟 for j in range(len(arr)-i-1): # j 为下标 if arr[j] > arr[j+1]: # 如果这个数大于后面的数就交换两者的位置 arr[j], arr[j+1] = arr[j+1], arr[j] print(arr) # 每一趟比较完了就打印一次arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]bubble_sort(arr) [3, 38, 5, 44, 15, 36, 26, 27, 2, 46, 4, 19, 47, 48, 50][3, 5, 38, 15, 36, 26, 27, 2, 44, 4, 19, 46, 47, 48, 50][3, 5, 15, 36, 26, 27, 2, 38, 4, 19, 44, 46, 47, 48, 50][3, 5, 15, 26, 27, 2, 36, 4, 19, 38, 44, 46, 47, 48, 50][3, 5, 15, 26, 2, 27, 4, 19, 36, 38, 44, 46, 47, 48, 50][3, 5, 15, 2, 26, 4, 19, 27, 36, 38, 44, 46, 47, 48, 50][3, 5, 2, 15, 4, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50][3, 2, 5, 4, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50][2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50][2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50][2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50][2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50][2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50][2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50] 改进版本: def bubble_sort(arr): for i in range(len(arr)-1): # 循环第 i 趟 flag = False for j in range(len(arr)-i-1): # j 为下标 if arr[j] > arr[j+1]: # 如果这个数大于后面的数就交换两者的位置 arr[j], arr[j+1] = arr[j+1], arr[j] flag = True if not flag: return print(arr) # 每一趟比较完了就打印一次arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]bubble_sort(arr) [3, 38, 5, 44, 15, 36, 26, 27, 2, 46, 4, 19, 47, 48, 50][3, 5, 38, 15, 36, 26, 27, 2, 44, 4, 19, 46, 47, 48, 50][3, 5, 15, 36, 26, 27, 2, 38, 4, 19, 44, 46, 47, 48, 50][3, 5, 15, 26, 27, 2, 36, 4, 19, 38, 44, 46, 47, 48, 50][3, 5, 15, 26, 2, 27, 4, 19, 36, 38, 44, 46, 47, 48, 50][3, 5, 15, 2, 26, 4, 19, 27, 36, 38, 44, 46, 47, 48, 50][3, 5, 2, 15, 4, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50][3, 2, 5, 4, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50][2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50] 二、选择排序(Selection Sort) 1、原理 第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。可以理解为 一个 0 到 n-1 的迭代,每次向后查找选择一个最小的元素。选择排序是不稳定的排序方法。 假如有 10 个小盆友从左到右站成一排,个头不等。老师想让他们按照个头从低到高站好,我们从第一个开始,从头到尾找一个个头最小的小盆友,然后把它和第一个小盆友交换。 然后从第二个小盆友开始采取同样的策略,这样一圈下来小盆友就是有序的了。 2、步骤 ① 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置; ② 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾; ③ 重复步骤 ②,直到所有元素均排序完毕。 3、动画演示 4、代码实现 Python 代码: def selection_sort(arr): for i in range(len(arr)-1): # 循环第 i 趟 min_index = i # 记录最小数的下标 for j in range(i+1, len(arr)): # j 为下标 if arr[j] < arr[min_index]: # 如果这个数小于记录的最小数,则更新最小数的下标 min_index = j arr[i], arr[min_index] = arr[min_index], arr[i] # 将 i 位置的数(已排序序列的末尾的数)和最小数进行交换 return arr 5、具体示例 def selection_sort(arr): for i in range(len(arr)-1): # 循环第 i 趟 min_index = i # 记录最小数的下标 for j in range(i+1, len(arr)): # j 为下标 if arr[j] < arr[min_index]: # 如果这个数小于记录的最小数,则更新最小数的下标 min_index = j arr[i], arr[min_index] = arr[min_index], arr[i] # 将 i 位置的数(已排序序列的末尾的数)和最小数进行交换 print(arr) # 每一趟比较完了就打印一次arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]selection_sort(arr) [2, 44, 38, 5, 47, 15, 36, 26, 27, 3, 46, 4, 19, 50, 48][2, 3, 38, 5, 47, 15, 36, 26, 27, 44, 46, 4, 19, 50, 48][2, 3, 4, 5, 47, 15, 36, 26, 27, 44, 46, 38, 19, 50, 48][2, 3, 4, 5, 47, 15, 36, 26, 27, 44, 46, 38, 19, 50, 48][2, 3, 4, 5, 15, 47, 36, 26, 27, 44, 46, 38, 19, 50, 48][2, 3, 4, 5, 15, 19, 36, 26, 27, 44, 46, 38, 47, 50, 48][2, 3, 4, 5, 15, 19, 26, 36, 27, 44, 46, 38, 47, 50, 48][2, 3, 4, 5, 15, 19, 26, 27, 36, 44, 46, 38, 47, 50, 48][2, 3, 4, 5, 15, 19, 26, 27, 36, 44, 46, 38, 47, 50, 48][2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 46, 44, 47, 50, 48][2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 50, 48][2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 50, 48][2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 50, 48][2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50] 三、插入排序(Insertion Sort) 1、原理 插入排序一般也被称为直接插入排序。对于少量元素的排序,它是一个有效的算法。它的基本思想是将一个记录插入到已经排好序的有序表中,从而形成一个新的有序表。在其实现过程使用双层循环,外层循环对除了第一个元素之外的所有元素进行遍历,内层循环对当前元素前面有序表进行待插入位置查找,并进行移动。 插入排序的工作方式像许多人排序一手扑克牌。开始时,我们的左手为空并且桌子上的牌面向下。然后,我们每次从桌子上拿走一张牌并将它插入左手中正确的位置。为了找到一张牌的正确位置,我们从右到左将它与已在手中的每张牌进行比较。拿在左手上的牌总是排序好的,原来这些牌是桌子上牌堆中顶部的牌。 2、步骤 ① 从第一个元素开始,该元素可以认为已经被排序; ② 取出下一个元素,在已经排序的元素序列中从后向前扫描; ③ 如果该元素(已排序的)大于新元素,将该元素往右移到下一位置,重复该步骤,直到找到已排序的元素小于或者等于新元素的位置; ④ 将新元素插入到步骤 ③ 找到的位置的后面; ⑤ 重复步骤 ② ~ ④。 3、动画演示 4、代码实现 def insertion_sort(arr): for i in range(1, len(arr)): # 将 i 看做摸到的牌的下标 tmp = arr[i] # 将摸到的牌储存到 tmp j = i-1 # 将 j 看做手里的牌的下标 while j >= 0 and arr[j] > tmp: # 如果手里的牌大于摸到的牌 arr[j+1] = arr[j] # 将手里的牌往右移一个位置(将手里的牌赋值给下一个位置) j -= 1 # 将手里的牌的下标减 1,再次准备与摸到的牌进行比较 arr[j+1] = tmp # 将摸到的牌插入到 j+1 位置 return arr 5、具体示例 def insertion_sort(arr): for i in range(1, len(arr)): # 将 i 看做摸到的牌的下标 tmp = arr[i] # 将摸到的牌储存到 tmp j = i-1 # 将 j 看做手里的牌的下标 while j >= 0 and arr[j] > tmp: # 如果手里的牌大于摸到的牌 arr[j+1] = arr[j] # 将手里的牌往右移一个位置(将手里的牌赋值给下一个位置) j -= 1 # 将手里的牌的下标减 1,再次准备与摸到的牌进行比较 arr[j+1] = tmp # 将摸到的牌插入到 j+1 位置 print(arr) # 每一趟比较完了就打印一次arr = [0, 9, 8, 7, 1, 2, 3, 4, 5, 6]insertion_sort(arr) [0, 9, 8, 7, 1, 2, 3, 4, 5, 6] # 手里第一张牌为 0,摸到 9,此时 i=1,j=0,0 比 9 小,将 9 插到索引 j+1=1 处。[0, 8, 9, 7, 1, 2, 3, 4, 5, 6] # 手里的牌为 0,9,摸到 8,此时 i=2,j=1,9 比 8 大,将 9 右移一个位置,j-1=0,将 8 插到 j+1=1 处[0, 7, 8, 9, 1, 2, 3, 4, 5, 6][0, 1, 7, 8, 9, 2, 3, 4, 5, 6][0, 1, 2, 7, 8, 9, 3, 4, 5, 6][0, 1, 2, 3, 7, 8, 9, 4, 5, 6][0, 1, 2, 3, 4, 7, 8, 9, 5, 6][0, 1, 2, 3, 4, 5, 7, 8, 9, 6][0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 四、希尔排序(Shell Sort) 1、原理 希尔排序是插入排序的一种更高效的改进版本,是一种分组插入排序算法,又称缩小增量排序(Diminishing Increment Sort),希尔排序是非稳定排序算法。该方法因 D.L.Shell 于 1959 年提出而得名。 希尔排序是基于插入排序的以下两点性质而提出改进方法的: 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率; 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位; 希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。 2、步骤 ① n 为数组长度,首先取一个整数 d1=n/2,将元素分为 d1 个组,每组相邻量元素之间距离为 d1-1,在各组内进行直接插入排序; ② 取第二个整数 d2=d1/2,重复步骤 ① 分组排序过程,直到 di=1,即所有元素在同一组内进行直接插入排序。 PS:希尔排序每趟并不使某些元素有序,而是使整体数据越来越接近有序;最后一趟排序使得所有数据有序。 3、动画演示 4、代码实现 def insertion_sort_gap(arr, gap): # 将 gap 看做隔 gap 个距离摸一张牌,而不是依次按照顺序摸牌 for i in range(gap, len(arr)): # 将 i 看做摸到的牌的下标 tmp = arr[i] # 将摸到的牌储存到 tmp j = i-gap # 将 j 看做手里的牌的下标 while j >= 0 and arr[j] > tmp: # 如果手里的牌大于摸到的牌 arr[j+gap] = arr[j] # 将手里的牌往右移一个位置(将手里的牌赋值给下一个位置) j -= gap # 将手里的牌的下标减 gap,再次准备与摸到的牌进行比较 arr[j+gap] = tmp # 将摸到的牌插入到 j+gap 位置def shell_sort(arr): d = len(arr) // 2 # 第一次分组 while d >= 1: insertion_sort_gap(arr, d) # 调用插入排序 d //= 2 # 整除 2 后再次分组 return arr 也可以不使用两个函数,写在一起即可: def shell_sort(arr): d = len(arr) // 2 # 第一次分组 while d >= 1: # 将 d 看做隔 d 个距离摸一张牌,而不是依次按照顺序摸牌 for i in range(d, len(arr)): # 将 i 看做摸到的牌的下标 tmp = arr[i] # 将摸到的牌储存到 tmp j = i - d # 将 j 看做手里的牌的下标 while j >= 0 and arr[j] > tmp: # 如果手里的牌大于摸到的牌 arr[j + d] = arr[j] # 将手里的牌往右移一个位置(将手里的牌赋值给下一个位置) j -= d # 将手里的牌的下标减 d,再次准备与摸到的牌进行比较 arr[j + d] = tmp # 将摸到的牌插入到 j+d 位置 d //= 2 # 整除 2 后再次分组 return arr 5、具体示例 def insertion_sort_gap(arr, gap): # 将 gap 看做隔 gap 个距离摸一张牌,而不是依次按照顺序摸牌 for i in range(gap, len(arr)): # 将 i 看做摸到的牌的下标 tmp = arr[i] # 将摸到的牌储存到 tmp j = i-gap # 将 j 看做手里的牌的下标 while j >= 0 and arr[j] > tmp: # 如果手里的牌大于摸到的牌 arr[j+gap] = arr[j] # 将手里的牌往右移一个位置(将手里的牌赋值给下一个位置) j -= gap # 将手里的牌的下标减 gap,再次准备与摸到的牌进行比较 arr[j+gap] = tmp # 将摸到的牌插入到 j+gap 位置def shell_sort(arr): d = len(arr) // 2 # 第一次分组 while d >= 1: insertion_sort_gap(arr, d) # 调用插入排序 print(arr) # 每一轮排序后打印一次 d //= 2 # 整除 2 后再次分组arr = [5, 7, 4, 6, 3, 1, 2, 9, 8]shell_sort(arr) [3, 1, 2, 6, 5, 7, 4, 9, 8][2, 1, 3, 6, 4, 7, 5, 9, 8][1, 2, 3, 4, 5, 6, 7, 8, 9] def shell_sort(arr): d = len(arr) // 2 # 第一次分组 while d >= 1: # 将 d 看做隔 d 个距离摸一张牌,而不是依次按照顺序摸牌 for i in range(d, len(arr)): # 将 i 看做摸到的牌的下标 tmp = arr[i] # 将摸到的牌储存到 tmp j = i - d # 将 j 看做手里的牌的下标 while j >= 0 and arr[j] > tmp: # 如果手里的牌大于摸到的牌 arr[j + d] = arr[j] # 将手里的牌往右移一个位置(将手里的牌赋值给下一个位置) j -= d # 将手里的牌的下标减 d,再次准备与摸到的牌进行比较 arr[j + d] = tmp # 将摸到的牌插入到 j+d 位置 print(arr) # 每一轮排序后打印一次 d //= 2 # 整除 2 后再次分组arr = [5, 7, 4, 6, 3, 1, 2, 9, 8]shell_sort(arr) [3, 1, 2, 6, 5, 7, 4, 9, 8][2, 1, 3, 6, 4, 7, 5, 9, 8][1, 2, 3, 4, 5, 6, 7, 8, 9] 五、归并排序(Merge Sort) 1、原理 归并的概念:假设一个列表分为两段,其中每一段都是有序列表,现在将该两段合并为一个有序列表,这种操作称为一次归并。 归并排序是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。 2、步骤 归并的基本步骤: ① 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列; ② 设定两个指针,最初位置分别为两个已经排序序列的起始位置; ③ 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置; ④ 重复步骤 ③ 直到某一指针达到序列尾; ⑤ 将另一序列剩下的所有元素直接复制到合并序列尾。 归并排序的步骤: ① 分解:将列表越分越小,直至分成一个元素,终止条件:一个元素是有序的。 ② 合并:不断将两个有序列表进行归并,列表越来越大,直到所有序列归并完毕。 3、动画演示 4、代码实现 def merge(arr, low, mid, high): # low 和 high 为整个数组的第一个和最后一个位置索引,mid 为中间位置索引 # i 和 j 为指针,最初位置分别为两个有序序列的起始位置 # ltmp 用来存放合并后的序列 i = low j = mid+1 ltmp = [] while i <= mid and j <= high: # 只要左右两边都有数 if arr[i] < arr[j]: # 当左边的数小于右边的数 ltmp.append(arr[i]) # 将左边的数存入 ltmp i += 1 # 左边的指针往右移一位 else: # 当右边的数小于左边的数 ltmp.append(arr[j]) # 将右边的数存入 ltmp j += 1 # 右边的指针往右移一位 # 上面的 while 语句执行完后,左边或者右边没有数了 while i <= mid: # 当左边还有数的时候 ltmp.append(arr[i]) # 将左边剩下的数全部存入 ltmp i += 1 while j <= high: # 当右边还有数的时候 ltmp.append(arr[j]) # 将右边剩下的数全部存入 ltmp j += 1 arr[low:high+1] = ltmp # 将排序后的数组写回原数组def merge_sort(arr, low, high): # low 和 high 为整个数组的第一个和最后一个位置索引 if low < high: # 至少有两个元素 mid = (low + high) // 2 merge_sort(arr, low, mid) # 把左边递归分解 merge_sort(arr, mid+1, high) # 把右边递归分解 merge(arr, low, mid, high) # 做归并 5、具体示例 def merge(arr, low, mid, high): # low 和 high 为整个数组的第一个和最后一个位置索引,mid 为中间位置索引 # i 和 j 为指针,最初位置分别为两个有序序列的起始位置 # ltmp 用来存放合并后的序列 i = low j = mid+1 ltmp = [] while i <= mid and j <= high: # 只要左右两边都有数 if arr[i] < arr[j]: # 当左边的数小于右边的数 ltmp.append(arr[i]) # 将左边的数存入 ltmp i += 1 # 左边的指针往右移一位 else: # 当右边的数小于左边的数 ltmp.append(arr[j]) # 将右边的数存入 ltmp j += 1 # 右边的指针往右移一位 # 上面的 while 语句执行完后,左边或者右边没有数了 while i <= mid: # 当左边还有数的时候 ltmp.append(arr[i]) # 将左边剩下的数全部存入 ltmp i += 1 while j <= high: # 当右边还有数的时候 ltmp.append(arr[j]) # 将右边剩下的数全部存入 ltmp j += 1 arr[low:high+1] = ltmp # 将排序后的数组写回原数组def merge_sort(arr, low, high): # low 和 high 为整个数组的第一个和最后一个位置索引 if low < high: # 至少有两个元素 mid = (low + high) // 2 merge_sort(arr, low, mid) # 把左边递归分解 merge_sort(arr, mid+1, high) # 把右边递归分解 merge(arr, low, mid, high) # 做归并 print(arr) # 每一次归并打印一次arr = [7, 1, 3, 2, 6, 9, 4]merge_sort(arr, 0, len(arr)-1) [1, 7, 3, 2, 6, 9, 4][1, 7, 2, 3, 6, 9, 4][1, 2, 3, 7, 6, 9, 4][1, 2, 3, 7, 6, 9, 4][1, 2, 3, 7, 4, 6, 9][1, 2, 3, 4, 6, 7, 9] 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/108987300未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 六、快速排序(Quick Sort) 1、原理 快速排序是对冒泡排序的一种改进。顾名思义快速排序就是快,而且效率高!它是处理大数据最快的排序算法之一了。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。 2、步骤 ① 从数列中挑出一个元素,称为 “基准值”; ② 重新排序数列,所有元素比基准值小的放在基准值的左边,比基准值大的放在基准值的右边(相同的数可以到任一边)。在这个分区退出之后,该基准值就处于数列的中间位置。这个称为分区(partition)操作,也可以称为一次归位操作,归位操作的过程见下动图; ③ 递归地把小于基准值元素的子数列和大于基准值元素的子数列按照步骤 ① ② 排序。 3、动画演示 4、代码实现 def partition(arr, left, right): # 归位操作,left,right 分别为数组左边和右边的位置索引 tmp = arr[left] while left < right: while left < right and arr[right] >= tmp: # 从右边找比 tmp 小的数,如果比 tmp 大,则移动指针 right -= 1 # 将指针左移一个位置 arr[left] = arr[right] # 将右边的值写到左边的空位上 while left < right and arr[left] <= tmp: # 从左边找比 tmp 大的数,如果比 tmp 小,则移动指针 left += 1 # 将指针右移一个位置 arr[right] = arr[left] # 将左边的值写到右边的空位上 arr[left] = tmp # 把 tmp 归位 return left # 返回 left,right 都可以,目的是便于后面的递归操作对左右两部分进行排序def quick_sort(arr, left, right): # 快速排序 if left < right: mid = partition(arr, left, right) quick_sort(arr, left, mid-1) # 对左半部分进行归位操作 quick_sort(arr, mid+1, right) # 对右半部分进行归位操作 return arr 5、具体示例 def partition(arr, left, right): # 归位操作,left,right 分别为数组左边和右边的位置索引 tmp = arr[left] while left < right: while left < right and arr[right] >= tmp: # 从右边找比 tmp 小的数,如果比 tmp 大,则移动指针 right -= 1 # 将指针左移一个位置 arr[left] = arr[right] # 将右边的值写到左边的空位上 while left < right and arr[left] <= tmp: # 从左边找比 tmp 大的数,如果比 tmp 小,则移动指针 left += 1 # 将指针右移一个位置 arr[right] = arr[left] # 将左边的值写到右边的空位上 arr[left] = tmp # 把 tmp 归位 return left # 返回 left,right 都可以,目的是便于后面的递归操作对左右两部分进行排序def quick_sort(arr, left, right): if left < right: mid = partition(arr, left, right) print(arr) # 每次归位后打印一次 quick_sort(arr, left, mid-1) # 对左半部分进行归位操作 quick_sort(arr, mid+1, right) # 对右半部分进行归位操作arr = [5, 7, 4, 6, 3, 1, 2, 9, 8]quick_sort(arr, 0, len(arr)-1) [2, 1, 4, 3, 5, 6, 7, 9, 8][1, 2, 4, 3, 5, 6, 7, 9, 8][1, 2, 3, 4, 5, 6, 7, 9, 8][1, 2, 3, 4, 5, 6, 7, 9, 8][1, 2, 3, 4, 5, 6, 7, 9, 8][1, 2, 3, 4, 5, 6, 7, 8, 9] 七、堆排序(Heap Sort) 1、原理 堆排序是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。 堆:一种特殊的完全二叉树结构 大根堆:一棵完全二叉树,满足任一节点都比其孩子节点大 小根堆:一棵完全二叉树,满足任一节点都比其孩子节点小 2、步骤 ① 构建堆:将待排序序列构建成一个堆 H[0……n-1],从最后一个非叶子结点开始,从左至右,从下至上进行调整。根据升序或降序需求选择大顶堆或小顶堆; ② 此时的堆顶元素,为最大或者最小元素; ③ 把堆顶元素和堆尾元素互换,调整堆,重新使堆有序; ④ 此时堆顶元素为第二大元素; ⑤ 重复以上步骤,直到堆变空。 3、动画演示 堆构建完成后再进行推排序: 4、代码实现 def sift(arr, low, high): """ :param li: 列表 :param low: 堆的根节点位置 :param high: 堆的最后一个元素的位置 """ i = low # i最开始指向根节点 j = 2 * i + 1 # j开始是左孩子 tmp = arr[low] # 把堆顶存起来 while j <= high: # 只要j位置有数 if j + 1 <= high and arr[j+1] > arr[j]: # 如果右孩子有并且比较大 j = j + 1 # j指向右孩子 if arr[j] > tmp: arr[i] = arr[j] i = j # 往下看一层 j = 2 * i + 1 else: # tmp更大,把tmp放到i的位置上 arr[i] = tmp # 把tmp放到某一级领导位置上 break else: arr[i] = tmp # 把tmp放到叶子节点上def heap_sort(arr): n = len(arr) for i in range((n-2)//2, -1, -1): # i表示建堆的时候调整的部分的根的下标 sift(arr, i, n-1) # 建堆完成 for i in range(n-1, -1, -1): # i 指向当前堆的最后一个元素 arr[0], arr[i] = arr[i], arr[0] sift(arr, 0, i - 1) # i-1是新的high return arr 5、具体示例 def sift(arr, low, high): """ :param li: 列表 :param low: 堆的根节点位置 :param high: 堆的最后一个元素的位置 """ i = low # i最开始指向根节点 j = 2 * i + 1 # j开始是左孩子 tmp = arr[low] # 把堆顶存起来 while j <= high: # 只要j位置有数 if j + 1 <= high and arr[j+1] > arr[j]: # 如果右孩子有并且比较大 j = j + 1 # j指向右孩子 if arr[j] > tmp: arr[i] = arr[j] i = j # 往下看一层 j = 2 * i + 1 else: # tmp更大,把tmp放到i的位置上 arr[i] = tmp # 把tmp放到某一级领导位置上 break else: arr[i] = tmp # 把tmp放到叶子节点上def heap_sort(arr): n = len(arr) print('建堆过程:') print(arr) for i in range((n-2)//2, -1, -1): # i表示建堆的时候调整的部分的根的下标 sift(arr, i, n-1) print(arr) # 建堆完成 print('堆排序过程:') print(arr) for i in range(n-1, -1, -1): # i 指向当前堆的最后一个元素 arr[0], arr[i] = arr[i], arr[0] sift(arr, 0, i - 1) # i-1是新的high print(arr)arr = [2, 7, 26, 25, 19, 17, 1, 90, 3, 36]heap_sort(arr) 建堆过程:[2, 7, 26, 25, 19, 17, 1, 90, 3, 36][2, 7, 26, 25, 36, 17, 1, 90, 3, 19][2, 7, 26, 90, 36, 17, 1, 25, 3, 19][2, 7, 26, 90, 36, 17, 1, 25, 3, 19][2, 90, 26, 25, 36, 17, 1, 7, 3, 19][90, 36, 26, 25, 19, 17, 1, 7, 3, 2]堆排序过程:[90, 36, 26, 25, 19, 17, 1, 7, 3, 2][36, 25, 26, 7, 19, 17, 1, 2, 3, 90][26, 25, 17, 7, 19, 3, 1, 2, 36, 90][25, 19, 17, 7, 2, 3, 1, 26, 36, 90][19, 7, 17, 1, 2, 3, 25, 26, 36, 90][17, 7, 3, 1, 2, 19, 25, 26, 36, 90][7, 2, 3, 1, 17, 19, 25, 26, 36, 90][3, 2, 1, 7, 17, 19, 25, 26, 36, 90][2, 1, 3, 7, 17, 19, 25, 26, 36, 90][1, 2, 3, 7, 17, 19, 25, 26, 36, 90][1, 2, 3, 7, 17, 19, 25, 26, 36, 90] 八、计数排序(Counting Sort) 1、原理 计数排序是一个非基于比较的排序算法,它的优势在于在对一定范围内的整数排序时,它的复杂度为 Ο(n+k),其中 k 是整数的范围,快于任何比较排序算法。计数排序是一种牺牲空间换取时间的做法。计数排序的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。 2、步骤 ① 找到待排序列表中的最大值 k,开辟一个长度为 k+1 的计数列表,计数列表中的值都为 0。 ② 遍历待排序列表,如果遍历到的元素值为 i,则计数列表中索引 i 的值加1。 ③ 遍历完整个待排序列表,计数列表中索引 i 的值 j 表示 i 的个数为 j,统计出待排序列表中每个值的数量。 ④ 创建一个新列表(也可以清空原列表,在原列表中添加),遍历计数列表,依次在新列表中添加 j 个 i,新列表就是排好序后的列表,整个过程没有比较待排序列表中的数据大小。 3、动画演示 4、代码实现 def count_sort(arr): if len(arr) < 2: # 如果数组长度小于 2 则直接返回 return arr max_num = max(arr) count = [0 for _ in range(max_num+1)] # 开辟一个计数列表 for val in arr: count[val] += 1 arr.clear() # 原数组清空 for ind, val in enumerate(count): # 遍历值和下标(值的数量) for i in range(val): arr.append(ind) return arr 5、具体示例 def count_sort(arr): if len(arr) < 2: # 如果数组长度小于 2 则直接返回 return arr max_num = max(arr) count = [0 for _ in range(max_num+1)] # 开辟一个计数列表 for val in arr: count[val] += 1 arr.clear() # 原数组清空 for ind, val in enumerate(count): # 遍历值和下标(值的数量) for i in range(val): arr.append(ind) return arrarr = [2, 3, 8, 7, 1, 2, 2, 2, 7, 3, 9, 8, 2, 1, 4, 2, 4, 6, 9, 2]sorted_arr = count_sort(arr)print(sorted_arr) [1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4, 6, 7, 7, 8, 8, 9, 9] 九、桶排序(Bucket Sort) 1、原理 桶排序又叫箱排序,工作的原理是将数组分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序)。桶排序是鸽巢排序的一种归纳结果。 桶排序也是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。为了使桶排序更加高效,我们需要做到这两点: 在额外空间充足的情况下,尽量增大桶的数量; 使用的映射函数能够将输入的 N 个数据均匀的分配到 K 个桶中。 同时,对于桶中元素的排序,选择何种比较排序算法对于性能的影响至关重要。 最快情况:当输入的数据可以均匀的分配到每一个桶中; 最慢情况:当输入的数据被分配到了同一个桶中。 2、步骤 ① 创建一个定量的数组当作空桶子; ② 遍历序列,把元素一个一个放到对应的桶子去; ③ 对每个不是空的桶子进行排序; ④ 从不是空的桶子里把元素再放回原来的序列中。 3、动画演示 (动图来源于@五分钟学算法,侵删) 4、代码实现 def bucket_sort(arr): max_num = max(arr) n = len(arr) buckets = [[] for _ in range(n)] # 创建桶 for var in arr: i = min(var // (max_num // n), n-1) # i 表示 var 放到几号桶里 buckets[i].append(var) # 把 var 加到桶里边 # 保持桶内的顺序 for j in range(len(buckets[i])-1, 0, -1): if buckets[i][j] < buckets[i][j-1]: buckets[i][j], buckets[i][j-1] = buckets[i][j-1], buckets[i][j] else: break sorted_arr = [] for buc in buckets: sorted_arr.extend(buc) return sorted_arr 5、具体示例 def bucket_sort(arr): max_num = max(arr) n = len(arr) buckets = [[] for _ in range(n)] # 创建桶 for var in arr: i = min(var // (max_num // n), n-1) # i 表示 var 放到几号桶里 buckets[i].append(var) # 把 var 加到桶里边 # 保持桶内的顺序 for j in range(len(buckets[i])-1, 0, -1): if buckets[i][j] < buckets[i][j-1]: buckets[i][j], buckets[i][j-1] = buckets[i][j-1], buckets[i][j] else: break sorted_arr = [] for buc in buckets: sorted_arr.extend(buc) return sorted_arrarr = [7, 12, 56, 23, 19, 33, 35, 42, 42, 2, 8, 22, 39, 26, 17]sorted_arr = bucket_sort(arr)print(sorted_arr) [2, 7, 8, 12, 17, 19, 22, 23, 26, 33, 35, 39, 42, 42, 56] 十、基数排序(Radix Sort) 1、原理 基数排序属于分配式排序,是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。 基数排序、计数排序、桶排序三种排序算法都利用了桶的概念,但对桶的使用方法上是有明显差异的: 基数排序:根据键值的每位数字来分配桶; 计数排序:每个桶只存储单一键值; 桶排序:每个桶存储一定范围的数值。 2、步骤 ① 取数组中的最大数,并取得位数; ② 从最低位开始,依次进行一次排序; ③ 从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。 3、动画演示 4、代码实现 def radix_sort(li): max_num = max(li) # 最大值 9->1次循环, 99->2次循环, 888->3次循环, 10000->5次循环 it = 0 while 10 ** it <= max_num: buckets = [[] for _ in range(10)] for var in li: # var=987, it=1, 987//10->98, 98%10->8; it=2, 987//100->9, 9%10=9 digit = (var // 10 ** it) % 10 # 依次取一位数 buckets[digit].append(var) # 分桶完成 li.clear() for buc in buckets: li.extend(buc) it += 1 # 把数重新写回 li return arr 5、具体示例 def radix_sort(li): max_num = max(li) # 最大值 9->1次循环, 99->2次循环, 888->3次循环, 10000->5次循环 it = 0 while 10 ** it <= max_num: buckets = [[] for _ in range(10)] for var in li: # var=987, it=1, 987//10->98, 98%10->8; it=2, 987//100->9, 9%10=9 digit = (var // 10 ** it) % 10 # 依次取一位数 buckets[digit].append(var) # 分桶完成 li.clear() for buc in buckets: li.extend(buc) it += 1 # 把数重新写回 li return arrarr = [3221, 1, 10, 9680, 577, 9420, 7, 5622, 4793, 2030, 3138, 82, 2599, 743, 4127]sorted_arr = radix_sort(arr)print(sorted_arr) [1, 7, 10, 82, 577, 743, 2030, 2599, 3138, 3221, 4127, 4793, 5622, 9420, 9680] 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/108987300未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
欢迎加入爬虫逆向微信交流群:添加微信 IT-BOB(备注交流群) 文章目录 【1x00】前言 【2x00】思维导图 【3x00】数据结构分析 【4x00】主函数 main() 【5x00】数据获取模块 data_get 【5x01】初始化函数 init() 【5x02】中国总数据 china_total_data() 【5x03】全球总数据 global_total_data() 【5x04】中国每日数据 china_daily_data() 【5x05】境外每日数据 foreign_daily_data() 【6x00】词云图绘制模块 data_wordcloud 【6x01】中国累计确诊词云图 foreign_daily_data() 【6x02】全球累计确诊词云图 foreign_daily_data() 【7x00】地图绘制模块 data_map 【7x01】中国累计确诊地图 china_total_map() 【7x02】全球累计确诊地图 global_total_map() 【7x03】中国每日数据折线图 china_daily_map() 【7x04】境外每日数据折线图 foreign_daily_map() 【8x00】结果截图 【8x01】数据储存 Excel 【8x02】词云图 【8x03】地图 + 折线图 【9x00】完整代码 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/107140534未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【1x00】前言 本来两三个月之前就想搞个疫情数据实时数据展示的,由于各种不可抗拒因素一而再再而三的鸽了,最近终于抽空写了一个,数据是用 Python 爬取的百度疫情实时大数据报告,请求库用的 requests,解析用的 Xpath 语法,词云用的 wordcloud 库,数据可视化用 pyecharts 绘制的地图和折线图,数据储存在 Excel 表格里面,使用 openpyxl 对表格进行处理。 本程序实现了累计确诊地图展示和每日数据变化折线图展示,其他更多数据的获取和展示均可在程序中进行拓展,可以将程序部署在服务器上,设置定时运行,即可实时展示数据,pyecharts 绘图模块也可以整合到 Web 框架(Django、Flask等)中使用。 在获取数据时有全球和境外两个概念,全球包含中国,境外不包含中国,后期绘制的四个图:中国累计确诊地图、全球累计确诊地图(包含中国)、中国每日数据折线图、境外每日数据折线图(不包含中国)。 注意项:直接向该网页发送请求获取的响应中,没有每个国家的每日数据,该数据获取的地址是:https://voice.baidu.com/newpneumonia/get?target=trend&isCaseIn=1&stage=publish 预览地址:http://cov.itrhx.com/(已失效) 数据来源:https://voice.baidu.com/act/newpneumonia/newpneumonia/ pyecharts 文档:https://pyecharts.org/ openpyxl 文档:https://openpyxl.readthedocs.io/ wordcloud 文档:http://amueller.github.io/word_cloud/ 【2x00】思维导图 【3x00】数据结构分析 通过查看百度的疫情数据页面,可以看到很多整齐的数据,猜测就是疫情相关的数据,保存该页面,对其进行格式化,很容易可以分析出所有的数据都在 <script type="application/json" id="captain-config"></script> 里面,其中 title 里面是一些 Unicode 编码,将其转为中文后更容易得到不同的分类数据。 由于数据繁多,可以将数据主体部分提取出来,删除一些重复项和其他杂项,留下数据大体位置并分析数据结构,便于后期的数据提取,经过处理后的数据大致结构如下: <script type="application/json" id="captain-config"> { "component": [ { "mapLastUpdatedTime": "2020.07.05 16:13", // 国内疫情数据最后更新时间 "caseList": [ // caseList 列表,每一个元素是一个字典 { "confirmed": "1", // 每个字典包含中国每个省的每一项疫情数据 "died": "0", "crued": "1", "relativeTime": "1593792000", "confirmedRelative": "0", "diedRelative": "0", "curedRelative": "0", "curConfirm": "0", "curConfirmRelative": "0", "icuDisable": "1", "area": "西藏", "subList": [ // subList 列表,每一个元素是一个字典 { "city": "拉萨", // 每个字典包含该省份对应的每个城市疫情数据 "confirmed": "1", "died": "0", "crued": "1", "confirmedRelative": "0", "curConfirm": "0", "cityCode": "100" } ] } ], "caseOutsideList": [ // caseOutsideList 列表,每一个元素是一个字典 { "confirmed": "241419", // 每个字典包含各国的每一项疫情数据 "died": "34854", "crued": "191944", "relativeTime": "1593792000", "confirmedRelative": "223", "curConfirm": "14621", "icuDisable": "1", "area": "意大利", "subList": [ // subList 列表,每一个元素是一个字典 { "city": "伦巴第", // 每个字典包含每个国家对应的每个城市疫情数据 "confirmed": "94318", "died": "16691", "crued": "68201", "curConfirm": "9426" } ] } ], "summaryDataIn": { // summaryDataIn 国内总的疫情数据 "confirmed": "85307", "died": "4648", "cured": "80144", "asymptomatic": "99", "asymptomaticRelative": "7", "unconfirmed": "7", "relativeTime": "1593792000", "confirmedRelative": "19", "unconfirmedRelative": "1", "curedRelative": "27", "diedRelative": "0", "icu": "6", "icuRelative": "0", "overseasInput": "1931", "unOverseasInputCumulative": "83375", "overseasInputRelative": "6", "unOverseasInputNewAdd": "13", "curConfirm": "515", "curConfirmRelative": "-8", "icuDisable": "1" }, "summaryDataOut": { // summaryDataOut 国外总的疫情数据 "confirmed": "11302569", "died": "528977", "curConfirm": "4410601", "cured": "6362991", "confirmedRelative": "206165", "curedRelative": "190018", "diedRelative": "4876", "curConfirmRelative": "11271", "relativeTime": "1593792000" }, "trend": { // trend 字典,包含国内每日的疫情数据 "updateDate": [], // 日期 "list": [ // list 列表,每项数据及其对应的值 { "name": "确诊", "data": [] }, { "name": "疑似", "data": [] }, { "name": "治愈", "data": [] }, { "name": "死亡", "data": [] }, { "name": "新增确诊", "data": [] }, { "name": "新增疑似", "data": [] }, { "name": "新增治愈", "data": [] }, { "name": "新增死亡", "data": [] }, { "name": "累计境外输入", "data": [] }, { "name": "新增境外输入", "data": [] } ] }, "foreignLastUpdatedTime": "2020.07.05 16:13", // 国外疫情数据最后更新时间 "globalList": [ // globalList 列表,每一个元素是一个字典 { "area": "亚洲", // 按照不同洲进行分类 "subList": [ // subList 列表,每个洲各个国家的疫情数据 { "died": "52", "confirmed": "6159", "crued": "4809", "curConfirm": "1298", "confirmedRelative": "0", "relativeTime": "1593792000", "country": "塔吉克斯坦" } ], "died": "56556", // 每个洲总的疫情数据 "crued": "1625562", "confirmed": "2447873", "curConfirm": "765755", "confirmedRelative": "60574" }, { "area": "其他", // 其他特殊区域疫情数据 "subList": [ { "died": "13", "confirmed": "712", "crued": "651", "curConfirm": "48", "confirmedRelative": "0", "relativeTime": "1593792000", "country": "钻石公主号邮轮" } ], "died": "13", // 其他特殊区域疫情总的数据 "crued": "651", "confirmed": "712", "curConfirm": "48", "confirmedRelative": "0" }, { "area": "热门", // 热门国家疫情数据 "subList": [ { "died": "5206", "confirmed": "204610", "crued": "179492", "curConfirm": "19912", "confirmedRelative": "1172", "relativeTime": "1593792000", "country": "土耳其" } ], "died": "528967", // 热门国家疫情总的数据 "crued": "6362924", "confirmed": "11302357", "confirmedRelative": "216478", "curConfirm": "4410466" }], "allForeignTrend": { // allForeignTrend 字典,包含国外每日的疫情数据 "updateDate": [], // 日期 "list": [ // list 列表,每项数据及其对应的值 { "name": "累计确诊", "data": [] }, { "name": "治愈", "data": [] }, { "name": "死亡", "data": [] }, { "name": "现有确诊", "data": [] }, { "name": "新增确诊", "data": [] } ] }, "topAddCountry": [ // 确诊增量最高的国家 { "name": "美国", "value": 53162 } ], "topOverseasInput": [ // 境外输入最多的省份 { "name": "黑龙江", "value": 386 } ] } ] }</script> 【4x00】主函数 main() 分别将数据获取、词云图绘制、地图绘制写入三个文件:data_get()、data_wordcloud()、data_map(),然后使用一个主函数文件 main.py 来调用这三个文件里面的函数。 import data_getimport data_wordcloudimport data_mapdata_dict = data_get.init()data_get.china_total_data(data_dict)data_get.global_total_data(data_dict)data_get.china_daily_data(data_dict)data_get.foreign_daily_data(data_dict)data_wordcloud.china_wordcloud()data_wordcloud.global_wordcloud()data_map.all_map() 【5x00】数据获取模块 data_get 【5x01】初始化函数 init() 使用 xpath 语法 //script[@id="captain-config"]/text() 提取里面的值,利用 json.loads 方法将其转换为字典对象,以便后续的其他函数调用。 def init(): headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.13 Safari/537.36' } url = 'https://voice.baidu.com/act/newpneumonia/newpneumonia/' response = requests.get(url=url, headers=headers) tree = etree.HTML(response.text) dict1 = tree.xpath('//script[@id="captain-config"]/text()') print(type(dict1[0])) dict2 = json.loads(dict1[0]) return dict2 【5x02】中国总数据 china_total_data() def china_total_data(data): """ 1、中国省/直辖市/自治区/行政区疫情数据 省/直辖市/自治区/行政区:area 现有确诊: curConfirm 累计确诊: confirmed 累计治愈: crued 累计死亡: died 现有确诊增量: curConfirmRelative 累计确诊增量: confirmedRelative 累计治愈增量: curedRelative 累计死亡增量: diedRelative """ wb = openpyxl.Workbook() # 创建工作簿 ws_china = wb.active # 获取工作表 ws_china.title = "中国省份疫情数据" # 命名工作表 ws_china.append(['省/直辖市/自治区/行政区', '现有确诊', '累计确诊', '累计治愈', '累计死亡', '现有确诊增量', '累计确诊增量', '累计治愈增量', '累计死亡增量']) china = data['component'][0]['caseList'] for province in china: ws_china.append([province['area'], province['curConfirm'], province['confirmed'], province['crued'], province['died'], province['curConfirmRelative'], province['confirmedRelative'], province['curedRelative'], province['diedRelative']]) """ 2、中国城市疫情数据 城市:city 现有确诊:curConfirm 累计确诊:confirmed 累计治愈:crued 累计死亡:died 累计确诊增量:confirmedRelative """ ws_city = wb.create_sheet('中国城市疫情数据') ws_city.append(['城市', '现有确诊', '累计确诊', '累计治愈', '累计死亡', '累计确诊增量']) for province in china: for city in province['subList']: # 某些城市没有 curConfirm 数据,则将其设置为 0,crued 和 died 为空时,替换成 0 if 'curConfirm' not in city: city['curConfirm'] = '0' if city['crued'] == '': city['crued'] = '0' if city['died'] == '': city['died'] = '0' ws_city.append([city['city'], '0', city['confirmed'], city['crued'], city['died'], city['confirmedRelative']]) """ 3、中国疫情数据更新时间:mapLastUpdatedTime """ time_domestic = data['component'][0]['mapLastUpdatedTime'] ws_time = wb.create_sheet('中国疫情数据更新时间') ws_time.column_dimensions['A'].width = 22 # 调整列宽 ws_time.append(['中国疫情数据更新时间']) ws_time.append([time_domestic]) wb.save('COVID-19-China.xlsx') print('中国疫情数据已保存至 COVID-19-China.xlsx!') 【5x03】全球总数据 global_total_data() 全球总数据在提取完成后,进行地图绘制时发现并没有中国的数据,因此在写入全球数据时注意要单独将中国的数据插入 Excel 中。 def global_total_data(data): """ 1、全球各国疫情数据 国家:country 现有确诊:curConfirm 累计确诊:confirmed 累计治愈:crued 累计死亡:died 累计确诊增量:confirmedRelative """ wb = openpyxl.Workbook() ws_global = wb.active ws_global.title = "全球各国疫情数据" # 按照国家保存数据 countries = data['component'][0]['caseOutsideList'] ws_global.append(['国家', '现有确诊', '累计确诊', '累计治愈', '累计死亡', '累计确诊增量']) for country in countries: ws_global.append([country['area'], country['curConfirm'], country['confirmed'], country['crued'], country['died'], country['confirmedRelative']]) # 按照洲保存数据 continent = data['component'][0]['globalList'] for area in continent: ws_foreign = wb.create_sheet(area['area'] + '疫情数据') ws_foreign.append(['国家', '现有确诊', '累计确诊', '累计治愈', '累计死亡', '累计确诊增量']) for country in area['subList']: ws_foreign.append([country['country'], country['curConfirm'], country['confirmed'], country['crued'], country['died'], country['confirmedRelative']]) # 在“全球各国疫情数据”和“亚洲疫情数据”两张表中写入中国疫情数据 ws1, ws2 = wb['全球各国疫情数据'], wb['亚洲疫情数据'] original_data = data['component'][0]['summaryDataIn'] add_china_data = ['中国', original_data['curConfirm'], original_data['confirmed'], original_data['cured'], original_data['died'], original_data['confirmedRelative']] ws1.append(add_china_data) ws2.append(add_china_data) """ 2、全球疫情数据更新时间:foreignLastUpdatedTime """ time_foreign = data['component'][0]['foreignLastUpdatedTime'] ws_time = wb.create_sheet('全球疫情数据更新时间') ws_time.column_dimensions['A'].width = 22 # 调整列宽 ws_time.append(['全球疫情数据更新时间']) ws_time.append([time_foreign]) wb.save('COVID-19-Global.xlsx') print('全球疫情数据已保存至 COVID-19-Global.xlsx!') 【5x04】中国每日数据 china_daily_data() def china_daily_data(data): """ i_dict = data['component'][0]['trend'] i_dict['updateDate']:日期 i_dict['list'][0]:确诊 i_dict['list'][1]:疑似 i_dict['list'][2]:治愈 i_dict['list'][3]:死亡 i_dict['list'][4]:新增确诊 i_dict['list'][5]:新增疑似 i_dict['list'][6]:新增治愈 i_dict['list'][7]:新增死亡 i_dict['list'][8]:累计境外输入 i_dict['list'][9]:新增境外输入 """ ccd_dict = data['component'][0]['trend'] update_date = ccd_dict['updateDate'] # 日期 china_confirmed = ccd_dict['list'][0]['data'] # 每日累计确诊数据 china_crued = ccd_dict['list'][2]['data'] # 每日累计治愈数据 china_died = ccd_dict['list'][3]['data'] # 每日累计死亡数据 wb = openpyxl.load_workbook('COVID-19-China.xlsx') # 写入每日累计确诊数据 ws_china_confirmed = wb.create_sheet('中国每日累计确诊数据') ws_china_confirmed.append(['日期', '数据']) for data in zip(update_date, china_confirmed): ws_china_confirmed.append(data) # 写入每日累计治愈数据 ws_china_crued = wb.create_sheet('中国每日累计治愈数据') ws_china_crued.append(['日期', '数据']) for data in zip(update_date, china_crued): ws_china_crued.append(data) # 写入每日累计死亡数据 ws_china_died = wb.create_sheet('中国每日累计死亡数据') ws_china_died.append(['日期', '数据']) for data in zip(update_date, china_died): ws_china_died.append(data) wb.save('COVID-19-China.xlsx') print('中国每日累计确诊/治愈/死亡数据已保存至 COVID-19-China.xlsx!') 【5x05】境外每日数据 foreign_daily_data() def foreign_daily_data(data): """ te_dict = data['component'][0]['allForeignTrend'] te_dict['updateDate']:日期 te_dict['list'][0]:累计确诊 te_dict['list'][1]:治愈 te_dict['list'][2]:死亡 te_dict['list'][3]:现有确诊 te_dict['list'][4]:新增确诊 """ te_dict = data['component'][0]['allForeignTrend'] update_date = te_dict['updateDate'] # 日期 foreign_confirmed = te_dict['list'][0]['data'] # 每日累计确诊数据 foreign_crued = te_dict['list'][1]['data'] # 每日累计治愈数据 foreign_died = te_dict['list'][2]['data'] # 每日累计死亡数据 wb = openpyxl.load_workbook('COVID-19-Global.xlsx') # 写入每日累计确诊数据 ws_foreign_confirmed = wb.create_sheet('境外每日累计确诊数据') ws_foreign_confirmed.append(['日期', '数据']) for data in zip(update_date, foreign_confirmed): ws_foreign_confirmed.append(data) # 写入累计治愈数据 ws_foreign_crued = wb.create_sheet('境外每日累计治愈数据') ws_foreign_crued.append(['日期', '数据']) for data in zip(update_date, foreign_crued): ws_foreign_crued.append(data) # 写入累计死亡数据 ws_foreign_died = wb.create_sheet('境外每日累计死亡数据') ws_foreign_died.append(['日期', '数据']) for data in zip(update_date, foreign_died): ws_foreign_died.append(data) wb.save('COVID-19-Global.xlsx') print('境外每日累计确诊/治愈/死亡数据已保存至 COVID-19-Global.xlsx!') 【6x00】词云图绘制模块 data_wordcloud 【6x01】中国累计确诊词云图 foreign_daily_data() def china_wordcloud(): wb = openpyxl.load_workbook('COVID-19-China.xlsx') # 获取已有的xlsx文件 ws_china = wb['中国省份疫情数据'] # 获取中国省份疫情数据表 ws_china.delete_rows(1) # 删除第一行 china_dict = {} # 将省份及其累计确诊按照键值对形式储存在字典中 for data in ws_china.values: china_dict[data[0]] = int(data[2]) word_cloud = wordcloud.WordCloud(font_path='C:/Windows/Fonts/simsun.ttc', background_color='#CDC9C9', min_font_size=15, width=900, height=500) word_cloud.generate_from_frequencies(china_dict) word_cloud.to_file('WordCloud-China.png') print('中国省份疫情词云图绘制完毕!') 【6x02】全球累计确诊词云图 foreign_daily_data() def global_wordcloud(): wb = openpyxl.load_workbook('COVID-19-Global.xlsx') ws_global = wb['全球各国疫情数据'] ws_global.delete_rows(1) global_dict = {} for data in ws_global.values: global_dict[data[0]] = int(data[2]) word_cloud = wordcloud.WordCloud(font_path='C:/Windows/Fonts/simsun.ttc', background_color='#CDC9C9', width=900, height=500) word_cloud.generate_from_frequencies(global_dict) word_cloud.to_file('WordCloud-Global.png') print('全球各国疫情词云图绘制完毕!') 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/107140534未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【7x00】地图绘制模块 data_map 【7x01】中国累计确诊地图 china_total_map() def china_total_map(): wb = openpyxl.load_workbook('COVID-19-China.xlsx') # 获取已有的xlsx文件 ws_time = wb['中国疫情数据更新时间'] # 获取文件中中国疫情数据更新时间表 ws_data = wb['中国省份疫情数据'] # 获取文件中中国省份疫情数据表 ws_data.delete_rows(1) # 删除第一行 province = [] # 省份 curconfirm = [] # 累计确诊 for data in ws_data.values: province.append(data[0]) curconfirm.append(data[2]) time_china = ws_time['A2'].value # 更新时间 # 设置分级颜色 pieces = [ {'max': 0, 'min': 0, 'label': '0', 'color': '#FFFFFF'}, {'max': 9, 'min': 1, 'label': '1-9', 'color': '#FFE5DB'}, {'max': 99, 'min': 10, 'label': '10-99', 'color': '#FF9985'}, {'max': 999, 'min': 100, 'label': '100-999', 'color': '#F57567'}, {'max': 9999, 'min': 1000, 'label': '1000-9999', 'color': '#E64546'}, {'max': 99999, 'min': 10000, 'label': '≧10000', 'color': '#B80909'} ] # 绘制地图 ct_map = ( Map() .add(series_name='累计确诊人数', data_pair=[list(z) for z in zip(province, curconfirm)], maptype="china") .set_global_opts( title_opts=opts.TitleOpts(title="中国疫情数据(累计确诊)", subtitle='数据更新至:' + time_china + '\n\n来源:百度疫情实时大数据报告'), visualmap_opts=opts.VisualMapOpts(max_=300, is_piecewise=True, pieces=pieces) ) ) return ct_map 【7x02】全球累计确诊地图 global_total_map() def global_total_map(): wb = openpyxl.load_workbook('COVID-19-Global.xlsx') ws_time = wb['全球疫情数据更新时间'] ws_data = wb['全球各国疫情数据'] ws_data.delete_rows(1) country = [] # 国家 curconfirm = [] # 累计确诊 for data in ws_data.values: country.append(data[0]) curconfirm.append(data[2]) time_global = ws_time['A2'].value # 更新时间 # 国家名称中英文映射表 name_map = { "Somalia": "索马里", "Liechtenstein": "列支敦士登", "Morocco": "摩洛哥", "W. Sahara": "西撒哈拉", "Serbia": "塞尔维亚", "Afghanistan": "阿富汗", "Angola": "安哥拉", "Albania": "阿尔巴尼亚", "Andorra": "安道尔共和国", "United Arab Emirates": "阿拉伯联合酋长国", "Argentina": "阿根廷", "Armenia": "亚美尼亚", "Australia": "澳大利亚", "Austria": "奥地利", "Azerbaijan": "阿塞拜疆", "Burundi": "布隆迪", "Belgium": "比利时", "Benin": "贝宁", "Burkina Faso": "布基纳法索", "Bangladesh": "孟加拉国", "Bulgaria": "保加利亚", "Bahrain": "巴林", "Bahamas": "巴哈马", "Bosnia and Herz.": "波斯尼亚和黑塞哥维那", "Belarus": "白俄罗斯", "Belize": "伯利兹", "Bermuda": "百慕大", "Bolivia": "玻利维亚", "Brazil": "巴西", "Barbados": "巴巴多斯", "Brunei": "文莱", "Bhutan": "不丹", "Botswana": "博茨瓦纳", "Central African Rep.": "中非共和国", "Canada": "加拿大", "Switzerland": "瑞士", "Chile": "智利", "China": "中国", "Côte d'Ivoire": "科特迪瓦", "Cameroon": "喀麦隆", "Dem. Rep. Congo": "刚果(布)", "Congo": "刚果(金)", "Colombia": "哥伦比亚", "Cape Verde": "佛得角", "Costa Rica": "哥斯达黎加", "Cuba": "古巴", "N. Cyprus": "北塞浦路斯", "Cyprus": "塞浦路斯", "Czech Rep.": "捷克", "Germany": "德国", "Djibouti": "吉布提", "Denmark": "丹麦", "Dominican Rep.": "多米尼加", "Algeria": "阿尔及利亚", "Ecuador": "厄瓜多尔", "Egypt": "埃及", "Eritrea": "厄立特里亚", "Spain": "西班牙", "Estonia": "爱沙尼亚", "Ethiopia": "埃塞俄比亚", "Finland": "芬兰", "Fiji": "斐济", "France": "法国", "Gabon": "加蓬", "United Kingdom": "英国", "Georgia": "格鲁吉亚", "Ghana": "加纳", "Guinea": "几内亚", "Gambia": "冈比亚", "Guinea-Bissau": "几内亚比绍", "Eq. Guinea": "赤道几内亚", "Greece": "希腊", "Grenada": "格林纳达", "Greenland": "格陵兰岛", "Guatemala": "危地马拉", "Guam": "关岛", "Guyana": "圭亚那合作共和国", "Honduras": "洪都拉斯", "Croatia": "克罗地亚", "Haiti": "海地", "Hungary": "匈牙利", "Indonesia": "印度尼西亚", "India": "印度", "Br. Indian Ocean Ter.": "英属印度洋领土", "Ireland": "爱尔兰", "Iran": "伊朗", "Iraq": "伊拉克", "Iceland": "冰岛", "Israel": "以色列", "Italy": "意大利", "Jamaica": "牙买加", "Jordan": "约旦", "Japan": "日本", "Siachen Glacier": "锡亚琴冰川", "Kazakhstan": "哈萨克斯坦", "Kenya": "肯尼亚", "Kyrgyzstan": "吉尔吉斯斯坦", "Cambodia": "柬埔寨", "Korea": "韩国", "Kuwait": "科威特", "Lao PDR": "老挝", "Lebanon": "黎巴嫩", "Liberia": "利比里亚", "Libya": "利比亚", "Sri Lanka": "斯里兰卡", "Lesotho": "莱索托", "Lithuania": "立陶宛", "Luxembourg": "卢森堡", "Latvia": "拉脱维亚", "Moldova": "摩尔多瓦", "Madagascar": "马达加斯加", "Mexico": "墨西哥", "Macedonia": "马其顿", "Mali": "马里", "Malta": "马耳他", "Myanmar": "缅甸", "Montenegro": "黑山", "Mongolia": "蒙古国", "Mozambique": "莫桑比克", "Mauritania": "毛里塔尼亚", "Mauritius": "毛里求斯", "Malawi": "马拉维", "Malaysia": "马来西亚", "Namibia": "纳米比亚", "New Caledonia": "新喀里多尼亚", "Niger": "尼日尔", "Nigeria": "尼日利亚", "Nicaragua": "尼加拉瓜", "Netherlands": "荷兰", "Norway": "挪威", "Nepal": "尼泊尔", "New Zealand": "新西兰", "Oman": "阿曼", "Pakistan": "巴基斯坦", "Panama": "巴拿马", "Peru": "秘鲁", "Philippines": "菲律宾", "Papua New Guinea": "巴布亚新几内亚", "Poland": "波兰", "Puerto Rico": "波多黎各", "Dem. Rep. Korea": "朝鲜", "Portugal": "葡萄牙", "Paraguay": "巴拉圭", "Palestine": "巴勒斯坦", "Qatar": "卡塔尔", "Romania": "罗马尼亚", "Russia": "俄罗斯", "Rwanda": "卢旺达", "Saudi Arabia": "沙特阿拉伯", "Sudan": "苏丹", "S. Sudan": "南苏丹", "Senegal": "塞内加尔", "Singapore": "新加坡", "Solomon Is.": "所罗门群岛", "Sierra Leone": "塞拉利昂", "El Salvador": "萨尔瓦多", "Suriname": "苏里南", "Slovakia": "斯洛伐克", "Slovenia": "斯洛文尼亚", "Sweden": "瑞典", "Swaziland": "斯威士兰", "Seychelles": "塞舌尔", "Syria": "叙利亚", "Chad": "乍得", "Togo": "多哥", "Thailand": "泰国", "Tajikistan": "塔吉克斯坦", "Turkmenistan": "土库曼斯坦", "Timor-Leste": "东帝汶", "Tonga": "汤加", "Trinidad and Tobago": "特立尼达和多巴哥", "Tunisia": "突尼斯", "Turkey": "土耳其", "Tanzania": "坦桑尼亚", "Uganda": "乌干达", "Ukraine": "乌克兰", "Uruguay": "乌拉圭", "United States": "美国", "Uzbekistan": "乌兹别克斯坦", "Venezuela": "委内瑞拉", "Vietnam": "越南", "Vanuatu": "瓦努阿图", "Yemen": "也门", "South Africa": "南非", "Zambia": "赞比亚", "Zimbabwe": "津巴布韦", "Aland": "奥兰群岛", "American Samoa": "美属萨摩亚", "Fr. S. Antarctic Lands": "南极洲", "Antigua and Barb.": "安提瓜和巴布达", "Comoros": "科摩罗", "Curaçao": "库拉索岛", "Cayman Is.": "开曼群岛", "Dominica": "多米尼加", "Falkland Is.": "福克兰群岛马尔维纳斯", "Faeroe Is.": "法罗群岛", "Micronesia": "密克罗尼西亚", "Heard I. and McDonald Is.": "赫德岛和麦克唐纳群岛", "Isle of Man": "曼岛", "Jersey": "泽西岛", "Kiribati": "基里巴斯", "Saint Lucia": "圣卢西亚", "N. Mariana Is.": "北马里亚纳群岛", "Montserrat": "蒙特塞拉特", "Niue": "纽埃", "Palau": "帕劳", "Fr. Polynesia": "法属波利尼西亚", "S. Geo. and S. Sandw. Is.": "南乔治亚岛和南桑威奇群岛", "Saint Helena": "圣赫勒拿", "St. Pierre and Miquelon": "圣皮埃尔和密克隆群岛", "São Tomé and Principe": "圣多美和普林西比", "Turks and Caicos Is.": "特克斯和凯科斯群岛", "St. Vin. and Gren.": "圣文森特和格林纳丁斯", "U.S. Virgin Is.": "美属维尔京群岛", "Samoa": "萨摩亚" } pieces = [ {'max': 0, 'min': 0, 'label': '0', 'color': '#FFFFFF'}, {'max': 49, 'min': 1, 'label': '1-49', 'color': '#FFE5DB'}, {'max': 99, 'min': 50, 'label': '50-99', 'color': '#FFC4B3'}, {'max': 999, 'min': 100, 'label': '100-999', 'color': '#FF9985'}, {'max': 9999, 'min': 1000, 'label': '1000-9999', 'color': '#F57567'}, {'max': 99999, 'min': 10000, 'label': '10000-99999', 'color': '#E64546'}, {'max': 999999, 'min': 100000, 'label': '100000-999999', 'color': '#B80909'}, {'max': 9999999, 'min': 1000000, 'label': '≧1000000', 'color': '#8A0808'} ] gt_map = ( Map() .add(series_name='累计确诊人数', data_pair=[list(z) for z in zip(country, curconfirm)], maptype="world", name_map=name_map, is_map_symbol_show=False) .set_series_opts(label_opts=opts.LabelOpts(is_show=False)) .set_global_opts( title_opts=opts.TitleOpts(title="全球疫情数据(累计确诊)", subtitle='数据更新至:' + time_global + '\n\n来源:百度疫情实时大数据报告'), visualmap_opts=opts.VisualMapOpts(max_=300, is_piecewise=True, pieces=pieces), ) ) return gt_map 【7x03】中国每日数据折线图 china_daily_map() def china_daily_map(): wb = openpyxl.load_workbook('COVID-19-China.xlsx') ws_china_confirmed = wb['中国每日累计确诊数据'] ws_china_crued = wb['中国每日累计治愈数据'] ws_china_died = wb['中国每日累计死亡数据'] ws_china_confirmed.delete_rows(1) ws_china_crued.delete_rows(1) ws_china_died.delete_rows(1) x_date = [] # 日期 y_china_confirmed = [] # 每日累计确诊 y_china_crued = [] # 每日累计治愈 y_china_died = [] # 每日累计死亡 for china_confirmed in ws_china_confirmed.values: y_china_confirmed.append(china_confirmed[1]) for china_crued in ws_china_crued.values: x_date.append(china_crued[0]) y_china_crued.append(china_crued[1]) for china_died in ws_china_died.values: y_china_died.append(china_died[1]) fi_map = ( Line(init_opts=opts.InitOpts(height='420px')) .add_xaxis(xaxis_data=x_date) .add_yaxis( series_name="中国累计确诊数据", y_axis=y_china_confirmed, label_opts=opts.LabelOpts(is_show=False), ) .add_yaxis( series_name="中国累计治愈趋势", y_axis=y_china_crued, label_opts=opts.LabelOpts(is_show=False), ) .add_yaxis( series_name="中国累计死亡趋势", y_axis=y_china_died, label_opts=opts.LabelOpts(is_show=False), ) .set_global_opts( title_opts=opts.TitleOpts(title="中国每日累计确诊/治愈/死亡趋势"), legend_opts=opts.LegendOpts(pos_bottom="bottom", orient='horizontal'), tooltip_opts=opts.TooltipOpts(trigger="axis"), yaxis_opts=opts.AxisOpts( type_="value", axistick_opts=opts.AxisTickOpts(is_show=True), splitline_opts=opts.SplitLineOpts(is_show=True), ), xaxis_opts=opts.AxisOpts(type_="category", boundary_gap=False), ) ) return fi_map 【7x04】境外每日数据折线图 foreign_daily_map() def foreign_daily_map(): wb = openpyxl.load_workbook('COVID-19-Global.xlsx') ws_foreign_confirmed = wb['境外每日累计确诊数据'] ws_foreign_crued = wb['境外每日累计治愈数据'] ws_foreign_died = wb['境外每日累计死亡数据'] ws_foreign_confirmed.delete_rows(1) ws_foreign_crued.delete_rows(1) ws_foreign_died.delete_rows(1) x_date = [] # 日期 y_foreign_confirmed = [] # 累计确诊 y_foreign_crued = [] # 累计治愈 y_foreign_died = [] # 累计死亡 for foreign_confirmed in ws_foreign_confirmed.values: y_foreign_confirmed.append(foreign_confirmed[1]) for foreign_crued in ws_foreign_crued.values: x_date.append(foreign_crued[0]) y_foreign_crued.append(foreign_crued[1]) for foreign_died in ws_foreign_died.values: y_foreign_died.append(foreign_died[1]) fte_map = ( Line(init_opts=opts.InitOpts(height='420px')) .add_xaxis(xaxis_data=x_date) .add_yaxis( series_name="境外累计确诊趋势", y_axis=y_foreign_confirmed, label_opts=opts.LabelOpts(is_show=False), ) .add_yaxis( series_name="境外累计治愈趋势", y_axis=y_foreign_crued, label_opts=opts.LabelOpts(is_show=False), ) .add_yaxis( series_name="境外累计死亡趋势", y_axis=y_foreign_died, label_opts=opts.LabelOpts(is_show=False), ) .set_global_opts( title_opts=opts.TitleOpts(title="境外每日累计确诊/治愈/死亡趋势"), legend_opts=opts.LegendOpts(pos_bottom="bottom", orient='horizontal'), tooltip_opts=opts.TooltipOpts(trigger="axis"), yaxis_opts=opts.AxisOpts( type_="value", axistick_opts=opts.AxisTickOpts(is_show=True), splitline_opts=opts.SplitLineOpts(is_show=True), ), xaxis_opts=opts.AxisOpts(type_="category", boundary_gap=False), ) ) return fte_map 【8x00】结果截图 【8x01】数据储存 Excel 【8x02】词云图 【8x03】地图 + 折线图 【9x00】完整代码 预览地址:http://cov.itrhx.com/(已失效) 完整代码地址(点亮 star 有 buff 加成):https://github.com/TRHX/Python3-Spider-Practice 爬虫实战专栏(持续更新):https://itrhx.blog.csdn.net/article/category/9351278 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/107140534未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【01x00】读取数据 【01x01】简单示例 【01x02】header / names 定制列标签 【01x03】index_col 指定列为行索引 【01x04】sep 指定分隔符 【01x05】skiprows 忽略行 【01x06】na_values 设置缺失值 【01x07】nrows / chunksize 行与块 【02x00】写入数据 【02x01】简单示例 【02x02】sep 指定分隔符 【02x03】na_rep 替换缺失值 【02x04】index / header 行与列标签 【02x05】columns 指定列 Pandas 系列文章: Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象 Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作 Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理 Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引 Python 数据分析三剑客之 Pandas(五):统计计算与统计描述 Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并 Python 数据分析三剑客之 Pandas(七):合并数据集 Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换 Python 数据分析三剑客之 Pandas(九):时间序列 Python 数据分析三剑客之 Pandas(十):数据读写 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106963135未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【01x00】读取数据 Pandas 提供了一些用于将表格型数据读取为 DataFrame 对象的函数。常见方法如下: Pandas 官方对 IO 工具的介绍:https://pandas.pydata.org/pandas-docs/stable/user_guide/io.html 函数描述 read_csv从文件、URL、文件型对象中加载带分隔符的数据。默认分隔符为逗号 read_table从文件、URL、文件型对象中加载带分隔符的数据。默认分隔符为制表符('\t') read_fwf读取定宽列格式数据(没有分隔符) read_clipboard读取剪贴板中的数据,可以看做 read_table 的剪贴板版本。在将网页转换为表格时很有用 read_excel从 Excel XLS 或 XLSX file 读取表格数据 read_hdf读取 pandas写的 HDF5 文件 read_html读取 HTML 文档中的所有表格 read_json读取 JSON( JavaScript Object Notation)字符串中的数据 read_msgpack读取二进制格式编码的 pandas 数据(Pandas v1.0.0 中已删除对 msgpack 的支持,建议使用 pyarrow) read_pickle读取 Python pickle 格式中存储的任意对象 read_sas读取存储于 SAS 系统自定义存储格式的 SAS 数据集 read_sql(使用 SQLAlchemy)读取 SQL 查询结果为 pandas 的 DataFrame read_stata读取 Stata 文件格式的数据集 read_feather读取 Feather 二进制格式文件 以下以 read_csv 和 read_table 为例,它们的参数多达 50 多个,具体可参见官方文档: read_csv:https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html read_table:https://pandas.pydata.org/docs/reference/api/pandas.read_table.html 常用参数: 参数描述 path表示文件系统位置、URL、文件型对象的字符串 sep / delimiter用于对行中各字段进行拆分的字符序列或正则表达式 header用作列名的行号,默认为 0(第一行),如果没有 header 行就应该设置为 None index_col用作行索引的列编号或列名。可以是单个名称、数字或由多个名称、数字组成的列表(层次化索引) names用于结果的列名列表,结合 header=None skiprows需要忽略的行数(从文件开始处算起),或需要跳过的行号列表(从0开始) na_values指定一组值,将该组值设置为 NaN(缺失值) comment用于将注释信息从行尾拆分出去的字符(一个或多个) parse_dates尝试将数据解析为日期,默认为 False。如果为 True,则尝试解析所有列。此外,还可以指定需要解析的一组列号或列名。 如果列表的元素为列表或元组,就会将多个列组合到一起再进行日期解析工作(例如,日期、时间分别位于两个列中) keep_date_col如果连接多列解析日期,则保持参与连接的列。默认为 False converters由列号 / 列名跟函数之间的映射关系组成的字典。例如,{'foo': f} 会对 foo 列的所有值应用函数 f dayfirst当解析有歧义的日期时,将其看做国际格式(例如,7/6/2012 —> June 7,2012),默认为 Fase date_parser用于解析日期的函数 nrows需要读取的行数(从文件开始处算起) iterator返回一个 TextParser 以便逐块读取文件 chunksize文件块的大小(用于迭代) skip_footer需要忽略的行数(从文件末尾处算起) verbose打印各种解析器输出信息,比如“非数值列中缺失值的数量”等 encoding用于 unicode 的文本编码格式。例如,“utf-8” 表示用 UTF-8 编码的文本 squeeze如果数据经解析后仅含一列,则返回 Series thousands千分位分隔符,如 , 或 . 【01x01】简单示例 首先创建一个 test1.csv 文件: 使用 read_csv 方法将其读出为一个 DataFrame 对象: >>> import pandas as pd>>> obj = pd.read_csv(r'C:\Users\TanRe\Desktop\test1.csv')>>> obj a b c d message0 1 2 3 4 hello1 5 6 7 8 world2 9 10 11 12 python>>> >>> type(obj)<class 'pandas.core.frame.DataFrame'> 前面的 csv 文件是以逗号分隔的,可以使用 read_table 方法并指定分隔符来读取: >>> import pandas as pd>>> obj = pd.read_table(r'C:\Users\TanRe\Desktop\test1.csv', sep=',')>>> obj a b c d message0 1 2 3 4 hello1 5 6 7 8 world2 9 10 11 12 python 【01x02】header / names 定制列标签 以上示例中第一行为列标签,如果没有单独定义列标签,使用 read_csv 方法也会默认将第一行当作列标签: >>> import pandas as pd>>> obj = pd.read_csv(r'C:\Users\TanRe\Desktop\test2.csv')>>> obj 1 2 3 4 hello0 5 6 7 8 world1 9 10 11 12 python 避免以上情况,可以设置 header=None,Pandas 会为其自动分配列标签: >>> import pandas as pd>>> pd.read_csv(r'C:\Users\TanRe\Desktop\test2.csv', header=None) 0 1 2 3 40 1 2 3 4 hello1 5 6 7 8 world2 9 10 11 12 python 也可以使用 names 参数自定义列标签,传递的是一个列表: >>> import pandas as pd>>> pd.read_csv(r'C:\Users\TanRe\Desktop\test2.csv', names=['a', 'b', 'c', 'd', 'message']) a b c d message0 1 2 3 4 hello1 5 6 7 8 world2 9 10 11 12 python 【01x03】index_col 指定列为行索引 index_col 参数可以指定某一列作为 DataFrame 的行索引,传递的参数是列名称,在以下示例中,会将列名为 message 的列作为 DataFrame 的行索引: >>> pd.read_csv(r'C:\Users\TanRe\Desktop\test2.csv', names=['a', 'b', 'c', 'd', 'message'], index_col='message') a b c dmessage hello 1 2 3 4world 5 6 7 8python 9 10 11 12 如果需要构造多层索引的 DataFrame 对象,则只需传入由列编号或列名组成的列表即可: >>> import pandas as pd>>> pd.read_csv(r'C:\Users\TanRe\Desktop\test3.csv', index_col=['key1', 'key2']) value1 value2key1 key2 one a 1 2 b 3 4 c 5 6 d 7 8two a 9 10 b 11 12 c 13 14 d 15 16 【01x04】sep 指定分隔符 在 read_table 中,sep 参数用于接收分隔符,如果遇到不是用固定的分隔符去分隔字段的,也可以传递一个正则表达式作为 read_table 的分隔符,如下面的 txt 文件数据之间是由不同的空白字符间隔开的: >>> import pandas as pd>>> pd.read_table(r'C:\Users\TanRe\Desktop\test1.txt', sep='\s+') A B Caaa -0.264438 -1.026059 -0.619500bbb 0.927272 0.302904 -0.032399ccc -0.264273 -0.386314 -0.217601ddd -0.871858 -0.348382 1.100491 【01x05】skiprows 忽略行 skiprows参数可用于设置需要忽略的行数,或需要跳过的行号列表,在下面的示例中,读取文件时选择跳过第1、3、4行(索引值分别为0、2、3): >>> import pandas as pd>>> pd.read_csv(r'C:\Users\TanRe\Desktop\test4.csv', skiprows=[0, 2, 3]) a b c d message0 1 2 3 4 hello1 5 6 7 8 world2 9 10 11 12 python 【01x06】na_values 设置缺失值 当文件中出现了空字符串或者 NA 值,Pandas 会将其标记成 NaN(缺失值),同样也可以使用 isnull 方法来判断结果值是否为缺失值: >>> import pandas as pd>>> obj = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv')>>> obj something a b c d message0 one 1 2 3.0 4 NaN1 two 5 6 NaN 8 world2 three 9 10 11.0 12 python>>> >>> pd.isnull(obj) something a b c d message0 False False False False False True1 False False False True False False2 False False False False False False na_values 方法可以传递一组值,将这组值设置为缺失值,如果传递的为字典对象,则字典的各值将被设置为 NaN: >>> import pandas as pd>>> obj1 = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv')>>> obj1 something a b c d message0 one 1 2 3.0 4 NaN1 two 5 6 NaN 8 world2 three 9 10 11.0 12 python>>> >>> obj2 = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv', na_values=['1', '12'])>>> obj2 something a b c d message0 one NaN 2 3.0 4.0 NaN1 two 5.0 6 NaN 8.0 world2 three 9.0 10 11.0 NaN python>>> >>> sentinels = {'message': ['python', 'world'], 'something': ['two']}>>> obj3 = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv', na_values=sentinels)>>> obj3 something a b c d message0 one 1 2 3.0 4 NaN1 NaN 5 6 NaN 8 NaN2 three 9 10 11.0 12 NaN 【01x07】nrows / chunksize 行与块 以下 test6.csv 文件中包含 50 行数据: 可以设置 pd.options.display.max_rows 来紧凑地显示指定行数的数据: >>> import pandas as pd>>> pd.options.display.max_rows = 10>>> pd.read_csv(r'C:\Users\TanRe\Desktop\test6.csv') one two three four key0 0.467976 -0.038649 -0.295344 -1.824726 L1 -0.358893 1.404453 0.704965 -0.200638 B2 -0.501840 0.659254 -0.421691 -0.057688 G3 0.204886 1.074134 1.388361 -0.982404 R4 0.354628 -0.133116 0.283763 -0.837063 Q.. ... ... ... ... ..45 2.311896 -0.417070 -1.409599 -0.515821 L46 -0.479893 -0.633419 0.745152 -0.646038 E47 0.523331 0.787112 0.486066 1.093156 K48 -0.362559 0.598894 -1.843201 0.887292 G49 -0.096376 -1.012999 -0.657431 -0.573315 0[50 rows x 5 columns] 通过 nrows 参数可以读取指定行数: >>> import pandas as pd>>> pd.read_csv(r'C:\Users\TanRe\Desktop\test6.csv', nrows=5) one two three four key0 0.467976 -0.038649 -0.295344 -1.824726 L1 -0.358893 1.404453 0.704965 -0.200638 B2 -0.501840 0.659254 -0.421691 -0.057688 G3 0.204886 1.074134 1.388361 -0.982404 R4 0.354628 -0.133116 0.283763 -0.837063 Q 要逐块读取文件,可以指定 chunksize(行数): >>> import pandas as pd>>> chunker = pd.read_csv(r'C:\Users\TanRe\Desktop\test6.csv', chunksize=50)>>> chunker<pandas.io.parsers.TextFileReader object at 0x07A20D60> 返回的 TextParser 对象,可以根据 chunksize 对文件进行逐块迭代。以下示例中,对 test6.csv 文件数据进行迭代处理,将值计数聚合到 “key” 列中: >>> import pandas as pd>>> chunker = pd.read_csv(r'C:\Users\TanRe\Desktop\test6.csv', chunksize=50)>>> tot = pd.Series([], dtype='float64')>>> for piece in chunker: tot = tot.add(piece['key'].value_counts(), fill_value=0)>>> tot = tot.sort_values(ascending=False)>>> tot[:10]G 6.0E 5.0B 5.0L 5.00 5.0K 4.0A 4.0R 4.0C 2.0Q 2.0dtype: float64 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106963135未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【02x00】写入数据 Pandas 提供了一些用于将表格型数据读取为 DataFrame 对象的函数。常见方法如下: 函数描述 to_csv将对象写入逗号分隔值(csv)文件 to_clipboard将对象复制到系统剪贴板 to_excel将对象写入 Excel 工作表 to_hdf使用 HDFStore 将包含的数据写入 HDF5 文件 to_html将 DataFrame 呈现为 HTML 表格 to_json将对象转换为 JSON( JavaScript Object Notation)字符串 to_msgpack将对象写入二进制格式编码的文件(Pandas v1.0.0 中已删除对 msgpack 的支持,建议使用 pyarrow) to_picklePickle(序列化)对象到文件 to_sql将存储在 DataFrame 中的数据写入 SQL 数据库 to_stata将 DataFrame 对象导出为 Stata 格式 to_feather将 DataFrames 写入 Feather 二进制格式文件 以下以 to_csv 为例,它的参数同样多达 50 多个,具体可参见官方文档: https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_csv.html https://pandas.pydata.org/docs/reference/api/pandas.Series.to_csv.html 【02x01】简单示例 以之前的 test5.csv 文件为例,先读出数据,再将数据写入另外的文件: >>> import pandas as pd>>> data = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv')>>> data something a b c d message0 one 1 2 3.0 4 NaN1 two 5 6 NaN 8 world2 three 9 10 11.0 12 python>>> >>> data.to_csv(r'C:\Users\TanRe\Desktop\out1.csv') 【02x02】sep 指定分隔符 sep 参数可用于其他分隔符: >>> import pandas as pd>>> data = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv')>>> data something a b c d message0 one 1 2 3.0 4 NaN1 two 5 6 NaN 8 world2 three 9 10 11.0 12 python>>>>>> data.to_csv(r'C:\Users\TanRe\Desktop\out2.csv', sep='|') 【02x03】na_rep 替换缺失值 na_rep 参数可将缺失值(NaN)替换成其他字符串: >>> import pandas as pd>>> data = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv')>>> data something a b c d message0 one 1 2 3.0 4 NaN1 two 5 6 NaN 8 world2 three 9 10 11.0 12 python>>> >>> data.to_csv(r'C:\Users\TanRe\Desktop\out3.csv', na_rep='X') 【02x04】index / header 行与列标签 设置 index=False, header=False,可以禁用行标签与列标签: >>> import pandas as pd>>> data = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv')>>> data something a b c d message0 one 1 2 3.0 4 NaN1 two 5 6 NaN 8 world2 three 9 10 11.0 12 python>>> >>> data.to_csv(r'C:\Users\TanRe\Desktop\out4.csv', index=False, header=False) 还可以传入列表来重新设置列标签: >>> import pandas as pd>>> data = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv')>>> data something a b c d message0 one 1 2 3.0 4 NaN1 two 5 6 NaN 8 world2 three 9 10 11.0 12 python>>> >>> data.to_csv(r'C:\Users\TanRe\Desktop\out5.csv', header=['a', 'b', 'c', 'd', 'e', 'f']) 【02x05】columns 指定列 可以通过设置 columns 参数,只写入部分列,并按照指定顺序排序: >>> import pandas as pd>>> data = pd.read_csv(r'C:\Users\TanRe\Desktop\test5.csv')>>> data something a b c d message0 one 1 2 3.0 4 NaN1 two 5 6 NaN 8 world2 three 9 10 11.0 12 python>>>>>> data.to_csv(r'C:\Users\TanRe\Desktop\out6.csv', columns=['c', 'b', 'a']) 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106963135未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【01x00】时间序列 【02x00】Timestamp 时间戳 【02x01】pandas.Timestamp 【02x02】freq 频率部分取值 【02x03】to_datetime 【02x04】date_range 【02x05】索引与切片 【02x06】移动数据与数据偏移 【02x07】时区处理 【03x00】period 固定时期 【03x01】pandas.Period 【03x02】period_range 【03x03】asfreq 时期频率转换 【03x04】to_period 与 to_timestamp() 【04x00】timedelta 时间间隔 【04x01】pandas.Timedelta 【04x02】to_timedelta 【04x03】timedelta_range 【05x00】重采样及频率转换 Pandas 系列文章: Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象 Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作 Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理 Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引 Python 数据分析三剑客之 Pandas(五):统计计算与统计描述 Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并 Python 数据分析三剑客之 Pandas(七):合并数据集 Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换 Python 数据分析三剑客之 Pandas(九):时间序列 Python 数据分析三剑客之 Pandas(十):数据读写 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106947061未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【01x00】时间序列 官网对于时间序列的介绍:https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html 时间序列(time series)是一种重要的结构化数据形式,应用于多个领域,包括金融学、经济学、生态学、神经科学、物理学等。在多个时间点观察或测量到的任何事物都可以形成一段时间序列。很多时间序列是固定频率的,也就是说,数据点是根据某种规律定期出现的(比如每15秒、每5分钟、每月出现一次)。时间序列也可以是不定期的,没有固定的时间单位或单位之间的偏移量。时间序列数据的意义取决于具体的应用场景,主要有以下几种: 时间戳(timestamp),表示某个具体的时间点,例如 2020-6-24 15:30; 固定周期(period),表示某个时间周期,例如 2020-01; 时间间隔(timedelta),持续时间,即两个日期或时间之间的差异。 针对时间戳数据,Pandas 提供了 Timestamp 类型。它本质上是 Python 的原生 datetime 类型的替代品,但是在性能更好的 numpy.datetime64 类型的基础上创建。对应的索引数据结构是 DatetimeIndex。 针对时间周期数据,Pandas 提供了 Period 类型。这是利用 numpy.datetime64 类型将固定频率的时间间隔进行编码。对应的索引数据结构是 PeriodIndex。 针对时间增量或持续时间,Pandas 提供了 Timedelta 类型。Timedelta 是一种代替 Python 原生datetime.timedelta 类型的高性能数据结构,同样是基于 numpy.timedelta64 类型。对应的索引数据结构是 TimedeltaIndex。 【02x00】Timestamp 时间戳 【02x01】pandas.Timestamp 在 pandas 中,pandas.Timestamp 方法用来代替 Python 中的 datetime.datetime 方法。 Timestamp 与 Python 的 Datetime 等效,在大多数情况下都可以互换。 此类型用于组成 DatetimeIndex 以及 Pandas 中其他面向时间序列的数据结构。 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.Timestamp.html 基本语法: class pandas.Timestamp(ts_input=<object object>, freq=None, tz=None, unit=None, year=None, month=None, day=None, hour=None, minute=None, second=None, microsecond=None, nanosecond=None, tzinfo=None) 常用参数: 参数描述 ts_input要转换为时间戳的对象,可以是 datetime-like,str,int,float 类型 freq时间戳将具有的偏移量,可以是 str,日期偏移量类型,取值参见【02x02】freq 频率部分取值 tz时间戳将具有的时区 unit如果 ts_input 是整数或浮点数,该参数用于设置其单位(D、s、ms、us、ns) 简单示例: >>> import pandas as pd>>> pd.Timestamp('2017-01-01T12')Timestamp('2017-01-01 12:00:00') 设置 unit='s',即待转换对象单位为秒: >>> import pandas as pd>>> pd.Timestamp(1513393355.5, unit='s')Timestamp('2017-12-16 03:02:35.500000') 使用 tz 参数设置时区: >>> import pandas as pd>>> pd.Timestamp(1513393355, unit='s', tz='US/Pacific')Timestamp('2017-12-15 19:02:35-0800', tz='US/Pacific') 单独设置年月日: >>> import pandas as pd>>> pd.Timestamp(year=2020, month=6, day=24, hour=12)Timestamp('2020-06-24 12:00:00') 【02x02】freq 频率部分取值 完整取值参见官方文档:https://pandas.pydata.org/docs/user_guide/timeseries.html#timeseries-offset-aliases 参数类型描述 DDay每日历日 BBusinessDay每工作日 HHour每小时 T 或 minMinute每分 SSecond每秒 L 或 msMilli每毫秒(即每千分之一秒) UMicro每微秒(即每百万分之一秒) MMonthEnd每月最后一个日历日 BMBusinessMonthEnd每月最后一个工作日 MSMonthBegin每月第一个日历日 BMSBusinessMonthBegin每月第一个工作日 W-MON、W-TUE…Week从指定的星期几(MON、TUE、 WED、THU、FR、SAT、SUN)开始算起,每周 WoM-1MON、WOM-2MON…WeekOfMonth产生每月第一、第二、第三或第四周的星期几。例如,WoM-3FRI 表示每月第3个星期五 Q-JAN、Q-FEB…QuarterEnd对于以指定月份(JAN、FEB、MAR、APR、MAY、JUN、JUL、AUG、SEP、OCT、NOV、DEC)结束的年度,每季度最后一月的最后个日历日 BQ-JAN、BQ-FEB…BusinessQuarterEnd对于以指定月份结束的年度,每季度最后一月的最后一个工作日 QS-JAN、QS-FEB…QuarterBegin对于以指定月份结束的年度,每季度最后一月的第一个日历日 BQS-JAN、 BQS-FEB…BusinessQuarterBegin对于以指定月份结束的年度,每季度最后一月的第一个工作日 A-JAN、A-FEB…YearEnd每年指定月份(JAN、FEB、MAR、APR、MAY、JUN、JUL、AUG、SEP、 OCT、NOV、DEC)的最后一个日历日 BA-JAN、BA-FEB…BusinessYearEnd每年指定月份的最后一个工作日 AS-JAN、AS-FEB…YearBegin每年指定月份的第一个历日日 BAS-JAN、BAS-FEB…BusinessYearBegin每年指定月份的第一个工作日 【02x03】to_datetime 在 Python 中,datetime 库提供了日期和时间处理方法,利用 str 或 strftime 方法可以将 datetime 对象转化成字符串,具体用法可参见【Python 标准库学习】日期和时间处理库 — datetime。 >>> from datetime import datetime>>> stamp = datetime(2020, 6, 24)>>> stampdatetime.datetime(2020, 6, 24, 0, 0)>>>>>> str(stamp)'2020-06-24 00:00:00'>>> >>> stamp.strftime('%Y-%m-%d')'2020-06-24' 在 pandas 中 to_datetime 方法可以将字符串解析成多种不同的 Timestamp(时间戳) 对象: >>> import pandas as pd>>> datestrs = '2011-07-06 12:00:00'>>> type(datestrs)<class 'str'>>>> >>> pd.to_datetime(datestrs)Timestamp('2011-07-06 12:00:00') 基本语法: pandas.to_datetime(arg, errors='raise', dayfirst=False, yearfirst=False, utc=None, format=None, exact=True, unit=None, infer_datetime_format=False, origin='unix', cache=True) 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.to_datetime.html 常用参数: 参数描述 arg要转换为日期时间的对象,可以接受 int, float, str, datetime, list, tuple, 1-d array, Series DataFrame/dict-like 类型 errors如果字符串不满足时间戳的形式,是否会发生异常 ignore:不引发异常,返回原始输入;raise:无效解析将引发异常(默认);coerce:无效解析将被设置为NaT dayfirstbool 类型,默认 False,如果 arg 是 str 或列表,是否首先解析为日期 例如 dayfirst 为 True,10/11/12 被解析为 2012-11-10,为 False 则解析为 2012-10-11 yearfirstbool 类型,默认 False,如果 arg 是 str 或列表,是否首先解析为年份 例如 dayfirst 为 True,10/11/12 被解析为 2010-11-12,为 False 则解析为 2012-10-11 如果 dayfirst 和 yearfirst 都为 True,则优先 yearfirst utcbool 类型,是否转换为协调世界时,默认 None format格式化时间,如 21/2/20 16:10 使用 %d/%m/%y %H:%M 会被解析为 2020-02-21 16:10:00 符号含义常见文章:【Python 标准库学习】日期和时间处理库 — datetime 或者官方文档 exact如果为 True,则需要精确的格式匹配。如果为 False,则允许格式与目标字符串中的任何位置匹配 unit如果 arg 是整数或浮点数,该参数用于设置其单位(D、s、ms、us、ns) 简单应用: >>> import pandas as pd>>> obj = pd.DataFrame({'year': [2015, 2016], 'month': [2, 3], 'day': [4, 5]})>>> obj year month day0 2015 2 41 2016 3 5>>> >>> pd.to_datetime(obj)0 2015-02-041 2016-03-05dtype: datetime64[ns] 设置 format 和 errors 参数: >>> import pandas as pd>>> pd.to_datetime('13000101', format='%Y%m%d', errors='ignore')datetime.datetime(1300, 1, 1, 0, 0)>>> >>> pd.to_datetime('13000101', format='%Y%m%d', errors='coerce')NaT>>> >>> pd.to_datetime('13000101', format='%Y%m%d', errors='raise')Traceback (most recent call last):...pandas._libs.tslibs.np_datetime.OutOfBoundsDatetime: Out of bounds nanosecond timestamp: 1300-01-01 00:00:00 设置 unit 参数: >>> import pandas as pd>>> pd.to_datetime(1490195805, unit='s')Timestamp('2017-03-22 15:16:45')>>> >>> pd.to_datetime(1490195805433502912, unit='ns')Timestamp('2017-03-22 15:16:45.433502912') 【02x04】date_range pandas.date_range 方法可用于根据指定的频率生成指定长度的 DatetimeIndex。 基本语法: pandas.date_range(start=None, end=None, periods=None, freq=None, tz=None, normalize=False, name=None, closed=None, **kwargs) → pandas.core.indexes.datetimes.DatetimeIndex 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.date_range.html 参数描述 start开始日期 end结束日期 periodsint 类型,要生成的时段数(天) freq频率字符串,即按照某种特定的频率来生成日期,取值参见【02x02】freq 频率部分取值 tz设置时区,例如 “Asia/Hong_Kong” normalizebool 类型,默认 False,是否在生成日期之前对其进行规范化(仅保留年月日) name结果 DatetimeIndex 的名称 closedNone:默认值,同时保留开始日期和结束日期 'left':保留开始日期,不保留结束日期 'right':保留结束日期,不保留开始日期 简单示例: >>> import pandas as pd>>> pd.date_range(start='1/1/2018', end='1/08/2018')DatetimeIndex(['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04', '2018-01-05', '2018-01-06', '2018-01-07', '2018-01-08'], dtype='datetime64[ns]', freq='D') 指定 periods 参数: >>> import pandas as pd>>> pd.date_range(start='2012-04-01', periods=20)DatetimeIndex(['2012-04-01', '2012-04-02', '2012-04-03', '2012-04-04', '2012-04-05', '2012-04-06', '2012-04-07', '2012-04-08', '2012-04-09', '2012-04-10', '2012-04-11', '2012-04-12', '2012-04-13', '2012-04-14', '2012-04-15', '2012-04-16', '2012-04-17', '2012-04-18', '2012-04-19', '2012-04-20'], dtype='datetime64[ns]', freq='D')>>> >>> pd.date_range(end='2012-06-01', periods=20)DatetimeIndex(['2012-05-13', '2012-05-14', '2012-05-15', '2012-05-16', '2012-05-17', '2012-05-18', '2012-05-19', '2012-05-20', '2012-05-21', '2012-05-22', '2012-05-23', '2012-05-24', '2012-05-25', '2012-05-26', '2012-05-27', '2012-05-28', '2012-05-29', '2012-05-30', '2012-05-31', '2012-06-01'], dtype='datetime64[ns]', freq='D')>>>>>> pd.date_range(start='2018-04-24', end='2018-04-27', periods=3)DatetimeIndex(['2018-04-24 00:00:00', '2018-04-25 12:00:00', '2018-04-27 00:00:00'], dtype='datetime64[ns]', freq=None)>>>>>> pd.date_range(start='2018-04-24', end='2018-04-28', periods=3)DatetimeIndex(['2018-04-24', '2018-04-26', '2018-04-28'], dtype='datetime64[ns]', freq=None) 指定 freq='M' 会按照每月最后一个日历日的频率生成日期,指定 freq='3M' 会每隔3个月按照每月最后一个日历日的频率生成日期: >>> import pandas as pd>>> pd.date_range(start='1/1/2018', periods=5, freq='M')DatetimeIndex(['2018-01-31', '2018-02-28', '2018-03-31', '2018-04-30', '2018-05-31'], dtype='datetime64[ns]', freq='M')>>> >>> pd.date_range(start='1/1/2018', periods=5, freq='3M')DatetimeIndex(['2018-01-31', '2018-04-30', '2018-07-31', '2018-10-31', '2019-01-31'], dtype='datetime64[ns]', freq='3M')>>> 使用 tz 参数设置时区: >>> import pandas as pd>>> pd.date_range(start='1/1/2018', periods=5, tz='Asia/Tokyo')DatetimeIndex(['2018-01-01 00:00:00+09:00', '2018-01-02 00:00:00+09:00', '2018-01-03 00:00:00+09:00', '2018-01-04 00:00:00+09:00', '2018-01-05 00:00:00+09:00'], dtype='datetime64[ns, Asia/Tokyo]', freq='D')>>> >>> pd.date_range(start='6/24/2020', periods=5, tz='Asia/Hong_Kong')DatetimeIndex(['2020-06-24 00:00:00+08:00', '2020-06-25 00:00:00+08:00', '2020-06-26 00:00:00+08:00', '2020-06-27 00:00:00+08:00', '2020-06-28 00:00:00+08:00'], dtype='datetime64[ns, Asia/Hong_Kong]', freq='D') 设置 normalize 参数,在生成时间戳之前对其进行格式化操作: >>> import pandas as pd>>> pd.date_range('2020-06-24 12:56:31', periods=5, normalize=True)DatetimeIndex(['2020-06-24', '2020-06-25', '2020-06-26', '2020-06-27', '2020-06-28'], dtype='datetime64[ns]', freq='D') 设置 closed 参数: >>> import pandas as pd>>> pd.date_range(start='2020-06-20', end='2020-06-24', closed=None)DatetimeIndex(['2020-06-20', '2020-06-21', '2020-06-22', '2020-06-23', '2020-06-24'], dtype='datetime64[ns]', freq='D')>>> >>> pd.date_range(start='2020-06-20', end='2020-06-24', closed='left')DatetimeIndex(['2020-06-20', '2020-06-21', '2020-06-22', '2020-06-23'], dtype='datetime64[ns]', freq='D')>>> >>> pd.date_range(start='2020-06-20', end='2020-06-24', closed='right')DatetimeIndex(['2020-06-21', '2020-06-22', '2020-06-23', '2020-06-24'], dtype='datetime64[ns]', freq='D') 【02x05】索引与切片 Pandas 最基本的时间序列类型就是以时间戳(通常以 Python 字符串或 datatime 对象表示)为索引的Series,这些 datetime 对象实际上是被放在 DatetimeIndex 中的,可以使用类似 pandas.Series 对象的切片方法对其进行索引: >>> import pandas as pd>>> import numpy as np>>> dates = [datetime(2011, 1, 2), datetime(2011, 1, 5), datetime(2011, 1, 7), datetime(2011, 1, 8), datetime(2011, 1, 10), datetime(2011, 1, 12)]>>> obj = pd.Series(np.random.randn(6), index=dates)>>> >>> obj2011-01-02 -0.4071102011-01-05 -0.1866612011-01-07 -0.7310802011-01-08 0.8609702011-01-10 1.9299732011-01-12 -0.168599dtype: float64>>> >>> obj.indexDatetimeIndex(['2011-01-02', '2011-01-05', '2011-01-07', '2011-01-08', '2011-01-10', '2011-01-12'], dtype='datetime64[ns]', freq=None)>>>>>> obj.index[0]Timestamp('2011-01-02 00:00:00')>>> >>> obj.index[0:3]DatetimeIndex(['2011-01-02', '2011-01-05', '2011-01-07'], dtype='datetime64[ns]', freq=None) 另外还可以传入一个可以被解释为日期的字符串,或者只需传入“年”或“年月”即可轻松选取数据的切片: >>> import pandas as pd>>> import numpy as np>>> obj = pd.Series(np.random.randn(1000), index=pd.date_range('1/1/2000', periods=1000))>>> obj2000-01-01 -1.1422842000-01-02 1.1987852000-01-03 2.4669092000-01-04 -0.0867282000-01-05 -0.978437 ... 2002-09-22 -0.2522402002-09-23 0.1485612002-09-24 -1.3304092002-09-25 -0.6734712002-09-26 -0.253271Freq: D, Length: 1000, dtype: float64>>> >>> obj['26/9/2002']-0.25327100684233356>>> >>> obj['2002']2002-01-01 1.0587152002-01-02 0.9008592002-01-03 1.9935082002-01-04 -0.1032112002-01-05 -0.950090 ... 2002-09-22 -0.2522402002-09-23 0.1485612002-09-24 -1.3304092002-09-25 -0.6734712002-09-26 -0.253271Freq: D, Length: 269, dtype: float64>>> >>> obj['2002-09']2002-09-01 -0.9955282002-09-02 0.5015282002-09-03 -0.4867532002-09-04 -1.0839062002-09-05 1.4589752002-09-06 -1.3316852002-09-07 0.1953382002-09-08 -0.4296132002-09-09 1.1258232002-09-10 1.6070512002-09-11 0.5303872002-09-12 -0.0159382002-09-13 1.7810432002-09-14 -0.2771232002-09-15 0.3445692002-09-16 -1.0108102002-09-17 0.4630012002-09-18 1.8836362002-09-19 0.2745202002-09-20 0.6241842002-09-21 -1.2030572002-09-22 -0.2522402002-09-23 0.1485612002-09-24 -1.3304092002-09-25 -0.6734712002-09-26 -0.253271Freq: D, dtype: float64>>> >>> obj['20/9/2002':'26/9/2002']2002-09-20 0.6241842002-09-21 -1.2030572002-09-22 -0.2522402002-09-23 0.1485612002-09-24 -1.3304092002-09-25 -0.6734712002-09-26 -0.253271Freq: D, dtype: float64 【02x06】移动数据与数据偏移 移动(shifting)指的是沿着时间轴将数据前移或后移。Series 和 DataFrame 都有一个 shift 方法用于执行单纯的前移或后移操作,保持索引不变: >>> import pandas as pd>>> import numpy as np>>> obj = pd.Series(np.random.randn(4), index=pd.date_range('1/1/2000', periods=4, freq='M'))>>> obj2000-01-31 -0.1002172000-02-29 1.1778342000-03-31 -0.6443532000-04-30 -1.954679Freq: M, dtype: float64>>> >>> obj.shift(2)2000-01-31 NaN2000-02-29 NaN2000-03-31 -0.1002172000-04-30 1.177834Freq: M, dtype: float64>>> >>> obj.shift(-2)2000-01-31 -0.6443532000-02-29 -1.9546792000-03-31 NaN2000-04-30 NaNFreq: M, dtype: float64 因为简单的移位操作不会修改索引,所以部分数据会被丢弃并引入 NaN(缺失值)。因此,如果频率已知,则可以将其传给 shift 以便实现对时间戳进行位移而不是对数据进行简单位移: >>> import pandas as pd>>> import numpy as np>>> obj = pd.Series(np.random.randn(4), index=pd.date_range('1/1/2000', periods=4, freq='M'))>>> obj2000-01-31 -0.1002172000-02-29 1.1778342000-03-31 -0.6443532000-04-30 -1.954679Freq: M, dtype: float64>>> >>> obj.shift(2, freq='M')2000-03-31 -0.1002172000-04-30 1.1778342000-05-31 -0.6443532000-06-30 -1.954679Freq: M, dtype: float64 Pandas 中的频率是由一个基础频率(base frequency)和一个乘数组成的。基础频率通常以一个字符串别名表示,比如 "M" 表示每月,"H" 表示每小时。对于每个基础频率,都有一个被称为日期偏移量(date offset)的对象与之对应。例如,按小时计算的频率可以用 Hour 类表示: >>> from pandas.tseries.offsets import Hour, Minute>>> hour = Hour()>>> hour<Hour>>>> >>> four_hours = Hour(4)>>> four_hours<4 * Hours> 一般来说,无需明确创建这样的对象,只需使用诸如 "H" 或 "4H" 这样的字符串别名即可。在基础频率前面放上一个整数即可创建倍数: >>> import pandas as pd>>> pd.date_range('2000-01-01', '2000-01-03 23:59', freq='4h')DatetimeIndex(['2000-01-01 00:00:00', '2000-01-01 04:00:00', '2000-01-01 08:00:00', '2000-01-01 12:00:00', '2000-01-01 16:00:00', '2000-01-01 20:00:00', '2000-01-02 00:00:00', '2000-01-02 04:00:00', '2000-01-02 08:00:00', '2000-01-02 12:00:00', '2000-01-02 16:00:00', '2000-01-02 20:00:00', '2000-01-03 00:00:00', '2000-01-03 04:00:00', '2000-01-03 08:00:00', '2000-01-03 12:00:00', '2000-01-03 16:00:00', '2000-01-03 20:00:00'], dtype='datetime64[ns]', freq='4H') 大部分偏移量对象都可通过加法进行连接: >>> from pandas.tseries.offsets import Hour, Minute>>> Hour(2) + Minute(30)<150 * Minutes> 对于 freq 参数也可以传入频率字符串(如 "2h30min"),这种字符串可以被高效地解析为等效的表达式: >>> import pandas as pd>>> pd.date_range('2000-01-01', periods=10, freq='1h30min')DatetimeIndex(['2000-01-01 00:00:00', '2000-01-01 01:30:00', '2000-01-01 03:00:00', '2000-01-01 04:30:00', '2000-01-01 06:00:00', '2000-01-01 07:30:00', '2000-01-01 09:00:00', '2000-01-01 10:30:00', '2000-01-01 12:00:00', '2000-01-01 13:30:00'], dtype='datetime64[ns]', freq='90T') 这种偏移量还可以用在 datetime 或 Timestamp 对象上: >>> from pandas.tseries.offsets import Day, MonthEnd>>> now = datetime(2011, 11, 17)>>> now + 3 * Day()Timestamp('2011-11-20 00:00:00') 如果加的是锚点偏移量,比如 MonthEnd,第一次增量会将原日期向前滚动到符合频率规则的下一个日期: >>> from pandas.tseries.offsets import Day, MonthEnd>>> now = datetime(2011, 11, 17)>>> now + MonthEnd()Timestamp('2011-11-30 00:00:00')>>> now + MonthEnd(2)Timestamp('2011-12-31 00:00:00') 通过锚点偏移量的 rollforward 和 rollback 方法,可明确地将日期向前或向后滚动: >>> from pandas.tseries.offsets import Day, MonthEnd>>> now = datetime(2011, 11, 17)>>> offset = MonthEnd()>>> offset.rollforward(now)Timestamp('2011-11-30 00:00:00')>>> offset.rollback(now)Timestamp('2011-10-31 00:00:00') 与 groupby 方法结合使用: >>> import pandas as pd>>> import numpy as np>>> from pandas.tseries.offsets import Day, MonthEnd>>> obj = pd.Series(np.random.randn(20), index=pd.date_range('1/15/2000', periods=20, freq='4d'))>>> obj2000-01-15 -0.5917292000-01-19 -0.7758442000-01-23 -0.7456032000-01-27 -0.0764392000-01-31 1.7964172000-02-04 -0.5003492000-02-08 0.5158512000-02-12 -0.3441712000-02-16 0.4196572000-02-20 0.3072882000-02-24 0.1151132000-02-28 -0.3625852000-03-03 1.0748922000-03-07 1.1113662000-03-11 0.9499102000-03-15 -1.5357272000-03-19 0.5459442000-03-23 -0.8101392000-03-27 -1.2606272000-03-31 -0.128403Freq: 4D, dtype: float64>>>>>> offset = MonthEnd()>>> obj.groupby(offset.rollforward).mean()2000-01-31 -0.0786402000-02-29 0.0215432000-03-31 -0.006598dtype: float64 【02x07】时区处理 在 Python 中,时区信息来自第三方库 pytz,使用 pytz.common_timezones 方法可以查看所有的时区名称,使用 pytz.timezone 方法从 pytz 中获取时区对象: >>> import pytz>>> pytz.common_timezones['Africa/Abidjan', 'Africa/Accra', 'Africa/Addis_Ababa', ..., 'UTC']>>>>>> tz = pytz.timezone('Asia/Shanghai')>>> tz<DstTzInfo 'Asia/Shanghai' LMT+8:06:00 STD> # 表示与 UTC 时间相差8小时6分 在 date_range 方法中,tz 参数用于指定时区,默认为 None,可以使用 tz_localize 方法将其进行本地化时区转换,如下示例中,将无时区转本地化 UTC 时区: >>> import pandas as pd>>> import numpy as np>>> rng = pd.date_range('3/9/2012 9:30', periods=6, freq='D')>>> ts = pd.Series(np.random.randn(len(rng)), index=rng)>>> ts2012-03-09 09:30:00 -1.5279132012-03-10 09:30:00 -1.1161012012-03-11 09:30:00 0.3593582012-03-12 09:30:00 -0.4759202012-03-13 09:30:00 -0.3365702012-03-14 09:30:00 -1.075952Freq: D, dtype: float64>>> >>> print(ts.index.tz)None>>> >>> ts_utc = ts.tz_localize('UTC')>>> ts_utc2012-03-09 09:30:00+00:00 -1.5279132012-03-10 09:30:00+00:00 -1.1161012012-03-11 09:30:00+00:00 0.3593582012-03-12 09:30:00+00:00 -0.4759202012-03-13 09:30:00+00:00 -0.3365702012-03-14 09:30:00+00:00 -1.075952Freq: D, dtype: float64>>>>>> ts_utc.indexDatetimeIndex(['2012-03-09 09:30:00+00:00', '2012-03-10 09:30:00+00:00', '2012-03-11 09:30:00+00:00', '2012-03-12 09:30:00+00:00', '2012-03-13 09:30:00+00:00', '2012-03-14 09:30:00+00:00'], dtype='datetime64[ns, UTC]', freq='D') 时间序列被本地化到某个特定时区后,就可以用 tz_convert 方法将其转换到别的时区了: >>> import pandas as pd>>> import numpy as np>>> rng = pd.date_range('3/9/2012 9:30', periods=6, freq='D')>>> ts = pd.Series(np.random.randn(len(rng)), index=rng)>>> ts2012-03-09 09:30:00 0.4803032012-03-10 09:30:00 -1.4610392012-03-11 09:30:00 -1.5127492012-03-12 09:30:00 -2.1854212012-03-13 09:30:00 1.6578452012-03-14 09:30:00 0.175633Freq: D, dtype: float64>>>>>> ts.tz_localize('UTC').tz_convert('Asia/Shanghai')2012-03-09 17:30:00+08:00 0.4803032012-03-10 17:30:00+08:00 -1.4610392012-03-11 17:30:00+08:00 -1.5127492012-03-12 17:30:00+08:00 -2.1854212012-03-13 17:30:00+08:00 1.6578452012-03-14 17:30:00+08:00 0.175633Freq: D, dtype: float64 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106947061未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【03x00】period 固定时期 【03x01】pandas.Period 固定时期(period)表示的是时间区间,比如数日、数月、数季、数年等。Period 类所表示的就是这种数据类型,其构造函数需要用到一个字符串或整数。 基本语法: class pandas.Period(value=None, freq=None, ordinal=None, year=None, month=None, quarter=None, day=None, hour=None, minute=None, second=None) 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.Period.html 常用参数: 参数描述 value时间段 freq时间戳将具有的偏移量,可以是 str,日期偏移量类型,取值参见【02x02】freq 频率部分取值 以下示例中,Period 对象表示的是从2020年1月1日到2020年12月31日之间的整段时间 >>> import pandas as pd>>> pd.Period(2020, freq='A-DEC')Period('2020', 'A-DEC') 利用加减法对其按照频率进行位移: >>> import pandas as pd>>> obj = pd.Period(2020, freq='A-DEC')>>> objPeriod('2020', 'A-DEC')>>> >>> obj + 5Period('2025', 'A-DEC')>>> >>> obj - 5Period('2015', 'A-DEC') PeriodIndex 类保存了一组 Period,它可以在任何 pandas 数据结构中被用作轴索引: >>> import pandas as pd>>> import numpy as np>>> rng = [pd.Period('2000-01'), pd.Period('2000-02'), pd.Period('2000-03'), pd.Period('2000-04'), pd.Period('2000-05'), pd.Period('2000-06')]>>> obj = pd.Series(np.random.randn(6), index=rng)>>> obj2000-01 0.2290922000-02 1.5154982000-03 -0.3344012000-04 -0.4926812000-05 -2.0128182000-06 0.338804Freq: M, dtype: float64>>> >>> obj.indexPeriodIndex(['2000-01', '2000-02', '2000-03', '2000-04', '2000-05', '2000-06'], dtype='period[M]', freq='M') >>> import pandas as pd>>> values = ['2001Q3', '2002Q2', '2003Q1']>>> index = pd.PeriodIndex(values, freq='Q-DEC')>>> indexPeriodIndex(['2001Q3', '2002Q2', '2003Q1'], dtype='period[Q-DEC]', freq='Q-DEC')>>> 【03x02】period_range pandas.period_range 方法可根据指定的频率生成指定长度的 PeriodIndex。 基本语法: pandas.period_range(start=None, end=None, periods=None, freq=None, name=None) → pandas.core.indexes.period.PeriodIndex 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.period_range.html 常用参数: 参数描述 start起始日期 end结束日期 periods要生成的时段数 freq时间戳将具有的偏移量,可以是 str,日期偏移量类型,取值参见【02x02】freq 频率部分取值 name结果 PeriodIndex 对象名称 简单应用: >>> import pandas as pd>>> pd.period_range(start='2019-01-01', end='2020-01-01', freq='M')PeriodIndex(['2019-01', '2019-02', '2019-03', '2019-04', '2019-05', '2019-06', '2019-07', '2019-08', '2019-09', '2019-10', '2019-11', '2019-12', '2020-01'], dtype='period[M]', freq='M')>>>>>> pd.period_range(start=pd.Period('2017Q1', freq='Q'), end=pd.Period('2017Q2', freq='Q'), freq='M')PeriodIndex(['2017-03', '2017-04', '2017-05', '2017-06'], dtype='period[M]', freq='M') 【03x03】asfreq 时期频率转换 Period 和 PeriodIndex 对象都可以通过 asfreq 方法被转换成别的频率。 基本语法:PeriodIndex.asfreq(self, *args, **kwargs) 常用参数: 参数描述 freq新的频率(偏移量),取值参见【02x02】freq 频率部分取值 how按照开始或者结束对齐,'E' or 'END' or 'FINISH';'S' or 'START' or 'BEGIN' 应用示例: >>> import pandas as pd>>> pidx = pd.period_range('2010-01-01', '2015-01-01', freq='A')>>> pidxPeriodIndex(['2010', '2011', '2012', '2013', '2014', '2015'], dtype='period[A-DEC]', freq='A-DEC')>>> >>> pidx.asfreq('M')PeriodIndex(['2010-12', '2011-12', '2012-12', '2013-12', '2014-12', '2015-12'], dtype='period[M]', freq='M')>>> >>> pidx.asfreq('M', how='S')PeriodIndex(['2010-01', '2011-01', '2012-01', '2013-01', '2014-01', '2015-01'], dtype='period[M]', freq='M') 【03x04】to_period 与 to_timestamp() to_period 方法可以将 Timestamp(时间戳) 转换为 Period(固定时期); to_timestamp 方法可以将 Period(固定时期)转换为 Timestamp(时间戳) 。 >>> import pandas as pd>>> rng = pd.date_range('2000-01-01', periods=3, freq='M')>>> ts = pd.Series(np.random.randn(3), index=rng)>>> ts2000-01-31 0.2207592000-02-29 -0.1082212000-03-31 0.819433Freq: M, dtype: float64>>> >>> pts = ts.to_period()>>> pts2000-01 0.2207592000-02 -0.1082212000-03 0.819433Freq: M, dtype: float64>>> >>> pts2 = pts.to_timestamp()>>> pts22000-01-01 0.2207592000-02-01 -0.1082212000-03-01 0.819433Freq: MS, dtype: float64>>> >>> ts.indexDatetimeIndex(['2000-01-31', '2000-02-29', '2000-03-31'], dtype='datetime64[ns]', freq='M')>>> >>> pts.indexPeriodIndex(['2000-01', '2000-02', '2000-03'], dtype='period[M]', freq='M')>>> >>> pts2.indexDatetimeIndex(['2000-01-01', '2000-02-01', '2000-03-01'], dtype='datetime64[ns]', freq='MS') 【04x00】timedelta 时间间隔 【04x01】pandas.Timedelta Timedelta 表示持续时间,即两个日期或时间之间的差。 Timedelta 相当于 Python 的 datetime.timedelta,在大多数情况下两者可以互换。 基本语法:class pandas.Timedelta(value=<object object>, unit=None, **kwargs) 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.Timedelta.html 常用参数: 参数描述 value传入的值,可以是 Timedelta,timedelta,np.timedelta64,string 或 integer 对象 unit用于设置 value 的单位,具体取值参见官方文档 表示两个 datetime 对象之间的时间差: >>> import pandas as pd>>> pd.to_datetime('2020-6-24') - pd.to_datetime('2016-1-1')Timedelta('1636 days 00:00:00') 通过字符串传递参数: >>> import pandas as pd>>> pd.Timedelta('3 days 3 hours 3 minutes 30 seconds')Timedelta('3 days 03:03:30') 通过整数传递参数: >>> import pandas as pd>>> pd.Timedelta(5,unit='h')Timedelta('0 days 05:00:00') 获取属性: >>> import pandas as pd>>> obj = pd.Timedelta('3 days 3 hours 3 minutes 30 seconds')>>> objTimedelta('3 days 03:03:30')>>> >>> obj.days3>>> obj.seconds11010 【04x02】to_timedelta to_timedelta 方法可以将传入的对象转换成 timedelta 对象。 基本语法:pandas.to_timedelta(arg, unit='ns', errors='raise') 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.to_timedelta.html 常用参数: 参数描述 arg要转换为 timedelta 的对象,可以是 str,timedelta,list-like 或 Series 对象 unit用于设置 arg 的单位,具体取值参见官方文档 errors如果 arg 不满足时间戳的形式,是否会发生异常 ignore:不引发异常,返回原始输入;raise:无效解析将引发异常(默认);coerce:无效解析将被设置为NaT 将单个字符串解析为 timedelta 对象: >>> import pandas as pd>>> pd.to_timedelta('1 days 06:05:01.00003')Timedelta('1 days 06:05:01.000030')>>>>>> pd.to_timedelta('15.5us')Timedelta('0 days 00:00:00.000015') 将字符串列表或数组解析为 timedelta 对象: >>> import pandas as pd>>> pd.to_timedelta(['1 days 06:05:01.00003', '15.5us', 'nan'])TimedeltaIndex(['1 days 06:05:01.000030', '0 days 00:00:00.000015', NaT], dtype='timedelta64[ns]', freq=None) 指定 unit 参数: >>> import pandas as pd>>> pd.to_timedelta(np.arange(5), unit='s')TimedeltaIndex(['00:00:00', '00:00:01', '00:00:02', '00:00:03', '00:00:04'], dtype='timedelta64[ns]', freq=None)>>> >>> pd.to_timedelta(np.arange(5), unit='d')TimedeltaIndex(['0 days', '1 days', '2 days', '3 days', '4 days'], dtype='timedelta64[ns]', freq=None) 【04x03】timedelta_range timedelta_range 方法可根据指定的频率生成指定长度的 TimedeltaIndex。 基本语法: pandas.timedelta_range(start=None, end=None, periods=None, freq=None, name=None, closed=None) → pandas.core.indexes.timedeltas.TimedeltaIndex 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.timedelta_range.html 常用参数: 参数描述 start开始日期 end结束日期 periodsint 类型,要生成的时段数 freq频率字符串,即按照某种特定的频率来生成日期,取值参见【02x02】freq 频率部分取值 name结果 TimedeltaIndex 的名称 closedNone:默认值,同时保留开始日期和结束日期 'left':保留开始日期,不保留结束日期 'right':保留结束日期,不保留开始日期 应用示例: >>> import pandas as pd>>> pd.timedelta_range(start='1 day', periods=4)TimedeltaIndex(['1 days', '2 days', '3 days', '4 days'], dtype='timedelta64[ns]', freq='D') closed 参数指定保留哪个端点。默认保留两个端点: >>> import pandas as pd>>> pd.timedelta_range(start='1 day', periods=4, closed='right')TimedeltaIndex(['2 days', '3 days', '4 days'], dtype='timedelta64[ns]', freq='D') freq 参数指定 TimedeltaIndex 的频率。只接受固定频率,非固定频率如 'M' 将会报错: >>> import pandas as pd>>> pd.timedelta_range(start='1 day', end='2 days', freq='6H')TimedeltaIndex(['1 days 00:00:00', '1 days 06:00:00', '1 days 12:00:00', '1 days 18:00:00', '2 days 00:00:00'], dtype='timedelta64[ns]', freq='6H')>>> >>> pd.timedelta_range(start='1 day', end='2 days', freq='M')Traceback (most recent call last):...ValueError: <MonthEnd> is a non-fixed frequency 【05x00】重采样及频率转换 重采样(resampling)指的是将时间序列从一个频率转换到另一个频率的处理过程。将高频率数据聚合到低频率称为降采样(downsampling),而将低频率数据转换到高频率则称为升采样(upsampling)。并不是所有的重采样都能被划分到这两个大类中。例如,将 W-WED(每周三)转换为 W-FRI 既不是降采样也不是升采样。 Pandas 中提供了 resample 方法来帮助我们实现重采样。Pandas 对象都带有一个 resample 方法,它是各种频率转换工作的主力函数。 基本语法: Series.resample(self, rule, axis=0, closed: Union[str, NoneType] = None, label: Union[str, NoneType] = None, convention: str = 'start', kind: Union[str, NoneType] = None, loffset=None, base: int = 0, on=None, level=None) DataFrame.resample(self, rule, axis=0, closed: Union[str, NoneType] = None, label: Union[str, NoneType] = None, convention: str = 'start', kind: Union[str, NoneType] = None, loffset=None, base: int = 0, on=None, level=None) 常用参数: 参数描述 rule axis重采样的轴,默认 0 closed在重采样中,各时间段的哪一端是闭合(即包含)的, 除 'M'、'A'、'Q'、'BM'、'BA'、'BQ' 和 'W' 默认值为 ‘right’ 外,其他默认值为 'left‘ label在重采样中,如何设置聚合值的标签, right 或 left,默认为 None, 例如,9:30 到 9:35 之间的这 5 分钟会被标记为 9:30 或 9:35 convention仅用于 PeriodIndex(固定时期),对周期进行重采样,'start' or 's','end' or 'e' on对于 DataFrame 对象,可用该参数指定重采样后的数据的 index(行索引) 为原数据中的某列 level对于具有层级索引(MultiIndex)的 DataFrame 对象,可以使用该参数来指定需要在哪个级别上进行重新采样 将序列重采样到三分钟的频率,并将每个频率的值相加: >>> import pandas as pd>>> index = pd.date_range('1/1/2000', periods=9, freq='T')>>> series = pd.Series(range(9), index=index)>>> series2000-01-01 00:00:00 02000-01-01 00:01:00 12000-01-01 00:02:00 22000-01-01 00:03:00 32000-01-01 00:04:00 42000-01-01 00:05:00 52000-01-01 00:06:00 62000-01-01 00:07:00 72000-01-01 00:08:00 8Freq: T, dtype: int64>>> >>> series.resample('3T').sum()2000-01-01 00:00:00 32000-01-01 00:03:00 122000-01-01 00:06:00 21Freq: 3T, dtype: int64 设置 label='right',即每个索引 index 会使用靠右侧(较大值)的标签: >>> import pandas as pd>>> index = pd.date_range('1/1/2000', periods=9, freq='T')>>> series = pd.Series(range(9), index=index)>>> series2000-01-01 00:00:00 02000-01-01 00:01:00 12000-01-01 00:02:00 22000-01-01 00:03:00 32000-01-01 00:04:00 42000-01-01 00:05:00 52000-01-01 00:06:00 62000-01-01 00:07:00 72000-01-01 00:08:00 8Freq: T, dtype: int64>>> >>> series.resample('3T', label='right').sum()2000-01-01 00:03:00 32000-01-01 00:06:00 122000-01-01 00:09:00 21Freq: 3T, dtype: int64 设置 closed='right',即结果中会包含原数据中最右侧(较大)的值: >>> import pandas as pd>>> index = pd.date_range('1/1/2000', periods=9, freq='T')>>> series = pd.Series(range(9), index=index)>>> series2000-01-01 00:00:00 02000-01-01 00:01:00 12000-01-01 00:02:00 22000-01-01 00:03:00 32000-01-01 00:04:00 42000-01-01 00:05:00 52000-01-01 00:06:00 62000-01-01 00:07:00 72000-01-01 00:08:00 8Freq: T, dtype: int64>>> >>> series.resample('3T', label='right', closed='right').sum()2000-01-01 00:00:00 02000-01-01 00:03:00 62000-01-01 00:06:00 152000-01-01 00:09:00 15Freq: 3T, dtype: int64 以下示例将序列重采样到30秒的频率,asfreq()[0:5] 用于选择前5行数据: >>> import pandas as pd>>> index = pd.date_range('1/1/2000', periods=9, freq='T')>>> series = pd.Series(range(9), index=index)>>> series2000-01-01 00:00:00 02000-01-01 00:01:00 12000-01-01 00:02:00 22000-01-01 00:03:00 32000-01-01 00:04:00 42000-01-01 00:05:00 52000-01-01 00:06:00 62000-01-01 00:07:00 72000-01-01 00:08:00 8Freq: T, dtype: int64>>> >>> series.resample('30S').asfreq()[0:5]2000-01-01 00:00:00 0.02000-01-01 00:00:30 NaN2000-01-01 00:01:00 1.02000-01-01 00:01:30 NaN2000-01-01 00:02:00 2.0Freq: 30S, dtype: float64 使用 pad 方法向后填充缺失值(NaN): >>> import pandas as pd>>> index = pd.date_range('1/1/2000', periods=9, freq='T')>>> series = pd.Series(range(9), index=index)>>> series2000-01-01 00:00:00 02000-01-01 00:01:00 12000-01-01 00:02:00 22000-01-01 00:03:00 32000-01-01 00:04:00 42000-01-01 00:05:00 52000-01-01 00:06:00 62000-01-01 00:07:00 72000-01-01 00:08:00 8Freq: T, dtype: int64>>> >>> series.resample('30S').pad()[0:5]2000-01-01 00:00:00 02000-01-01 00:00:30 02000-01-01 00:01:00 12000-01-01 00:01:30 12000-01-01 00:02:00 2Freq: 30S, dtype: int64 使用 bfill 方法向前填充缺失值(NaN): >>> import pandas as pd>>> index = pd.date_range('1/1/2000', periods=9, freq='T')>>> series = pd.Series(range(9), index=index)>>> series2000-01-01 00:00:00 02000-01-01 00:01:00 12000-01-01 00:02:00 22000-01-01 00:03:00 32000-01-01 00:04:00 42000-01-01 00:05:00 52000-01-01 00:06:00 62000-01-01 00:07:00 72000-01-01 00:08:00 8Freq: T, dtype: int64>>> >>> series.resample('30S').bfill()[0:5]2000-01-01 00:00:00 02000-01-01 00:00:30 12000-01-01 00:01:00 12000-01-01 00:01:30 22000-01-01 00:02:00 2Freq: 30S, dtype: int64 通过 apply 方法传递自定义函数: >>> import pandas as pd>>> index = pd.date_range('1/1/2000', periods=9, freq='T')>>> series = pd.Series(range(9), index=index)>>> series2000-01-01 00:00:00 02000-01-01 00:01:00 12000-01-01 00:02:00 22000-01-01 00:03:00 32000-01-01 00:04:00 42000-01-01 00:05:00 52000-01-01 00:06:00 62000-01-01 00:07:00 72000-01-01 00:08:00 8Freq: T, dtype: int64>>> >>> def custom_resampler(array_like): return np.sum(array_like) + 5>>> series.resample('3T').apply(custom_resampler)2000-01-01 00:00:00 82000-01-01 00:03:00 172000-01-01 00:06:00 26Freq: 3T, dtype: int64 convention 参数的应用: >>> import pandas as pd>>> s = pd.Series([1, 2], index=pd.period_range('2012-01-01', freq='A', periods=2))>>> s2012 12013 2Freq: A-DEC, dtype: int64>>> >>> s.resample('Q', convention='start').asfreq()2012Q1 1.02012Q2 NaN2012Q3 NaN2012Q4 NaN2013Q1 2.02013Q2 NaN2013Q3 NaN2013Q4 NaNFreq: Q-DEC, dtype: float64>>> >>> s.resample('Q', convention='end').asfreq()2012Q4 1.02013Q1 NaN2013Q2 NaN2013Q3 NaN2013Q4 2.0Freq: Q-DEC, dtype: float64 >>> import pandas as pd>>> q = pd.Series([1, 2, 3, 4], index=pd.period_range('2018-01-01', freq='Q', periods=4))>>> q2018Q1 12018Q2 22018Q3 32018Q4 4Freq: Q-DEC, dtype: int64>>> >>> q.resample('M', convention='end').asfreq()2018-03 1.02018-04 NaN2018-05 NaN2018-06 2.02018-07 NaN2018-08 NaN2018-09 3.02018-10 NaN2018-11 NaN2018-12 4.0Freq: M, dtype: float64>>> >>> q.resample('M', convention='start').asfreq()2018-01 1.02018-02 NaN2018-03 NaN2018-04 2.02018-05 NaN2018-06 NaN2018-07 3.02018-08 NaN2018-09 NaN2018-10 4.02018-11 NaN2018-12 NaNFreq: M, dtype: float64 对于 DataFrame 对象,可以使用关键字 on 来指定原数据中的某列为重采样后数据的行索引: >>> import pandas as pd>>> d = dict({'price': [10, 11, 9, 13, 14, 18, 17, 19], 'volume': [50, 60, 40, 100, 50, 100, 40, 50]})>>> df = pd.DataFrame(d)>>> df['week_starting'] = pd.date_range('01/01/2018', periods=8, freq='W')>>> df price volume week_starting0 10 50 2018-01-071 11 60 2018-01-142 9 40 2018-01-213 13 100 2018-01-284 14 50 2018-02-045 18 100 2018-02-116 17 40 2018-02-187 19 50 2018-02-25>>> >>> df.resample('M', on='week_starting').mean() price volumeweek_starting 2018-01-31 10.75 62.52018-02-28 17.00 60.0 对于具有层级索引(MultiIndex)的 DataFrame 对象,可以使用关键字 level 来指定需要在哪个级别上进行重新采样: >>> import pandas as pd>>> days = pd.date_range('1/1/2000', periods=4, freq='D')>>> d2 = dict({'price': [10, 11, 9, 13, 14, 18, 17, 19], 'volume': [50, 60, 40, 100, 50, 100, 40, 50]})>>> df2 = pd.DataFrame(d2, index=pd.MultiIndex.from_product([days, ['morning', 'afternoon']]))>>> df2 price volume2000-01-01 morning 10 50 afternoon 11 602000-01-02 morning 9 40 afternoon 13 1002000-01-03 morning 14 50 afternoon 18 1002000-01-04 morning 17 40 afternoon 19 50>>> >>> df2.resample('D', level=0).sum() price volume2000-01-01 21 1102000-01-02 22 1402000-01-03 32 1502000-01-04 36 90 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106947061未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【01x00】数据重塑 【01x01】stack 【01x02】unstack 【02x00】重复数据处理 【02x01】duplicated 【02x02】drop_duplicates 【03x00】数据替换 【03x01】replace 【03x02】where 【03x03】mask Pandas 系列文章: Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象 Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作 Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理 Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引 Python 数据分析三剑客之 Pandas(五):统计计算与统计描述 Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并 Python 数据分析三剑客之 Pandas(七):合并数据集 Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换 Python 数据分析三剑客之 Pandas(九):时间序列 Python 数据分析三剑客之 Pandas(十):数据读写 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106900748未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【01x00】数据重塑 有许多用于重新排列表格型数据的基础运算。这些函数也称作重塑(reshape)或轴向旋转(pivot)运算。重塑层次化索引主要有以下两个方法: stack:将数据的列转换成行; unstack:将数据的行转换成列。 【01x01】stack stack 方法用于将数据的列转换成为行; 基本语法:DataFrame.stack(self, level=-1, dropna=True) 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.stack.html 参数描述 level从列转换到行,指定不同层级的列索引或列标签、由列索引或列标签组成的数组,默认-1 dropnabool 类型,是否删除重塑后数据中所有值为 NaN 的行,默认 True 单层列(Single level columns): >>> import pandas as pd>>> obj = pd.DataFrame([[0, 1], [2, 3]], index=['cat', 'dog'], columns=['weight', 'height'])>>> obj weight heightcat 0 1dog 2 3>>> >>> obj.stack()cat weight 0 height 1dog weight 2 height 3dtype: int64 多层列(Multi level columns): >>> import pandas as pd>>> multicol = pd.MultiIndex.from_tuples([('weight', 'kg'), ('weight', 'pounds')])>>> obj = pd.DataFrame([[1, 2], [2, 4]], index=['cat', 'dog'], columns=multicol)>>> obj weight kg poundscat 1 2dog 2 4>>> >>> obj.stack() weightcat kg 1 pounds 2dog kg 2 pounds 4 缺失值填充: >>> import pandas as pd>>> multicol = pd.MultiIndex.from_tuples([('weight', 'kg'), ('height', 'm')])>>> obj = pd.DataFrame([[1.0, 2.0], [3.0, 4.0]], index=['cat', 'dog'], columns=multicol)>>> obj weight height kg mcat 1.0 2.0dog 3.0 4.0>>> >>> obj.stack() height weightcat kg NaN 1.0 m 2.0 NaNdog kg NaN 3.0 m 4.0 NaN 通过 level 参数指定不同层级的轴进行重塑: >>> import pandas as pd>>> multicol = pd.MultiIndex.from_tuples([('weight', 'kg'), ('height', 'm')])>>> obj = pd.DataFrame([[1.0, 2.0], [3.0, 4.0]], index=['cat', 'dog'], columns=multicol)>>> obj weight height kg mcat 1.0 2.0dog 3.0 4.0>>> >>> obj.stack(level=0) kg mcat height NaN 2.0 weight 1.0 NaNdog height NaN 4.0 weight 3.0 NaN>>> >>> obj.stack(level=1) height weightcat kg NaN 1.0 m 2.0 NaNdog kg NaN 3.0 m 4.0 NaN>>>>>> obj.stack(level=[0, 1])cat height m 2.0 weight kg 1.0dog height m 4.0 weight kg 3.0dtype: float64 对于重塑后的数据,若有一行的值均为 NaN,则默认会被删除,可以设置 dropna=False 来保留缺失值: >>> import pandas as pd>>> multicol = pd.MultiIndex.from_tuples([('weight', 'kg'), ('height', 'm')])>>> obj = pd.DataFrame([[None, 1.0], [2.0, 3.0]], index=['cat', 'dog'], columns=multicol)>>> obj weight height kg mcat NaN 1.0dog 2.0 3.0>>> >>> obj.stack(dropna=False) height weightcat kg NaN NaN m 1.0 NaNdog kg NaN 2.0 m 3.0 NaN>>> >>> obj.stack(dropna=True) height weightcat m 1.0 NaNdog kg NaN 2.0 m 3.0 NaN 【01x02】unstack unstack:将数据的行转换成列。 基本语法: Series.unstack(self, level=-1, fill_value=None) DataFrame.unstack(self, level=-1, fill_value=None) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.unstack.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.unstack.html 参数描述 level从行转换到列,指定不同层级的行索引,默认-1 fill_value用于替换 NaN 的值 在 Series 对象中的应用: >>> import pandas as pd>>> obj = pd.Series([1, 2, 3, 4], index=pd.MultiIndex.from_product([['one', 'two'], ['a', 'b']]))>>> objone a 1 b 2two a 3 b 4dtype: int64>>> >>> obj.unstack() a bone 1 2two 3 4>>> >>> obj.unstack(level=0) one twoa 1 3b 2 4 和 stack 方法类似,如果值不存在将会引入缺失值(NaN): >>> import pandas as pd>>> obj1 = pd.Series([0, 1, 2, 3], index=['a', 'b', 'c', 'd'])>>> obj2 = pd.Series([4, 5, 6], index=['c', 'd', 'e'])>>> obj3 = pd.concat([obj1, obj2], keys=['one', 'two'])>>> obj3one a 0 b 1 c 2 d 3two c 4 d 5 e 6dtype: int64>>> >>> obj3.unstack() a b c d eone 0.0 1.0 2.0 3.0 NaNtwo NaN NaN 4.0 5.0 6.0 在 DataFrame 对象中的应用: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame(np.arange(6).reshape((2, 3)), index=pd.Index(['Ohio','Colorado'], name='state'), columns=pd.Index(['one', 'two', 'three'], name='number'))>>> objnumber one two threestate Ohio 0 1 2Colorado 3 4 5>>> >>> obj2 = obj.stack()>>> obj2state numberOhio one 0 two 1 three 2Colorado one 3 two 4 three 5dtype: int32>>> >>> obj3 = pd.DataFrame({'left': obj2, 'right': obj2 + 5}, columns=pd.Index(['left', 'right'], name='side'))>>> obj3side left rightstate number Ohio one 0 5 two 1 6 three 2 7Colorado one 3 8 two 4 9 three 5 10>>> >>> obj3.unstack('state')side left right state Ohio Colorado Ohio Coloradonumber one 0 3 5 8two 1 4 6 9three 2 5 7 10>>> >>> obj3.unstack('state').stack('side')state Colorado Ohionumber side one left 3 0 right 8 5two left 4 1 right 9 6three left 5 2 right 10 7 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106900748未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【02x00】重复数据处理 duplicated:判断是否为重复值; drop_duplicates:删除重复值。 【02x01】duplicated duplicated 方法可以判断值是否为重复数据。 基本语法: Series.duplicated(self, keep='first') DataFrame.duplicated(self, subset: Union[Hashable, Sequence[Hashable], NoneType] = None, keep: Union[str, bool] = 'first') → ’Series’ 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.duplicated.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.duplicated.html 参数描述 keep标记重复项的方法,默认 'first' 'first':将非重复项和第一个重复项标记为 False,其他重复项标记为 True 'last':将非重复项和最后一个重复项标记为 False,其他重复项标记为 True False:将所有重复项标记为 True,非重复项标记为 False subset列标签或标签序列,在 DataFrame 对象中才有此参数, 用于指定某列,仅标记该列的重复项,默认情况下将考虑所有列 默认情况下,对于每组重复的值,第一个出现的重复值标记为 False,其他重复项标记为 True,非重复项标记为 False,相当于 keep='first': >>> import pandas as pd>>> obj = pd.Series(['lama', 'cow', 'lama', 'beetle', 'lama'])>>> obj0 lama1 cow2 lama3 beetle4 lamadtype: object>>> >>> obj.duplicated()0 False1 False2 True3 False4 Truedtype: bool>>>>>> obj.duplicated(keep='first')0 False1 False2 True3 False4 Truedtype: bool 设置 keep='last',将每组非重复项和最后一次出现的重复项标记为 False,其他重复项标记为 True,设置 keep=False,则所有重复项均为 True,其他值为 False: >>> import pandas as pd>>> obj = pd.Series(['lama', 'cow', 'lama', 'beetle', 'lama'])>>> obj0 lama1 cow2 lama3 beetle4 lamadtype: object>>> >>> obj.duplicated(keep='last')0 True1 False2 True3 False4 Falsedtype: bool>>> >>> obj.duplicated(keep=False)0 True1 False2 True3 False4 Truedtype: bool 在 DataFrame 对象中,subset 参数用于指定某列,仅标记该列的重复项,默认情况下将考虑所有列: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame({'data1' : ['a'] * 4 + ['b'] * 4, 'data2' : np.random.randint(0, 4, 8)})>>> obj data1 data20 a 01 a 02 a 03 a 34 b 35 b 36 b 07 b 2>>> >>> obj.duplicated()0 False1 True2 True3 False4 False5 True6 False7 Falsedtype: bool>>> >>> obj.duplicated(subset='data1')0 False1 True2 True3 True4 False5 True6 True7 Truedtype: bool>>> >>> obj.duplicated(subset='data2', keep='last')0 True1 True2 True3 True4 True5 False6 False7 Falsedtype: bool 【02x02】drop_duplicates drop_duplicates 方法会返回一个删除了重复值的序列。 基本语法: Series.drop_duplicates(self, keep='first', inplace=False) DataFrame.drop_duplicates(self, subset: Union[Hashable, Sequence[Hashable], NoneType] = None, keep: Union[str, bool] = 'first', inplace: bool = False, ignore_index: bool = False) → Union[ForwardRef(‘DataFrame’), NoneType] 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.drop_duplicates.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.drop_duplicates.html 参数描述 keep删除重复项的方法,默认 'first' 'first':保留非重复项和第一个重复项,其他重复项标记均删除 'last':保留非重复项和最后一个重复项,其他重复项删除 False:将所有重复项删除,非重复项保留 inplace是否返回删除重复项后的值,默认 False,若设置为 True,则不返回值,直接改变原数据 subset列标签或标签序列,在 DataFrame 对象中才有此参数, 用于指定某列,仅标记该列的重复项,默认情况下将考虑所有列 ignore_indexbool 类型,在 DataFrame 对象中才有此参数,是否忽略原对象的轴标记, 默认 False,如果为 True,则新对象的索引将是 0, 1, 2, …, n-1 keep 参数的使用: >>> import pandas as pd>>> obj = pd.Series(['lama', 'cow', 'lama', 'beetle', 'lama', 'hippo'], name='animal')>>> obj0 lama1 cow2 lama3 beetle4 lama5 hippoName: animal, dtype: object>>> >>> obj.drop_duplicates()0 lama1 cow3 beetle5 hippoName: animal, dtype: object>>> >>> obj.drop_duplicates(keep='last')1 cow3 beetle4 lama5 hippoName: animal, dtype: object>>> >>> obj.drop_duplicates(keep=False)1 cow3 beetle5 hippoName: animal, dtype: object 如果设置 inplace=True,则不会返回任何值,但原对象的值已被改变: >>> import pandas as pd>>> obj1 = pd.Series(['lama', 'cow', 'lama', 'beetle', 'lama', 'hippo'], name='animal')>>> obj10 lama1 cow2 lama3 beetle4 lama5 hippoName: animal, dtype: object>>> >>> obj2 = obj1.drop_duplicates()>>> obj2 # 有返回值0 lama1 cow3 beetle5 hippoName: animal, dtype: object>>> >>> obj3 = obj1.drop_duplicates(inplace=True)>>> obj3 # 无返回值>>>>>> obj1 # 原对象的值已改变0 lama1 cow3 beetle5 hippoName: animal, dtype: object 在 DataFrame 对象中的使用: >>> import numpy as np>>> import pandas as pd>>> obj = pd.DataFrame({'data1' : ['a'] * 4 + ['b'] * 4, 'data2' : np.random.randint(0, 4, 8)})>>> obj data1 data20 a 21 a 12 a 13 a 24 b 15 b 26 b 07 b 0>>> >>> obj.drop_duplicates() data1 data20 a 21 a 14 b 15 b 26 b 0>>> >>> obj.drop_duplicates(subset='data2') data1 data20 a 21 a 16 b 0>>> >>> obj.drop_duplicates(subset='data2', ignore_index=True) data1 data20 a 21 a 12 b 0 【03x00】数据替换 【03x01】replace replace 方法可以根据值的内容进行替换。 基本语法: Series.replace(self, to_replace=None, value=None, inplace=False, limit=None, regex=False, method='pad') DataFrame.replace(self, to_replace=None, value=None, inplace=False, limit=None, regex=False, method='pad') 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.replace.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.replace.html 常用参数: 参数描述 to_replace找到要替换值的方法,可以是:字符串、正则表达式、列表、字典、整数、浮点数、Series 对象或者 None 使用不同参数的区别参见官方文档 value用于替换匹配项的值, 对于 DataFrame,可以使用字典的值来指定每列要使用的值, 还允许使用此类对象的正则表达式,字符串和列表或字典 inplacebool 类型,是否直接改变原数据且不返回值,默认 False regexbool 类型或者与 to_replace 相同的类型, 当 to_replace 参数为正则表达式时,regex 应为 True,或者直接使用该参数代替 to_replace to_replace 和 value 参数只传入一个值,单个值替换单个值: >>> import pandas as pd>>> obj = pd.Series([0, 1, 2, 3, 4])>>> obj0 01 12 23 34 4dtype: int64>>> >>> obj.replace(0, 5)0 51 12 23 34 4dtype: int64 to_replace 传入多个值,value 传入一个值,多个值替换一个值: >>> import pandas as pd>>> obj = pd.Series([0, 1, 2, 3, 4])>>> obj0 01 12 23 34 4dtype: int64>>> >>> obj.replace([0, 1, 2, 3], 4)0 41 42 43 44 4dtype: int64 to_replace 和 value 参数都传入多个值,多个值替换多个值: >>> import pandas as pd>>> obj = pd.Series([0, 1, 2, 3, 4])>>> obj0 01 12 23 34 4dtype: int64>>> >>> obj.replace([0, 1, 2, 3], [4, 3, 2, 1])0 41 32 23 14 4dtype: int64 to_replace 传入字典: >>> import pandas as pd>>> obj = pd.DataFrame({'A': [0, 1, 2, 3, 4], 'B': [5, 6, 7, 8, 9], 'C': ['a', 'b', 'c', 'd', 'e']})>>> obj A B C0 0 5 a1 1 6 b2 2 7 c3 3 8 d4 4 9 e>>> >>> obj.replace(0, 5) A B C0 5 5 a1 1 6 b2 2 7 c3 3 8 d4 4 9 e>>> >>> obj.replace({0: 10, 1: 100}) A B C0 10 5 a1 100 6 b2 2 7 c3 3 8 d4 4 9 e>>> >>> obj.replace({'A': 0, 'B': 5}, 100) A B C0 100 100 a1 1 6 b2 2 7 c3 3 8 d4 4 9 e>>> obj.replace({'A': {0: 100, 4: 400}}) A B C0 100 5 a1 1 6 b2 2 7 c3 3 8 d4 400 9 e to_replace 传入正则表达式: >>> import pandas as pd>>> obj = pd.DataFrame({'A': ['bat', 'foo', 'bait'], 'B': ['abc', 'bar', 'xyz']})>>> obj A B0 bat abc1 foo bar2 bait xyz>>> >>> obj.replace(to_replace=r'^ba.$', value='new', regex=True) A B0 new abc1 foo new2 bait xyz>>> >>> obj.replace({'A': r'^ba.$'}, {'A': 'new'}, regex=True) A B0 new abc1 foo bar2 bait xyz>>> >>> obj.replace(regex=r'^ba.$', value='new') A B0 new abc1 foo new2 bait xyz>>> >>> obj.replace(regex={r'^ba.$': 'new', 'foo': 'xyz'}) A B0 new abc1 xyz new2 bait xyz>>> >>> obj.replace(regex=[r'^ba.$', 'foo'], value='new') A B0 new abc1 new new2 bait xyz 【03x02】where where 方法用于替换条件为 False 的值。 基本语法: Series.where(self, cond, other=nan, inplace=False, axis=None, level=None, errors='raise', try_cast=False) DataFrame.where(self, cond, other=nan, inplace=False, axis=None, level=None, errors='raise', try_cast=False) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.where.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.where.html 常用参数: 参数描述 cond替换条件,如果 cond 为 True,则保留原始值。如果为 False,则替换为来自 other 的相应值 other替换值,如果 cond 为 False,则替换为来自该参数的相应值 inplacebool 类型,是否直接改变原数据且不返回值,默认 False 在 Series 中的应用: >>> import pandas as pd>>> obj = pd.Series(range(5))>>> obj0 01 12 23 34 4dtype: int64>>> >>> obj.where(obj > 0)0 NaN1 1.02 2.03 3.04 4.0dtype: float64>>> >>> obj.where(obj > 1, 10)0 101 102 23 34 4dtype: int64 在 DataFrame 中的应用: >>> import pandas as pd>>> obj = pd.DataFrame(np.arange(10).reshape(-1, 2), columns=['A', 'B'])>>> obj A B0 0 11 2 32 4 53 6 74 8 9>>> >>> m = obj % 3 == 0>>> obj.where(m, -obj) A B0 0 -11 -2 32 -4 -53 6 -74 -8 9>>> >>> obj.where(m, -obj) == np.where(m, obj, -obj) A B0 True True1 True True2 True True3 True True4 True True 【03x03】mask mask 方法与 where 方法相反,mask 用于替换条件为 False 的值。 基本语法: Series.mask(self, cond, other=nan, inplace=False, axis=None, level=None, errors='raise', try_cast=False) DataFrame.mask(self, cond, other=nan, inplace=False, axis=None, level=None, errors='raise', try_cast=False) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.mask.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.mask.html 常用参数: 参数描述 cond替换条件,如果 cond 为 False,则保留原始值。如果为 True,则替换为来自 other 的相应值 other替换值,如果 cond 为 False,则替换为来自该参数的相应值 inplacebool 类型,是否直接改变原数据且不返回值,默认 False 在 Series 中的应用: >>> import pandas as pd>>> obj = pd.Series(range(5))>>> obj0 01 12 23 34 4dtype: int64>>> >>> obj.mask(obj > 0)0 0.01 NaN2 NaN3 NaN4 NaNdtype: float64>>> >>> obj.mask(obj > 1, 10)0 01 12 103 104 10dtype: int64 在 DataFrame 中的应用: >>> import pandas as pd>>> obj = pd.DataFrame(np.arange(10).reshape(-1, 2), columns=['A', 'B'])>>> obj A B0 0 11 2 32 4 53 6 74 8 9>>> >>> m = obj % 3 == 0>>> >>> obj.mask(m, -obj) A B0 0 11 2 -32 4 53 -6 74 8 -9>>> >>> obj.where(m, -obj) == obj.mask(~m, -obj) A B0 True True1 True True2 True True3 True True4 True True 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106900748未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【01x00】concat 【02x00】append 【03x00】merge 【03x01】一对一连接 【03x02】多对一连接 【03x03】多对多连接 【03x04】参数 on / left_on / right_on 【03x05】参数 how 【03x06】参数 suffixes 【03x07】参数 left_index / right_index 【04x00】join 【05x00】四种方法的区别 Pandas 系列文章: Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象 Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作 Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理 Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引 Python 数据分析三剑客之 Pandas(五):统计计算与统计描述 Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并 Python 数据分析三剑客之 Pandas(七):合并数据集 Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换 Python 数据分析三剑客之 Pandas(九):时间序列 Python 数据分析三剑客之 Pandas(十):数据读写 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106830112未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【01x00】concat pandas.concat 可以沿着指定轴将多个对象堆叠到一起。 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.concat.html 基本语法: pandas.concat(objs: Union[Iterable[‘DataFrame’], Mapping[Optional[Hashable], ‘DataFrame’]], axis='0', join: str = "'outer'", ignore_index: bool = 'False', keys='None', levels='None', names='None', verify_integrity: bool = 'False', sort: bool = 'False', copy: bool = 'True') → ’DataFrame’ pandas.concat(objs: Union[Iterable[FrameOrSeriesUnion], Mapping[Optional[Hashable], FrameOrSeriesUnion]], axis='0', join: str = "'outer'", ignore_index: bool = 'False', keys='None', levels='None', names='None', verify_integrity: bool = 'False', sort: bool = 'False', copy: bool = 'True') → FrameOrSeriesUnion 常用参数描述: 参数描述 objsSeries 或 DataFrame 对象的序列或映射,要合并的对象 axis沿指定轴合并,0 or ‘index’,1 or ‘columns’,只有在 DataFrame 中才有 1 or 'columns’ join如何处理其他轴(或多个轴)上的索引,可取值:‘inner’,‘outer’(默认值) ‘outer’:当 axis = 0 时,列名相同的列会合并,其余列都保留(并集),空值填充; ‘inner’:当 axis = 0 时,列名相同的列会合并,其余列都舍弃(交集) ignore_indexbool 类型,连接后的值是否使用原索引值,如果为 True,则索引将会是 0, 1, …, n-1 keys序列形式,默认 None,传递 keys 后,会构造一个层次索引,即 MultiIndex 对象,keys 为最外层索引 levels用于构造 MultiIndex 的特定级别(唯一值)。未指定则将从键中推断出来 names列表类型,为索引添加标签 verify_integritybool 类型,是否检查合并后的索引有无重复项,设置为 True 若有重复项则会报错 sort当 join='outer' 时对列索引进行排序。当 join='inner' 时此操作无效 合并两个 Series 对象: >>> import pandas as pd>>> obj1 = pd.Series(['a', 'b'])>>> obj2 = pd.Series(['c', 'd'])>>> pd.concat([obj1, obj2])0 a1 b0 c1 ddtype: object 设置 ignore_index=True,放弃原有的索引值: >>> import pandas as pd>>> obj1 = pd.Series(['a', 'b'])>>> obj2 = pd.Series(['c', 'd'])>>> pd.concat([obj1, obj2], ignore_index=True)0 a1 b2 c3 ddtype: object 设置 keys 参数,添加最外层的索引: >>> import pandas as pd>>> obj1 = pd.Series(['a', 'b'])>>> obj2 = pd.Series(['c', 'd'])>>> pd.concat([obj1, obj2], keys=['s1', 's2'])s1 0 a 1 bs2 0 c 1 ddtype: object 设置 names 参数,为索引添加标签: >>> import pandas as pd>>> obj1 = pd.Series(['a', 'b'])>>> obj2 = pd.Series(['c', 'd'])>>> pd.concat([obj1, obj2], keys=['s1', 's2'], names=['Series name', 'Row ID'])Series name Row IDs1 0 a 1 bs2 0 c 1 ddtype: object 合并 DataFrame 对象: >>> import pandas as pd>>> obj1 = pd.DataFrame([['a', 1], ['b', 2]], columns=['letter', 'number'])>>> obj2 = pd.DataFrame([['c', 3], ['d', 4]], columns=['letter', 'number'])>>> obj1 letter number0 a 11 b 2>>> >>> obj2 letter number0 c 31 d 4>>> >>> pd.concat([obj1, obj2]) letter number0 a 11 b 20 c 31 d 4 合并 DataFrame 对象,不存在的值将会被 NaN 填充: >>> import pandas as pd>>> obj1 = pd.DataFrame([['a', 1], ['b', 2]], columns=['letter', 'number'])>>> obj2 = pd.DataFrame([['c', 3, 'cat'], ['d', 4, 'dog']], columns=['letter', 'number', 'animal'])>>> obj1 letter number0 a 11 b 2>>> >>> obj2 letter number animal0 c 3 cat1 d 4 dog>>> >>> pd.concat([obj1, obj2]) letter number animal0 a 1 NaN1 b 2 NaN0 c 3 cat1 d 4 dog 合并 DataFrame 对象,设置 join="inner" 不存在的列将会舍弃: >>> import pandas as pd>>> obj1 = pd.DataFrame([['a', 1], ['b', 2]], columns=['letter', 'number'])>>> obj2 = pd.DataFrame([['c', 3, 'cat'], ['d', 4, 'dog']], columns=['letter', 'number', 'animal'])>>> obj1 letter number0 a 11 b 2>>> >>> obj2 letter number animal0 c 3 cat1 d 4 dog>>> >>> pd.concat([obj1, obj2], join="inner") letter number0 a 11 b 20 c 31 d 4 合并 DataFrame 对象,设置 axis=1 沿 y 轴合并(增加列): >>> import pandas as pd>>> obj1 = pd.DataFrame([['a', 1], ['b', 2]], columns=['letter', 'number'])>>> obj2 = pd.DataFrame([['bird', 'polly'], ['monkey', 'george']], columns=['animal', 'name'])>>> obj1 letter number0 a 11 b 2>>> >>> obj2 animal name0 bird polly1 monkey george>>> >>> pd.concat([obj1, obj2], axis=1) letter number animal name0 a 1 bird polly1 b 2 monkey george 设置 verify_integrity=True ,检查新的索引是否有重复项,有重复项会报错: >>> import pandas as pd>>> obj1 = pd.DataFrame([1], index=['a'])>>> obj2 = pd.DataFrame([2], index=['a'])>>> obj1 0a 1>>> >>> obj2 0a 2>>> >>> pd.concat([obj1, obj2], verify_integrity=True)Traceback (most recent call last): ...ValueError: Indexes have overlapping values: ['a'] 设置 sort=True,会对列索引进行排序输出: >>> obj1 = pd.DataFrame([['a', 3], ['d', 2]], columns=['letter', 'number'])>>> obj2 = pd.DataFrame([['c', 1, 'cat'], ['b', 4, 'dog']], columns=['letter', 'number', 'animal'])>>> obj1 letter number0 a 31 d 2>>> >>> obj2 letter number animal0 c 1 cat1 b 4 dog>>> >>> pd.concat([obj1, obj2], sort=True) animal letter number0 NaN a 31 NaN d 20 cat c 11 dog b 4 【02x00】append Append 方法事实上是在一个 Series / DataFrame 对象后最追加另一个 Series / DataFrame 对象并返回一个新对象,不改变原对象的值。 基本语法: Series.append(self, to_append, ignore_index=False, verify_integrity=False) DataFrame.append(self, other, ignore_index=False, verify_integrity=False, sort=False) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.append.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.append.html 参数描述: 参数描述 to_append / other要追加的数据 ignore_indexbool 类型,连接后的值是否使用原索引值,如果为 True,则索引将会是 0, 1, …, n-1 verify_integritybool 类型,是否检查合并后的索引有无重复项,设置为 True 若有重复项则会报错 sortbool 类型,是否对列索引(columns)进行排序,默认 False 合并 Series 对象: >>> import pandas as pd>>> obj1 = pd.Series([1, 2, 3])>>> obj2 = pd.Series([4, 5, 6])>>> obj3 = pd.Series([4, 5, 6], index=[3, 4, 5])>>> obj10 11 22 3dtype: int64>>> >>> obj20 41 52 6dtype: int64>>> >>> obj33 44 55 6dtype: int64>>> >>> obj1.append(obj2)0 11 22 30 41 52 6dtype: int64>>> >>> obj1.append(obj3)0 11 22 33 44 55 6dtype: int64>>> >>> obj1.append(obj2, ignore_index=True)0 11 22 33 44 55 6dtype: int64>>> >>> obj1.append(obj2, verify_integrity=True)Traceback (most recent call last):...ValueError: Indexes have overlapping values: Int64Index([0, 1, 2], dtype='int64') 合并 DataFrame 对象: >>> import pandas as pd>>> obj1 = pd.DataFrame([[1, 2], [3, 4]], columns=list('AB'))>>> obj2 = pd.DataFrame([[5, 6], [7, 8]], columns=list('AB'))>>> >>> obj1 A B0 1 21 3 4>>> >>> obj2 A B0 5 61 7 8>>> >>> obj1.append(obj2) A B0 1 21 3 40 5 61 7 8>>> >>> obj1.append(obj2, ignore_index=True) A B0 1 21 3 42 5 63 7 8 以下虽然不是生成 DataFrames 的推荐方法,但演示了从多个数据源生成 DataFrames 的两种方法: >>> import pandas as pd>>> obj = pd.DataFrame(columns=['A'])>>> for i in range(5): obj = obj.append({'A': i}, ignore_index=True) >>> obj A0 01 12 23 34 4 >>> import pandas as pd>>> pd.concat([pd.DataFrame([i], columns=['A']) for i in range(5)], ignore_index=True) A0 01 12 23 34 4 【03x00】merge 将不同的数据源进行合并是数据科学中常见的操作,这既包括将两个不同的数据集非常简单地拼接在一起,也包括用数据库那样的连接(join)与合并(merge)操作处理有重叠字段的数据集。Series 与DataFrame 都具备这类操作,Pandas 的函数与方法让数据合并变得快速简单。 数据集的合并(merge)或连接(join)运算是通过一个或多个键将行连接起来的。这些运算是关系型数据库(基于SQL)的核心。Pandas 的 merge 函数是对数据应用这些算法的主要切入点。 pandas.merge 可根据一个或多个连接键将不同 DataFrame 中的行连接起来。 基本语法: pandas.merge(left, right, how: str = 'inner', on=None, left_on=None, right_on=None, left_index: bool = False, right_index: bool = False, sort: bool = False, suffixes='_x', '_y', copy: bool = True, indicator: bool = False, validate=None) → ’DataFrame’ 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.merge.html 常见参数描述: 参数描述 left参与合并的左侧 DataFrame 对象 right参与合并的右侧 DataFrame 对象 how合并方式,默认 'inner' 'inner':内连接,即使用两个对象中都有的键(交集); 'outer':外连接,即使用两个对象中所有的键(并集); 'left':左连接,即使用左对象中所有的键; 'right':右连接,即使用右对象中所有的键; on用于连接的列名。必须存在于左右两个 Dataframe对象中 如果未指定,且其他连接键也未指定,则以 left 和 right 列名的交集作为连接键 left_on左侧 DataFrame 对象中用作连接键的列 right_on右侧 DataFrame 对象中用作连接键的列 left_indexbool 类型,是否使用左侧 DataFrame 对象中的索引(index)作为连接键,默认 False right_indexbool 类型,是否使用右侧 DataFrame 对象中的索引(index)作为连接键,默认 False sortbool 类型,是否在结果中按顺序对连接键排序,默认 False。 如果为 False,则连接键的顺序取决于联接类型(how 关键字) suffixes字符串值元组,用于追加到重叠列名的末尾,默认为 ('_x', '_y')。 例如,如果左右两个 DataFrame 对象都有 data 列时,则结果中就会出现 data_x 和 data_y 【03x01】一对一连接 一对一连接是指两个 DataFrame 对象的列的值没有重复值。 如果不指定任何参数,调用 merge 方法,merge 就会将重叠的列的列名当做键来合并。 在下面的示例中,两个 DataFrame 对象都有一个列名为 key 的列,未指定按照哪一列来合并,merge 就会默认按照 key 来合并: >>> import pandas as pd>>> obj1 = pd.DataFrame({'key': ['b', 'a', 'c'], 'data1': range(3)})>>> obj2 = pd.DataFrame({'key': ['a', 'c', 'b'], 'data2': range(3)})>>> obj1 key data10 b 01 a 12 c 2>>> >>> obj2 key data20 a 01 c 12 b 2>>> >>> pd.merge(obj1, obj2) key data1 data20 b 0 21 a 1 02 c 2 1 【03x02】多对一连接 多对一连接是指两个 DataFrame 对象中,有一个的列的值有重复值。通过多对一连接获得的结果,DataFrame 将会保留重复值。 >>> import pandas as pd>>> obj1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], 'data1': range(7)})>>> obj2 = pd.DataFrame({'key': ['a', 'b', 'd'], 'data2': range(3)})>>> >>> obj1 key data10 b 01 b 12 a 23 c 34 a 45 a 56 b 6>>> >>> obj2 key data20 a 01 b 12 d 2>>> >>> pd.merge(obj1, obj2) key data1 data20 b 0 11 b 1 12 b 6 13 a 2 04 a 4 05 a 5 0 【03x03】多对多连接 多对多连接是指两个 DataFrame 对象中的列的值都有重复值。 >>> import pandas as pd>>> obj1 = pd.DataFrame({'key': ['a', 'b', 'b', 'c'], 'data1': range(4)})>>> obj2 = pd.DataFrame({'key': ['a', 'a', 'b', 'b', 'c', 'c'], 'data2': range(6)})>>> obj1 key data10 a 01 b 12 b 23 c 3>>> >>> obj2 key data20 a 01 a 12 b 23 b 34 c 45 c 5>>> >>> pd.merge(obj1, obj2) key data1 data20 a 0 01 a 0 12 b 1 23 b 1 34 b 2 25 b 2 36 c 3 47 c 3 5 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106830112未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【03x04】参数 on / left_on / right_on 参数 on 用于指定按照某一列来进行合并,若不指定该参数,则会默认按照重叠的列的列名当做键来合并: >>> import pandas as pd>>> obj1 = pd.DataFrame({'key': ['b', 'a', 'c'], 'data1': range(3)})>>> obj2 = pd.DataFrame({'key': ['a', 'c', 'b'], 'data2': range(3)})>>> obj1 key data10 b 01 a 12 c 2>>> >>> obj2 key data20 a 01 c 12 b 2>>> >>> pd.merge(obj1, obj2, on='key') key data1 data20 b 0 21 a 1 02 c 2 1 如果要根据多个键进行合并,传入一个由列名组成的列表即可: >>> import pandas as pd>>> left = pd.DataFrame({'key1': ['foo', 'foo', 'bar'], 'key2': ['one', 'two', 'one'], 'lval': [1, 2, 3]})>>> right = pd.DataFrame({'key1': ['foo', 'foo', 'bar', 'bar'], 'key2': ['one', 'one', 'one', 'two'], 'rval': [4, 5, 6, 7]})>>> left key1 key2 lval0 foo one 11 foo two 22 bar one 3>>> >>> right key1 key2 rval0 foo one 41 foo one 52 bar one 63 bar two 7>>> >>> pd.merge(left, right, on=['key1', 'key2']) key1 key2 lval rval0 foo one 1 41 foo one 1 52 bar one 3 6 如果两个对象的列名不同,就可以使用 left_on、right_on 参数分别进行指定: >>> import pandas as pd>>> obj1 = pd.DataFrame({'lkey': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], 'data1': range(7)})>>> obj2 = pd.DataFrame({'rkey': ['a', 'b', 'd'], 'data2': range(3)})>>> obj1 lkey data10 b 01 b 12 a 23 c 34 a 45 a 56 b 6>>> >>> obj2 rkey data20 a 01 b 12 d 2>>> >>> pd.merge(obj1, obj2, left_on='lkey', right_on='rkey') lkey data1 rkey data20 b 0 b 11 b 1 b 12 b 6 b 13 a 2 a 04 a 4 a 05 a 5 a 0 【03x05】参数 how 在前面的示例中,结果里面 c 和 d 以及与之相关的数据消失了。默认情况下,merge 做的是内连接('inner'),结果中的键是交集。其他方式还有:'left'、'right'、'outer',含义如下: 'inner':内连接,即使用两个对象中都有的键(交集); 'outer':外连接,即使用两个对象中所有的键(并集); 'left':左连接,即使用左对象中所有的键; 'right':右连接,即使用右对象中所有的键; >>> import pandas as pd>>> obj1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], 'data1': range(7)})>>> obj2 = pd.DataFrame({'key': ['a', 'b', 'd'], 'data2': range(3)})>>> obj1 key data10 b 01 b 12 a 23 c 34 a 45 a 56 b 6>>> >>> obj2 key data20 a 01 b 12 d 2>>> >>> pd.merge(obj1, obj2, on='key', how='inner') key data1 data20 b 0 11 b 1 12 b 6 13 a 2 04 a 4 05 a 5 0>>> >>> pd.merge(obj1, obj2, on='key', how='outer') key data1 data20 b 0.0 1.01 b 1.0 1.02 b 6.0 1.03 a 2.0 0.04 a 4.0 0.05 a 5.0 0.06 c 3.0 NaN7 d NaN 2.0>>> >>> pd.merge(obj1, obj2, on='key', how='left') key data1 data20 b 0 1.01 b 1 1.02 a 2 0.03 c 3 NaN4 a 4 0.05 a 5 0.06 b 6 1.0>>> >>> pd.merge(obj1, obj2, on='key', how='right') key data1 data20 b 0.0 11 b 1.0 12 b 6.0 13 a 2.0 04 a 4.0 05 a 5.0 06 d NaN 2 【03x06】参数 suffixes suffixes 参数用于指定附加到左右两个 DataFrame 对象的重叠列名上的字符串: 在以下示例中,选择按照 key1 进行合并,而两个 DataFrame 对象都包含 key2 列,如果未指定 suffixes 参数,则默认会为两个对象的 key2 加上 _x 和 _y,以便区分它们,如果指定了 suffixes 参数,就会按照添加指定的后缀: >>> import pandas as pd>>> left = pd.DataFrame({'key1': ['foo', 'foo', 'bar'], 'key2': ['one', 'two', 'one'], 'lval': [1, 2, 3]})>>> right = pd.DataFrame({'key1': ['foo', 'foo', 'bar', 'bar'], 'key2': ['one', 'one', 'one', 'two'], 'rval': [4, 5, 6, 7]})>>> left key1 key2 lval0 foo one 11 foo two 22 bar one 3>>> >>> right key1 key2 rval0 foo one 41 foo one 52 bar one 63 bar two 7>>> >>> pd.merge(left, right, on='key1') key1 key2_x lval key2_y rval0 foo one 1 one 41 foo one 1 one 52 foo two 2 one 43 foo two 2 one 54 bar one 3 one 65 bar one 3 two 7>>> >>> pd.merge(left, right, on='key1', suffixes=('_left', '_right')) key1 key2_left lval key2_right rval0 foo one 1 one 41 foo one 1 one 52 foo two 2 one 43 foo two 2 one 54 bar one 3 one 65 bar one 3 two 7 【03x07】参数 left_index / right_index 有时候,DataFrame 中的连接键位于其索引中。在这种情况下,可以使用 left_index=True 或right_index=True(或两个都传)以说明索引应该被用作连接键。这种方法称为按索引连接,在 Pandas 中还有个 join 方法可以实现这个功能。 在以下示例中,按照 left 的 key 列进行连接,而 right 对象的连接键位于其索引中,因此要指定 right_index=True: >>> import pandas as pd>>> left = pd.DataFrame({'key': ['a', 'b', 'a', 'a', 'b', 'c'], 'value': range(6)})>>> right = pd.DataFrame({'group_val': [3.5, 7]}, index=['a', 'b'])>>> left key value0 a 01 b 12 a 23 a 34 b 45 c 5>>> >>> right group_vala 3.5b 7.0>>> >>> pd.merge(left, right, left_on='key', right_index=True) key value group_val0 a 0 3.52 a 2 3.53 a 3 3.51 b 1 7.04 b 4 7.0 【04x00】join join 方法只适用于 DataFrame 对象,Series 对象没有该方法,该方法用于连接另一个 DataFrame 对象的列(columns)。 基本语法:DataFrame.join(self, other, on=None, how='left', lsuffix='', rsuffix='', sort=False) → ’DataFrame’ 参数描述: 参数描述 other另一个 DataFrame、Series 或 DataFrame 列表对象 on列名称,或者列名称组成的列表、元组,连接的列 how合并方式,默认 'left' 'inner':内连接,即使用两个对象中都有的键(交集); 'outer':外连接,即使用两个对象中所有的键(并集); 'left':左连接,即使用左对象中所有的键; 'right':右连接,即使用右对象中所有的键; lsuffix当两个对象有相同的列名时,合并后左边数据列名的后缀 rsuffix当两个对象有相同的列名时,合并后右边数据列名的后缀 sortbool 类型,是否在结果中按顺序对连接键排序,默认 False。 如果为 False,则连接键的顺序取决于联接类型(how 关键字) 使用 lsuffix 和 rsuffix 参数: >>> import pandas as pd>>> obj = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3', 'K4', 'K5'], 'A': ['A0', 'A1', 'A2', 'A3', 'A4', 'A5']})>>> other = pd.DataFrame({'key': ['K0', 'K1', 'K2'], 'B': ['B0', 'B1', 'B2']})>>> obj key A0 K0 A01 K1 A12 K2 A23 K3 A34 K4 A45 K5 A5>>> >>> other key B0 K0 B01 K1 B12 K2 B2>>> >>> obj.join(other, lsuffix='_1', rsuffix='_2') key_1 A key_2 B0 K0 A0 K0 B01 K1 A1 K1 B12 K2 A2 K2 B23 K3 A3 NaN NaN4 K4 A4 NaN NaN5 K5 A5 NaN NaN 如果右表的索引是左表的某一列的值,这时可以将右表的索引和左表的列对齐合并这样的灵活方式进行合并: >>> import pandas as pd>>> obj = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'], 'B': ['B0', 'B1', 'B2', 'B3'],'key': ['K0', 'K1', 'K0', 'K1']})>>> other = pd.DataFrame({'C': ['C0', 'C1'],'D': ['D0', 'D1']},index=['K0', 'K1'])>>> obj A B key0 A0 B0 K01 A1 B1 K12 A2 B2 K03 A3 B3 K1>>> >>> other C DK0 C0 D0K1 C1 D1>>> >>> obj.join(other, on='key') A B key C D0 A0 B0 K0 C0 D01 A1 B1 K1 C1 D12 A2 B2 K0 C0 D03 A3 B3 K1 C1 D1 【05x00】四种方法的区别 concat:可用于两个或多个 Series 或 DataFrame 对象间,通过 axis 参数指定按照行方向(增加行)或列方向(增加列)进合并操作,默认行合并(增加行),取并集; append:在一个 Series 或 DataFrame 对象后最追加另一个 Series 或 DataFrame 对象并返回一个新对象,不改变原对象的值。只能按行合并(增加行)。 merge:只能对两个 DataFrame 对象进行合并,一般按照列方向(增加列)进行合并操作,按照行方向合并一般用 join 方法代替,默认列合并(增加列),取交集; join:只能对两个 DataFrame 对象进行合并,按照列方向(增加列)进行合并操作,默认左连接。 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106830112未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【01x00】GroupBy 机制 【02x00】GroupBy 对象 【03x00】GroupBy Split 数据分裂 【03x01】分组运算 【03x02】按类型按列分组 【03x03】自定义分组 【03x03x01】字典分组 【03x03x02】函数分组 【03x03x03】索引层级分组 【03x04】分组迭代 【03x05】对象转换 【04x00】GroupBy Apply 数据应用 【04x01】聚合函数 【04x02】自定义函数 【04x03】对不同列作用不同函数 【04x04】GroupBy.apply() Pandas 系列文章: Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象 Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作 Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理 Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引 Python 数据分析三剑客之 Pandas(五):统计计算与统计描述 Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并 Python 数据分析三剑客之 Pandas(七):合并数据集 Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换 Python 数据分析三剑客之 Pandas(九):时间序列 Python 数据分析三剑客之 Pandas(十):数据读写 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106804881未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【01x00】GroupBy 机制 对数据集进行分组并对各组应用一个函数(无论是聚合还是转换),通常是数据分析工作中的重要环节。在将数据集加载、融合、准备好之后,通常就是计算分组统计或生成透视表。Pandas 提供了一个灵活高效的 GroupBy 功能,虽然“分组”(group by)这个名字是借用 SQL 数据库语言的命令,但其理念引用发明 R 语言 frame 的 Hadley Wickham 的观点可能更合适:分裂(Split)、应用(Apply)和组合(Combine)。 分组运算过程:Split —> Apply —> Combine 分裂(Split):根据某些标准将数据分组; 应用(Apply):对每个组独立应用一个函数; 合并(Combine):把每个分组的计算结果合并起来。 官方介绍:https://pandas.pydata.org/docs/user_guide/groupby.html 【02x00】GroupBy 对象 常见的 GroupBy 对象:Series.groupby、DataFrame.groupby,基本语法如下: Series.groupby(self, by=None, axis=0, level=None, as_index: bool = True, sort: bool = True, group_keys: bool = True, squeeze: bool = False, observed: bool = False) → ’groupby_generic.SeriesGroupBy’ DataFrame.groupby(self, by=None, axis=0, level=None, as_index: bool = True, sort: bool = True, group_keys: bool = True, squeeze: bool = False, observed: bool = False) → ’groupby_generic.DataFrameGroupBy’ 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.groupby.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.groupby.html 常用参数解释如下: 参数描述 by映射、函数、标签或标签列表,用于确定分组依据的分组。如果 by 是函数,则会在对象索引的每个值上调用它。 如果传递了 dict 或 Series,则将使用 Series 或 dict 的值来确定组(将 Series 的值首先对齐;请参见.align() 方法)。 如果传递了 ndarray,则按原样使用这些值来确定组。标签或标签列表可以按自身中的列传递给分组。 注意,元组被解释为(单个)键 axis沿指定轴拆分,默认 0,0 or ‘index’,1 or ‘columns’,只有在 DataFrame 中才有 1 or 'columns’ level如果轴是 MultiIndex(层次结构),则按特定层级进行分组,默认 None as_indexbool 类型,默认 True,对于聚合输出,返回以组标签为索引的对象。仅与 DataFrame 输入相关。 as_index=False 实际上是“SQL样式”分组输出 sortbool 类型,默认 True,对组键排序。关闭此选项可获得更好的性能。注:这不影响每组的观察顺序。Groupby 保留每个组中行的顺序 group_keysbool 类型,默认 True,调用 apply 方法时,是否将组键(keys)添加到索引( index)以标识块 squeezebool 类型,默认 False,如果可能,减少返回类型的维度,否则返回一致的类型 groupby() 进行分组,GroupBy 对象没有进行实际运算,只是包含分组的中间数据,示例如下: >>> import pandas as pd>>> import numpy as np>>> data = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], 'data1': np.random.randn(8), 'data2': np.random.randn(8)}>>> >>> obj = pd.DataFrame(data)>>> obj key1 key2 data1 data20 a one -0.804160 -0.8689051 b one -0.086990 0.3257412 a two 0.757992 0.5411013 b three -0.281435 0.0978414 a two 0.817757 -0.6436995 b two -0.462760 -0.3211966 a one -0.403699 0.6021387 a three 0.883940 -0.850526>>> >>> obj.groupby('key1')<pandas.core.groupby.generic.DataFrameGroupBy object at 0x03CDB7C0>>>> >>> obj['data1'].groupby(obj['key1'])<pandas.core.groupby.generic.SeriesGroupBy object at 0x03CDB748> 【03x00】GroupBy Split 数据分裂 【03x01】分组运算 前面通过 groupby() 方法获得了一个 GroupBy 对象,它实际上还没有进行任何计算,只是含有一些有关分组键 obj['key1'] 的中间数据而已。换句话说,该对象已经有了接下来对各分组执行运算所需的一切信息。例如,我们可以调用 GroupBy 的 mean() 方法来计算分组平均值,size() 方法返回每个分组的元素个数: >>> import pandas as pd>>> import numpy as np>>> data = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], 'data1': np.random.randn(8), 'data2': np.random.randn(8)}>>> >>> obj = pd.DataFrame(data)>>> obj key1 key2 data1 data20 a one -0.544099 -0.6140791 b one 2.193712 0.1010052 a two -0.004683 0.8827703 b three 0.312858 1.7321054 a two 0.011089 0.0895875 b two 0.292165 1.3276386 a one -1.433291 -0.2389717 a three -0.004724 -2.117326>>> >>> grouped1 = obj.groupby('key1')>>> grouped2 = obj['data1'].groupby(obj['key1'])>>> >>> grouped1.mean() data1 data2key1 a -0.395142 -0.399604b 0.932912 1.053583>>> >>> grouped2.mean()key1a -0.395142b 0.932912Name: data1, dtype: float64>>>>>> grouped1.size()key1a 5b 3dtype: int64>>> >>> grouped2.size()key1a 5b 3Name: data1, dtype: int64 【03x02】按类型按列分组 groupby() 方法 axis 参数默认是 0,通过设置也可以在其他任何轴上进行分组,也支持按照类型(dtype)进行分组: >>> import pandas as pd>>> import numpy as np>>> data = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], 'data1': np.random.randn(8), 'data2': np.random.randn(8)}>>> obj = pd.DataFrame(data)>>> obj key1 key2 data1 data20 a one -0.607009 1.9483011 b one 0.150818 -0.0250952 a two -2.086024 0.3581643 b three 0.446061 1.7087974 a two 0.745457 -0.9809485 b two 0.981877 2.1593276 a one 0.804480 -0.4996617 a three 0.112884 0.004367>>> >>> obj.dtypeskey1 objectkey2 objectdata1 float64data2 float64dtype: object>>> >>> obj.groupby(obj.dtypes, axis=1).size()float64 2object 2dtype: int64>>> >>> obj.groupby(obj.dtypes, axis=1).sum() float64 object0 1.341291 aone1 0.125723 bone2 -1.727860 atwo3 2.154858 bthree4 -0.235491 atwo5 3.141203 btwo6 0.304819 aone7 0.117251 athree 【03x03】自定义分组 groupby() 方法中可以一次传入多个数组的列表,也可以自定义一组分组键。也可以通过一个字典、一个函数,或者按照索引层级进行分组。 传入多个数组的列表: >>> import pandas as pd>>> import numpy as np>>> data = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], 'data1': np.random.randn(8), 'data2': np.random.randn(8)}>>> obj = pd.DataFrame(data)>>> obj key1 key2 data1 data20 a one -0.841652 0.6880551 b one 0.510042 -0.5611712 a two -0.418862 -0.1459833 b three -1.104698 0.5631584 a two 0.329527 -0.8931085 b two 0.753653 -0.3425206 a one -0.882527 -1.1213297 a three 1.726794 0.160244>>> >>> means = obj['data1'].groupby([obj['key1'], obj['key2']]).mean()>>> meanskey1 key2 a one -0.862090 three 1.726794 two -0.044667b one 0.510042 three -1.104698 two 0.753653Name: data1, dtype: float64>>> >>> means.unstack()key2 one three twokey1 a -0.862090 1.726794 -0.044667b 0.510042 -1.104698 0.753653 自定义分组键: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame({'key1' : ['a', 'a', 'b', 'b', 'a'], 'key2' : ['one', 'two', 'one', 'two', 'one'], 'data1' : np.random.randn(5), 'data2' : np.random.randn(5)})>>> obj key1 key2 data1 data20 a one -0.024003 0.3504801 a two -0.767534 -0.1004262 b one -0.594983 -1.9455803 b two -0.374482 0.8175924 a one 0.755452 -0.137759>>> >>> states = np.array(['Wuhan', 'Beijing', 'Beijing', 'Wuhan', 'Wuhan'])>>> years = np.array([2005, 2005, 2006, 2005, 2006])>>> >>> obj['data1'].groupby([states, years]).mean()Beijing 2005 -0.767534 2006 -0.594983Wuhan 2005 -0.199242 2006 0.755452Name: data1, dtype: float64 【03x03x01】字典分组 通过字典进行分组: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame(np.random.randint(1, 10, (5,5)), columns=['a', 'b', 'c', 'd', 'e'], index=['A', 'B', 'C', 'D', 'E'])>>> obj a b c d eA 1 4 7 1 9B 8 2 4 7 8C 9 8 2 5 1D 2 4 2 8 3E 7 5 7 2 3>>> >>> obj_dict = {'a':'Python', 'b':'Python', 'c':'Java', 'd':'C++', 'e':'Java'}>>> obj.groupby(obj_dict, axis=1).size()C++ 1Java 2Python 2dtype: int64>>> >>> obj.groupby(obj_dict, axis=1).count() C++ Java PythonA 1 2 2B 1 2 2C 1 2 2D 1 2 2E 1 2 2>>> >>> obj.groupby(obj_dict, axis=1).sum() C++ Java PythonA 1 16 5B 7 12 10C 5 3 17D 8 5 6E 2 10 12 【03x03x02】函数分组 通过函数进行分组: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame(np.random.randint(1, 10, (5,5)), columns=['a', 'b', 'c', 'd', 'e'], index=['AA', 'BBB', 'CC', 'D', 'EE'])>>> obj a b c d eAA 3 9 5 8 2BBB 1 4 2 2 6CC 9 2 4 7 6D 2 5 5 7 1EE 8 8 8 2 2>>> >>> def group_key(idx): """ idx 为列索引或行索引 """ return len(idx)>>> obj.groupby(group_key).size() # 等价于 obj.groupby(len).size()1 12 33 1dtype: int64 【03x03x03】索引层级分组 通过不同索引层级进行分组: >>> import pandas as pd>>> import numpy as np>>> columns = pd.MultiIndex.from_arrays([['Python', 'Java', 'Python', 'Java', 'Python'], ['A', 'A', 'B', 'C', 'B']], names=['language', 'index'])>>> obj = pd.DataFrame(np.random.randint(1, 10, (5, 5)), columns=columns)>>> objlanguage Python Java Python Java Pythonindex A A B C B0 7 1 9 8 51 4 5 4 5 62 4 3 1 9 53 6 6 3 8 14 7 9 2 8 2>>> >>> obj.groupby(level='language', axis=1).sum()language Java Python0 9 211 10 142 12 103 14 104 17 11>>> >>> obj.groupby(level='index', axis=1).sum()index A B C0 8 14 81 9 10 52 7 6 93 12 4 84 16 4 8 【03x04】分组迭代 GroupBy 对象支持迭代,对于单层分组,可以产生一组二元元组,由分组名和数据块组成: >>> import pandas as pd>>> import numpy as np>>> data = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], 'data1': np.random.randn(8), 'data2': np.random.randn(8)}>>> obj = pd.DataFrame(data)>>> obj key1 key2 data1 data20 a one -1.088762 0.6685041 b one 0.275500 0.7878442 a two -0.108417 -0.4912963 b three 0.019524 -0.3633904 a two 0.453612 0.7969995 b two 1.982858 1.5018776 a one 1.101132 -1.9283627 a three 0.524775 -1.205842>>> >>> for group_name, group_data in obj.groupby('key1'): print(group_name) print(group_data) a key1 key2 data1 data20 a one -1.088762 0.6685042 a two -0.108417 -0.4912964 a two 0.453612 0.7969996 a one 1.101132 -1.9283627 a three 0.524775 -1.205842b key1 key2 data1 data21 b one 0.275500 0.7878443 b three 0.019524 -0.3633905 b two 1.982858 1.501877 对于多层分组,元组的第一个元素将会是由键值组成的元组,第二个元素为数据块: >>> import pandas as pd>>> import numpy as np>>> data = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], 'data1': np.random.randn(8), 'data2': np.random.randn(8)}>>> obj = pd.DataFrame(data)>>> obj key1 key2 data1 data20 a one -1.088762 0.6685041 b one 0.275500 0.7878442 a two -0.108417 -0.4912963 b three 0.019524 -0.3633904 a two 0.453612 0.7969995 b two 1.982858 1.5018776 a one 1.101132 -1.9283627 a three 0.524775 -1.205842>>> >>> for group_name, group_data in obj.groupby(['key1', 'key2']): print(group_name) print(group_data) ('a', 'one') key1 key2 data1 data20 a one -1.088762 0.6685046 a one 1.101132 -1.928362('a', 'three') key1 key2 data1 data27 a three 0.524775 -1.205842('a', 'two') key1 key2 data1 data22 a two -0.108417 -0.4912964 a two 0.453612 0.796999('b', 'one') key1 key2 data1 data21 b one 0.2755 0.787844('b', 'three') key1 key2 data1 data23 b three 0.019524 -0.36339('b', 'two') key1 key2 data1 data25 b two 1.982858 1.501877 【03x05】对象转换 GroupBy 对象支持转换成列表或字典: >>> import pandas as pd>>> import numpy as np>>> data = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], 'data1': np.random.randn(8), 'data2': np.random.randn(8)}>>> obj = pd.DataFrame(data)>>> obj key1 key2 data1 data20 a one -0.607009 1.9483011 b one 0.150818 -0.0250952 a two -2.086024 0.3581643 b three 0.446061 1.7087974 a two 0.745457 -0.9809485 b two 0.981877 2.1593276 a one 0.804480 -0.4996617 a three 0.112884 0.004367>>> >>> grouped = obj.groupby('key1')>>> list(grouped)[('a', key1 key2 data1 data20 a one -0.607009 1.9483012 a two -2.086024 0.3581644 a two 0.745457 -0.9809486 a one 0.804480 -0.4996617 a three 0.112884 0.004367),('b', key1 key2 data1 data21 b one 0.150818 -0.0250953 b three 0.446061 1.7087975 b two 0.981877 2.159327)]>>>>>> dict(list(grouped)){'a': key1 key2 data1 data20 a one -0.607009 1.9483012 a two -2.086024 0.3581644 a two 0.745457 -0.9809486 a one 0.804480 -0.4996617 a three 0.112884 0.004367,'b': key1 key2 data1 data21 b one 0.150818 -0.0250953 b three 0.446061 1.7087975 b two 0.981877 2.159327} 【04x00】GroupBy Apply 数据应用 聚合指的是任何能够从数组产生标量值的数据转换过程,常用于对分组后的数据进行计算 【04x01】聚合函数 之前的例子已经用过一些内置的聚合函数,比如 mean、count、min 以及 sum 等。常见的聚合运算如下表所示: 官方文档:https://pandas.pydata.org/docs/reference/groupby.html 方法描述 count非NA值的数量 describe针对Series或各DataFrame列计算汇总统计 min计算最小值 max计算最大值 argmin计算能够获取到最小值的索引位置(整数) argmax计算能够获取到最大值的索引位置(整数) idxmin计算能够获取到最小值的索引值 idxmax计算能够获取到最大值的索引值 quantile计算样本的分位数(0到1) sum值的总和 mean值的平均数 median值的算术中位数(50%分位数) mad根据平均值计算平均绝对离差 var样本值的方差 std样本值的标准差 应用示例: >>> import pandas as pd>>> import numpy as np>>> obj = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], 'data1': np.random.randint(1,10, 8), 'data2': np.random.randint(1,10, 8)}>>> obj = pd.DataFrame(obj)>>> obj key1 key2 data1 data20 a one 9 71 b one 5 92 a two 2 43 b three 3 44 a two 5 15 b two 5 96 a one 1 87 a three 2 4>>> >>> obj.groupby('key1').sum() data1 data2key1 a 19 24b 13 22>>> >>> obj.groupby('key1').max() key2 data1 data2key1 a two 9 8b two 5 9>>> >>> obj.groupby('key1').min() key2 data1 data2key1 a one 1 1b one 3 4>>> >>> obj.groupby('key1').mean() data1 data2key1 a 3.800000 4.800000b 4.333333 7.333333>>> >>> obj.groupby('key1').size()key1a 5b 3dtype: int64>>> >>> obj.groupby('key1').count() key2 data1 data2key1 a 5 5 5b 3 3 3>>> >>> obj.groupby('key1').describe() data1 ... data2 count mean std min 25% ... min 25% 50% 75% maxkey1 ... a 5.0 3.800000 3.271085 1.0 2.0 ... 1.0 4.0 4.0 7.0 8.0b 3.0 4.333333 1.154701 3.0 4.0 ... 4.0 6.5 9.0 9.0 9.0[2 rows x 16 columns] 【04x02】自定义函数 如果自带的内置函数满足不了我们的要求,则可以自定义一个聚合函数,然后传入 GroupBy.agg(func) 或 GroupBy.aggregate(func) 方法中即可。func 的参数为 groupby 索引对应的记录。 >>> import pandas as pd>>> import numpy as np>>> obj = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], 'data1': np.random.randint(1,10, 8), 'data2': np.random.randint(1,10, 8)}>>> obj = pd.DataFrame(obj)>>> obj key1 key2 data1 data20 a one 9 71 b one 5 92 a two 2 43 b three 3 44 a two 5 15 b two 5 96 a one 1 87 a three 2 4>>> >>> def peak_range(df): return df.max() - df.min()>>> >>> obj.groupby('key1').agg(peak_range) data1 data2key1 a 8 7b 2 5>>> >>> obj.groupby('key1').agg(lambda df : df.max() - df.min()) data1 data2key1 a 8 7b 2 5 【04x03】对不同列作用不同函数 使用字典可以对不同列作用不同的聚合函数: >>> import pandas as pd>>> import numpy as np>>> obj = {'key1' : ['a', 'b', 'a', 'b', 'a', 'b', 'a', 'a'], 'key2' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], 'data1': np.random.randint(1,10, 8), 'data2': np.random.randint(1,10, 8)}>>> obj = pd.DataFrame(obj)>>> obj key1 key2 data1 data20 a one 9 71 b one 5 92 a two 2 43 b three 3 44 a two 5 15 b two 5 96 a one 1 87 a three 2 4>>> >>> dict1 = {'data1':'mean', 'data2':'sum'}>>> dict2 = {'data1':['mean','max'], 'data2':'sum'}>>> >>> obj.groupby('key1').agg(dict1) data1 data2key1 a 3.800000 24b 4.333333 22>>> >>> obj.groupby('key1').agg(dict2) data1 data2 mean max sumkey1 a 3.800000 9 24b 4.333333 5 22 【04x04】GroupBy.apply() apply() 方法会将待处理的对象拆分成多个片段,然后对各片段调用传入的函数,最后尝试将各片段组合到一起。 >>> import pandas as pd>>> obj = pd.DataFrame({'A':['bob','sos','bob','sos','bob','sos','bob','bob'], 'B':['one','one','two','three','two','two','one','three'], 'C':[3,1,4,1,5,9,2,6], 'D':[1,2,3,4,5,6,7,8]})>>> obj A B C D0 bob one 3 11 sos one 1 22 bob two 4 33 sos three 1 44 bob two 5 55 sos two 9 66 bob one 2 77 bob three 6 8>>> >>> grouped = obj.groupby('A')>>> for name, group in grouped: print(name) print(group) bob A B C D0 bob one 3 12 bob two 4 34 bob two 5 56 bob one 2 77 bob three 6 8sos A B C D1 sos one 1 23 sos three 1 45 sos two 9 6>>> >>> grouped.apply(lambda x:x.describe()) # 对 bob 和 sos 两组数据使用 describe 方法 C DA bob count 5.000000 5.000000 mean 4.000000 4.800000 std 1.581139 2.863564 min 2.000000 1.000000 25% 3.000000 3.000000 50% 4.000000 5.000000 75% 5.000000 7.000000 max 6.000000 8.000000sos count 3.000000 3.000000 mean 3.666667 4.000000 std 4.618802 2.000000 min 1.000000 2.000000 25% 1.000000 3.000000 50% 1.000000 4.000000 75% 5.000000 5.000000 max 9.000000 6.000000>>>>>> grouped.apply(lambda x:x.min()) # # 对 bob 和 sos 两组数据使用 min 方法 A B C DA bob bob one 2 1sos sos one 1 2 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106804881未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【01x00】统计计算 【01x01】sum() 求和 【01x02】min() 最小值 【01x03】max() 最大值 【01x04】mean() 平均值 【01x05】idxmin() 最小值索引 【01x06】idxmax() 最大值索引 【02x00】统计描述 【03x00】常用统计方法 Pandas 系列文章: Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象 Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作 Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理 Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引 Python 数据分析三剑客之 Pandas(五):统计计算与统计描述 Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并 Python 数据分析三剑客之 Pandas(七):合并数据集 Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换 Python 数据分析三剑客之 Pandas(九):时间序列 Python 数据分析三剑客之 Pandas(十):数据读写 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106788501未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【01x00】统计计算 Pandas 对象拥有一组常用的数学和统计方法。它们大部分都属于约简和汇总统计,用于从 Series 中提取单个值(如 sum 或 mean)或从 DataFrame 的行或列中提取一个 Series。跟对应的 NumPy 数组方法相比,它们都是基于没有缺失数据的假设而构建的。 【01x01】sum() 求和 sum() 方法用于返回指定轴的和,相当于 numpy.sum()。 在 Series 和 DataFrame 中的基本语法如下: Series.sum(self, axis=None, skipna=None, level=None, numeric_only=None, min_count=0, **kwargs) DataFrame.sum(self, axis=None, skipna=None, level=None, numeric_only=None, min_count=0, **kwargs) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.sum.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.sum.html 常用参数描述如下: 参数描述 axis指定轴求和,0 or ‘index’,1 or ‘columns’,只有在 DataFrame 中才有 1 or 'columns’ skipnabool 类型,求和时是否排除缺失值(NA/null),默认 True level如果轴是 MultiIndex(层次结构),则沿指定层次求和 在 Series 中的应用: >>> import pandas as pd>>> idx = pd.MultiIndex.from_arrays([ ['warm', 'warm', 'cold', 'cold'], ['dog', 'falcon', 'fish', 'spider']], names=['blooded', 'animal'])>>> obj = pd.Series([4, 2, 0, 8], name='legs', index=idx)>>> objblooded animalwarm dog 4 falcon 2cold fish 0 spider 8Name: legs, dtype: int64>>> >>> obj.sum()14>>> >>> obj.sum(level='blooded')bloodedwarm 6cold 8Name: legs, dtype: int64>>> >>> obj.sum(level=0)bloodedwarm 6cold 8Name: legs, dtype: int64 在 DataFrame 中的应用: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame([[1.4, np.nan], [7.1, -4.5], [np.nan, np.nan], [0.75, -1.3]], index=['a', 'b', 'c', 'd'], columns=['one', 'two'])>>> obj one twoa 1.40 NaNb 7.10 -4.5c NaN NaNd 0.75 -1.3>>> >>> obj.sum()one 9.25two -5.80dtype: float64>>> >>> obj.sum(axis=1)a 1.40b 2.60c 0.00d -0.55dtype: float64 【01x02】min() 最小值 min() 方法用于返回指定轴的最小值。 在 Series 和 DataFrame 中的基本语法如下: Series.min(self, axis=None, skipna=None, level=None, numeric_only=None, **kwargs) DataFrame.min(self, axis=None, skipna=None, level=None, numeric_only=None, **kwargs) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.min.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.min.html 常用参数描述如下: 参数描述 axis指定轴求最小值,0 or ‘index’,1 or ‘columns’,只有在 DataFrame 中才有 1 or 'columns’ skipnabool 类型,求最小值时是否排除缺失值(NA/null),默认 True level如果轴是 MultiIndex(层次结构),则沿指定层次求最小值 在 Series 中的应用: >>> import pandas as pd>>> idx = pd.MultiIndex.from_arrays([ ['warm', 'warm', 'cold', 'cold'], ['dog', 'falcon', 'fish', 'spider']], names=['blooded', 'animal'])>>> obj = pd.Series([4, 2, 0, 8], name='legs', index=idx)>>> objblooded animalwarm dog 4 falcon 2cold fish 0 spider 8Name: legs, dtype: int64>>> >>> obj.min()0>>> >>> obj.min(level='blooded')bloodedwarm 2cold 0Name: legs, dtype: int64>>> >>> obj.min(level=0)bloodedwarm 2cold 0Name: legs, dtype: int64 在 DataFrame 中的应用: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame([[1.4, np.nan], [7.1, -4.5], [np.nan, np.nan], [0.75, -1.3]], index=['a', 'b', 'c', 'd'],columns=['one', 'two'])>>> obj one twoa 1.40 NaNb 7.10 -4.5c NaN NaNd 0.75 -1.3>>> >>> obj.min()one 0.75two -4.50dtype: float64>>> >>> obj.min(axis=1)a 1.4b -4.5c NaNd -1.3dtype: float64>>> >>> obj.min(axis='columns', skipna=False)a NaNb -4.5c NaNd -1.3dtype: float64 【01x03】max() 最大值 max() 方法用于返回指定轴的最大值。 在 Series 和 DataFrame 中的基本语法如下: Series.max(self, axis=None, skipna=None, level=None, numeric_only=None, **kwargs) DataFrame.max(self, axis=None, skipna=None, level=None, numeric_only=None, **kwargs) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.max.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.max.html 常用参数描述如下: 参数描述 axis指定轴求最大值,0 or ‘index’,1 or ‘columns’,只有在 DataFrame 中才有 1 or 'columns’ skipnabool 类型,求最大值时是否排除缺失值(NA/null),默认 True level如果轴是 MultiIndex(层次结构),则沿指定层次求最大值 在 Series 中的应用: >>> import pandas as pd>>> idx = pd.MultiIndex.from_arrays([ ['warm', 'warm', 'cold', 'cold'], ['dog', 'falcon', 'fish', 'spider']], names=['blooded', 'animal'])>>> obj = pd.Series([4, 2, 0, 8], name='legs', index=idx)>>> objblooded animalwarm dog 4 falcon 2cold fish 0 spider 8Name: legs, dtype: int64>>> >>> obj.max()8>>> >>> obj.max(level='blooded')bloodedwarm 4cold 8Name: legs, dtype: int64>>> >>> obj.max(level=0)bloodedwarm 4cold 8Name: legs, dtype: int64 在 DataFrame 中的应用: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame([[1.4, np.nan], [7.1, -4.5], [np.nan, np.nan], [0.75, -1.3]], index=['a', 'b', 'c', 'd'],columns=['one', 'two'])>>> obj one twoa 1.40 NaNb 7.10 -4.5c NaN NaNd 0.75 -1.3>>> >>> obj.max()one 7.1two -1.3dtype: float64>>> >>> obj.max(axis=1)a 1.40b 7.10c NaNd 0.75dtype: float64>>> >>> obj.max(axis='columns', skipna=False)a NaNb 7.10c NaNd 0.75dtype: float64 【01x04】mean() 平均值 mean() 方法用于返回指定轴的平均值。 在 Series 和 DataFrame 中的基本语法如下: Series.mean(self, axis=None, skipna=None, level=None, numeric_only=None, **kwargs) DataFrame.mean(self, axis=None, skipna=None, level=None, numeric_only=None, **kwargs) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.mean.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.mean.html 常用参数描述如下: 参数描述 axis指定轴求平均值,0 or ‘index’,1 or ‘columns’,只有在 DataFrame 中才有 1 or 'columns’ skipnabool 类型,求平均值时是否排除缺失值(NA/null),默认 True level如果轴是 MultiIndex(层次结构),则沿指定层次求平均值 在 Series 中的应用: >>> import pandas as pd>>> idx = pd.MultiIndex.from_arrays([ ['warm', 'warm', 'cold', 'cold'], ['dog', 'falcon', 'fish', 'spider']], names=['blooded', 'animal'])>>> obj = pd.Series([4, 2, 0, 8], name='legs', index=idx)>>> objblooded animalwarm dog 4 falcon 2cold fish 0 spider 8Name: legs, dtype: int64>>> >>> obj.mean()3.5>>> >>> obj.mean(level='blooded')bloodedwarm 3cold 4Name: legs, dtype: int64>>> >>> obj.mean(level=0)bloodedwarm 3cold 4Name: legs, dtype: int64 在 DataFrame 中的应用: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame([[1.4, np.nan], [7.1, -4.5], [np.nan, np.nan], [0.75, -1.3]], index=['a', 'b', 'c', 'd'],columns=['one', 'two'])>>> obj one twoa 1.40 NaNb 7.10 -4.5c NaN NaNd 0.75 -1.3>>> >>> obj.mean()one 3.083333two -2.900000dtype: float64>>> >>> obj.mean(axis=1)a 1.400b 1.300c NaNd -0.275dtype: float64>>> >>> obj.mean(axis='columns', skipna=False)a NaNb 1.300c NaNd -0.275dtype: float64 【01x05】idxmin() 最小值索引 idxmin() 方法用于返回最小值的索引。 在 Series 和 DataFrame 中的基本语法如下: Series.idxmin(self, axis=0, skipna=True, *args, **kwargs) DataFrame.idxmin(self, axis=0, skipna=True) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.idxmin.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.idxmin.html 常用参数描述如下: 参数描述 axis指定轴,0 or ‘index’,1 or ‘columns’,只有在 DataFrame 中才有 1 or 'columns’ skipnabool 类型,是否排除缺失值(NA/null),默认 True 在 Series 中的应用: >>> import pandas as pd>>> idx = pd.MultiIndex.from_arrays([ ['warm', 'warm', 'cold', 'cold'], ['dog', 'falcon', 'fish', 'spider']], names=['blooded', 'animal'])>>> obj = pd.Series([4, 2, 0, 8], name='legs', index=idx)>>> objblooded animalwarm dog 4 falcon 2cold fish 0 spider 8Name: legs, dtype: int64>>> >>> obj.idxmin()('cold', 'fish') 在 DataFrame 中的应用: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame([[1.4, np.nan], [7.1, -4.5], [np.nan, np.nan], [0.75, -1.3]], index=['a', 'b', 'c', 'd'],columns=['one', 'two'])>>> obj one twoa 1.40 NaNb 7.10 -4.5c NaN NaNd 0.75 -1.3>>> >>> obj.idxmin()one dtwo bdtype: object 【01x06】idxmax() 最大值索引 idxmax() 方法用于返回最大值的索引。 在 Series 和 DataFrame 中的基本语法如下: Series.idxmax(self, axis=0, skipna=True, *args, **kwargs) DataFrame.idxmax(self, axis=0, skipna=True) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.idxmax.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.idxmax.html 常用参数描述如下: 参数描述 axis指定轴,0 or ‘index’,1 or ‘columns’,只有在 DataFrame 中才有 1 or 'columns’ skipnabool 类型,是否排除缺失值(NA/null),默认 True 在 Series 中的应用: >>> import pandas as pd>>> idx = pd.MultiIndex.from_arrays([ ['warm', 'warm', 'cold', 'cold'], ['dog', 'falcon', 'fish', 'spider']], names=['blooded', 'animal'])>>> obj = pd.Series([4, 2, 0, 8], name='legs', index=idx)>>> objblooded animalwarm dog 4 falcon 2cold fish 0 spider 8Name: legs, dtype: int64>>> >>> obj.idxmax()('cold', 'spider') 在 DataFrame 中的应用: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame([[1.4, np.nan], [7.1, -4.5], [np.nan, np.nan], [0.75, -1.3]], index=['a', 'b', 'c', 'd'],columns=['one', 'two'])>>> obj one twoa 1.40 NaNb 7.10 -4.5c NaN NaNd 0.75 -1.3>>> >>> obj.idxmax()one btwo ddtype: object 【02x00】统计描述 describe() 方法用于快速综合统计结果:计数、均值、标准差、最大最小值、四分位数等。还可以通过参数来设置需要忽略或者包含的统计选项。 在 Series 和 DataFrame 中的基本语法如下: Series.describe(self: ~ FrameOrSeries, percentiles=None, include=None, exclude=None) DataFrame.describe(self: ~ FrameOrSeries, percentiles=None, include=None, exclude=None) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.describe.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.describe.html 参数描述 percentiles数字列表,可选项,要包含在输出中的百分比。所有值都应介于 0 和 1 之间。默认值为 [.25、.5、.75],即返回第 25、50 和 75 个百分点 include要包含在结果中的数据类型,数据类型列表,默认 None,具体取值类型参见官方文档 exclude要从结果中忽略的数据类型,数据类型列表,默认 None,具体取值类型参见官方文档 描述数字形式的 Series 对象: >>> import pandas as pd>>> obj = pd.Series([1, 2, 3])>>> obj0 11 22 3dtype: int64>>> >>> obj.describe()count 3.0mean 2.0std 1.0min 1.025% 1.550% 2.075% 2.5max 3.0dtype: float64 分类描述: >>> import pandas as pd>>> obj = pd.Series(['a', 'a', 'b', 'c'])>>> obj0 a1 a2 b3 cdtype: object>>> >>> obj.describe()count 4unique 3top afreq 2dtype: object 描述时间戳: >>> import pandas as pd>>> obj = pd.Series([ np.datetime64("2000-01-01"), np.datetime64("2010-01-01"), np.datetime64("2010-01-01") ])>>> obj0 2000-01-011 2010-01-012 2010-01-01dtype: datetime64[ns]>>> >>> obj.describe()count 3unique 2top 2010-01-01 00:00:00freq 2first 2000-01-01 00:00:00last 2010-01-01 00:00:00dtype: object 描述 DataFrame 对象: >>> import pandas as pd>>> obj = pd.DataFrame({'categorical': pd.Categorical(['d','e','f']), 'numeric': [1, 2, 3], 'object': ['a', 'b', 'c']})>>> obj categorical numeric object0 d 1 a1 e 2 b2 f 3 c>>> >>> obj.describe() numericcount 3.0mean 2.0std 1.0min 1.025% 1.550% 2.075% 2.5max 3.0 不考虑数据类型,显示所有描述: >>> import pandas as pd>>> obj = pd.DataFrame({'categorical': pd.Categorical(['d','e','f']), 'numeric': [1, 2, 3], 'object': ['a', 'b', 'c']})>>> obj categorical numeric object0 d 1 a1 e 2 b2 f 3 c>>> >>> obj.describe(include='all') categorical numeric objectcount 3 3.0 3unique 3 NaN 3top f NaN cfreq 1 NaN 1mean NaN 2.0 NaNstd NaN 1.0 NaNmin NaN 1.0 NaN25% NaN 1.5 NaN50% NaN 2.0 NaN75% NaN 2.5 NaNmax NaN 3.0 NaN 仅包含 category 列: >>> import pandas as pd>>> obj = pd.DataFrame({'categorical': pd.Categorical(['d','e','f']), 'numeric': [1, 2, 3], 'object': ['a', 'b', 'c']})>>> obj categorical numeric object0 d 1 a1 e 2 b2 f 3 c>>> >>> obj.describe(include=['category']) categoricalcount 3unique 3top ffreq 1 【03x00】常用统计方法 其他常用统计方法参见下表: 方法描述官方文档 count非NA值的数量Series丨DataFrame describe针对Series或各DataFrame列计算汇总统计Series丨DataFrame min计算最小值Series丨DataFrame max计算最大值Series丨DataFrame argmin计算能够获取到最小值的索引位置(整数)Series argmax计算能够获取到最大值的索引位置(整数)Series idxmin计算能够获取到最小值的索引值Series丨DataFrame idxmax计算能够获取到最大值的索引值Series丨DataFrame quantile计算样本的分位数(0到1)Series丨DataFrame sum值的总和Series丨DataFrame mean值的平均数Series丨DataFrame median值的算术中位数(50%分位数)Series丨DataFrame mad根据平均值计算平均绝对离差Series丨DataFrame var样本值的方差Series丨DataFrame std样本值的标准差Series丨DataFrame 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106788501未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【01x00】函数应用和映射 【02x00】排序 【02x01】sort_index() 索引排序 【02x02】sort_values() 按值排序 【02x03】rank() 返回排序后元素索引 【03x00】层级索引 【03x01】认识层级索引 【03x02】MultiIndex 索引对象 【03x03】提取值 【03x04】交换分层与排序 Pandas 系列文章: Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象 Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作 Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理 Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引 Python 数据分析三剑客之 Pandas(五):统计计算与统计描述 Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并 Python 数据分析三剑客之 Pandas(七):合并数据集 Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换 Python 数据分析三剑客之 Pandas(九):时间序列 Python 数据分析三剑客之 Pandas(十):数据读写 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106758103未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【01x00】函数应用和映射 Pandas 可直接使用 NumPy 的 ufunc(元素级数组方法) 函数: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame(np.random.randn(5,4) - 1)>>> obj 0 1 2 30 -0.228107 1.377709 -1.096528 -2.0510011 -2.477144 -0.500013 -0.040695 -0.2674522 -0.485999 -1.232930 -0.390701 -1.9479843 -0.839161 -0.702802 -1.756359 -1.8731494 0.853121 -1.540105 0.621614 -0.583360>>> >>> np.abs(obj) 0 1 2 30 0.228107 1.377709 1.096528 2.0510011 2.477144 0.500013 0.040695 0.2674522 0.485999 1.232930 0.390701 1.9479843 0.839161 0.702802 1.756359 1.8731494 0.853121 1.540105 0.621614 0.583360 函数映射:在 Pandas 中 apply 方法可以将函数应用到列或行上,可以通过设置 axis 参数来指定行或列,默认 axis = 0,即按列映射: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame(np.random.randn(5,4) - 1)>>> obj 0 1 2 30 -0.707028 -0.755552 -2.196480 -0.5296761 -0.772668 0.127485 -2.015699 -0.2836542 0.248200 -1.940189 -1.068028 -1.7517373 -0.872904 -0.465371 -1.327951 -2.8831604 -0.092664 0.258351 -1.010747 -2.313039>>> >>> obj.apply(lambda x : x.max())0 0.2482001 0.2583512 -1.0107473 -0.283654dtype: float64>>>>>> obj.apply(lambda x : x.max(), axis=1)0 -0.5296761 0.1274852 0.2482003 -0.4653714 0.258351dtype: float64 另外还可以通过 applymap 将函数映射到每个数据上: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame(np.random.randn(5,4) - 1)>>> obj 0 1 2 30 -0.772463 -1.597008 -3.196100 -1.9484861 -1.765108 -1.646421 -0.687175 -0.4017822 0.275699 -3.115184 -1.429063 -1.0756103 -0.251734 -0.448399 -3.077677 -0.2946744 -1.495896 -1.689729 -0.560376 -1.808794>>> >>> obj.applymap(lambda x : '%.2f' % x) 0 1 2 30 -0.77 -1.60 -3.20 -1.951 -1.77 -1.65 -0.69 -0.402 0.28 -3.12 -1.43 -1.083 -0.25 -0.45 -3.08 -0.294 -1.50 -1.69 -0.56 -1.81 【02x00】排序 【02x01】sort_index() 索引排序 根据条件对数据集排序(sorting)也是一种重要的内置运算。要对行或列索引进行排序(按字典顺序),可使用 sort_index 方法,它将返回一个已排序的新对象。 在 Series 和 DataFrame 中的基本语法如下: Series.sort_index(self, axis=0, level=None, ascending=True, inplace=False, kind='quicksort', na_position='last', sort_remaining=True, ignore_index: bool = False) DataFrame.sort_index(self, axis=0, level=None, ascending=True, inplace=False, kind='quicksort', na_position='last', sort_remaining=True, ignore_index: bool = False) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.sort_index.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.sort_index.html 常用参数描述如下: 参数描述 axis指定轴排序,0 or ‘index’,1 or ‘columns’,只有在 DataFrame 中才有 1 or 'columns’ ascending为 True时升序排序(默认),为 False时降序排序 kind排序方法,quicksort:快速排序(默认);'mergesort’:归并排序;'heapsort':堆排序;具体可参见 numpy.sort() 在 Series 中的应用(按照索引 index 排序): >>> import pandas as pd>>> obj = pd.Series(range(4), index=['d', 'a', 'b', 'c'])>>> objd 0a 1b 2c 3dtype: int64>>> >>> obj.sort_index()a 1b 2c 3d 0dtype: int64 在 DataFrame 中的应用(可按照索引 index 或列标签 columns 排序): >>> import pandas as pd>>> obj = pd.DataFrame(np.arange(8).reshape((2, 4)), index=['three', 'one'], columns=['d', 'a', 'b', 'c'])>>> obj d a b cthree 0 1 2 3one 4 5 6 7>>> >>> obj.sort_index() d a b cone 4 5 6 7three 0 1 2 3>>> >>> obj.sort_index(axis=1) a b c dthree 1 2 3 0one 5 6 7 4>>> >>> obj.sort_index(axis=1, ascending=False) d c b athree 0 3 2 1one 4 7 6 5 【02x02】sort_values() 按值排序 在 Series 和 DataFrame 中的基本语法如下: Series.sort_values(self, axis=0, ascending=True, inplace=False, kind='quicksort', na_position='last', ignore_index=False) DataFrame.sort_values(self, by, axis=0, ascending=True, inplace=False, kind='quicksort', na_position='last', ignore_index=False) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.sort_values.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.sort_values.html 常用参数描述如下: 参数描述 byDataFrame 中的必须参数,指定列的值进行排序,Series 中没有此参数 axis指定轴排序,0 or ‘index’,1 or ‘columns’,只有在 DataFrame 中才有 1 or 'columns’ ascending为 True时升序排序(默认),为 False时降序排序 kind排序方法,quicksort:快速排序(默认);'mergesort’:归并排序;'heapsort':堆排序;具体可参见 numpy.sort() 在 Series 中的应用,按照值排序,如果有缺失值,默认都会被放到 Series 的末尾: >>> import pandas as pd>>> obj = pd.Series([4, 7, -3, 2])>>> obj0 41 72 -33 2dtype: int64>>> >>> obj.sort_values()2 -33 20 41 7dtype: int64>>> >>> obj = pd.Series([4, np.nan, 7, np.nan, -3, 2])>>> obj0 4.01 NaN2 7.03 NaN4 -3.05 2.0dtype: float64>>> >>> obj.sort_values()4 -3.05 2.00 4.02 7.01 NaN3 NaNdtype: float64 在 DataFrame 中的应用,有时候可能希望根据一个或多个列中的值进行排序。将一个或多个列的名字传递给 sort_values() 的 by 参数即可达到该目的,当传递多个列时,首先会对第一列进行排序,若第一列有相同的值,再根据第二列进行排序,依次类推: >>> import pandas as pd>>> obj = pd.DataFrame({'a': [4, 4, -3, 2], 'b': [0, 1, 0, 1], 'c': [6, 4, 1, 3]})>>> obj a b c0 4 0 61 4 1 42 -3 0 13 2 1 3>>> >>> obj.sort_values(by='c') a b c2 -3 0 13 2 1 31 4 1 40 4 0 6>>> >>> obj.sort_values(by='c', ascending=False) a b c0 4 0 61 4 1 43 2 1 32 -3 0 1>>>>>> obj.sort_values(by=['a', 'b']) a b c2 -3 0 13 2 1 30 4 0 61 4 1 4 >>> import pandas as pd>>> obj = pd.DataFrame({'a': [4, 4, -3, 2], 'b': [0, 1, 0, 1], 'c': [6, 4, 1, 3]}, index=['A', 'B', 'C', 'D'])>>> obj a b cA 4 0 6B 4 1 4C -3 0 1D 2 1 3>>> >>> obj.sort_values(by='B', axis=1) b a cA 0 4 6B 1 4 4C 0 -3 1D 1 2 3 【02x03】rank() 返回排序后元素索引 rank() 函数会返回一个对象,对象的值是原对象经过排序后的索引值,即下标。 在 Series 和 DataFrame 中的基本语法如下: Series.rank(self: ~ FrameOrSeries, axis=0, method: str = 'average', numeric_only: Union[bool, NoneType] = None, na_option: str = 'keep', ascending: bool = True, pct: bool = False) DataFrame.rank(self: ~ FrameOrSeries, axis=0, method: str = 'average', numeric_only: Union[bool, NoneType] = None, na_option: str = 'keep', ascending: bool = True, pct: bool = False) 官方文档: https://pandas.pydata.org/docs/reference/api/pandas.Series.rank.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.rank.html 常用参数描述如下: 参数描述 axis指定轴排序,0 or ‘index’,1 or ‘columns’,只有在 DataFrame 中才有 1 or 'columns’ method有相同值时,如何处理: ‘average’:默认值,去两个相同索引的平均值;‘min’:取两个相同索引的最小值; ‘max’:取两个相同索引的最大值;‘first’:按照出现的先后顺序; ‘dense’:和 'min' 差不多,但是各组之间总是+1的,不太好解释,可以看后面的示例 ascending为 True时升序排序(默认),为 False时降序排序 在 Series 中的应用,按照值排序,如果有缺失值,默认都会被放到 Series 的末尾: >>> import pandas as pd>>> obj = pd.Series([7, -5, 7, 4, 2, 0, 4])>>> obj0 71 -52 73 44 25 06 4dtype: int64>>> >>> obj.rank()0 6.5 # 第 0 个和第 2 个值从小到大排名分别为 6 和 7,默认取平均值,即 6.51 1.02 6.53 4.5 # 第 3 个和第 6 个值从小到大排名分别为 4 和 5,默认取平均值,即 4.54 3.05 2.06 4.5dtype: float64>>> >>> obj.rank(method='first')0 6.0 # 第 0 个和第 2 个值从小到大排名分别为 6 和 7,按照第一次出现排序,分别为 6 和 71 1.02 7.03 4.0 # 第 3 个和第 6 个值从小到大排名分别为 4 和 5,按照第一次出现排序,分别为 4 和 54 3.05 2.06 5.0dtype: float64>>> >>> obj.rank(method='dense')0 5.0 # 第 0 个和第 2 个值从小到大排名分别为 6 和 7,按照最小值排序,但 dense 规定间隔为 1 所以为 51 1.02 5.03 4.0 # 第 3 个和第 6 个值从小到大排名分别为 4 和 5,按照最小值排序,即 44 3.05 2.06 4.0dtype: float64>>> >>> obj.rank(method='min')0 6.0 # 第 0 个和第 2 个值从小到大排名分别为 6 和 7,按照最小值排序,即 61 1.02 6.03 4.0 # 第 3 个和第 6 个值从小到大排名分别为 4 和 5,按照最小值排序,即 44 3.05 2.06 4.0dtype: float64 在 DataFrame 中可以使用 axis 参数来指定轴: >>> import pandas as pd>>> obj = pd.DataFrame({'b': [4.3, 7, -3, 2], 'a': [0, 1, 0, 1], 'c': [-2, 5, 8, -2.5]})>>> obj b a c0 4.3 0 -2.01 7.0 1 5.02 -3.0 0 8.03 2.0 1 -2.5>>> >>> obj.rank() b a c0 3.0 1.5 2.01 4.0 3.5 3.02 1.0 1.5 4.03 2.0 3.5 1.0>>> >>> obj.rank(axis='columns') b a c0 3.0 2.0 1.01 3.0 1.0 2.02 1.0 2.0 3.03 3.0 2.0 1.0 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106758103未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【03x00】层级索引 【03x01】认识层级索引 以下示例将创建一个 Series 对象, 索引 Index 由两个子 list 组成,第一个子 list 是外层索引,第二个 list 是内层索引: >>> import pandas as pd>>> import numpy as np>>> obj = pd.Series(np.random.randn(12),index=[['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd'], [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]])>>> obja 0 -0.201536 1 -0.629058 2 0.766716b 0 -1.255831 1 -0.483727 2 -0.018653c 0 0.788787 1 1.010097 2 -0.187258d 0 1.242363 1 -0.822011 2 -0.085682dtype: float64 【03x02】MultiIndex 索引对象 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.MultiIndex.html 尝试打印上面示例中 Series 的索引类型,会得到一个 MultiIndex 对象,MultiIndex 对象的 levels 属性表示两个层级中分别有那些标签,codes 属性表示每个位置分别是什么标签,如下所示: >>> import pandas as pd>>> import numpy as np>>> obj = pd.Series(np.random.randn(12),index=[['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd'], [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]])>>> obja 0 0.035946 1 -0.867215 2 -0.053355b 0 -0.986616 1 0.026071 2 -0.048394c 0 0.251274 1 0.217790 2 1.137674d 0 -1.245178 1 1.234972 2 -0.035624dtype: float64>>> >>> type(obj.index)<class 'pandas.core.indexes.multi.MultiIndex'>>>> >>> obj.indexMultiIndex([('a', 0), ('a', 1), ('a', 2), ('b', 0), ('b', 1), ('b', 2), ('c', 0), ('c', 1), ('c', 2), ('d', 0), ('d', 1), ('d', 2)], )>>> obj.index.levelsFrozenList([['a', 'b', 'c', 'd'], [0, 1, 2]])>>>>>> obj.index.codesFrozenList([[0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3], [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]]) 通常可以使用 from_arrays() 方法来将数组对象转换为 MultiIndex 索引对象: >>> arrays = [[1, 1, 2, 2], ['red', 'blue', 'red', 'blue']]>>> pd.MultiIndex.from_arrays(arrays, names=('number', 'color'))MultiIndex([(1, 'red'), (1, 'blue'), (2, 'red'), (2, 'blue')], names=['number', 'color']) 其他常用方法见下表(更多方法参见官方文档): 方法描述 from_arrays(arrays[, sortorder, names])将数组转换为 MultiIndex from_tuples(tuples[, sortorder, names])将元组列表转换为 MultiIndex from_product(iterables[, sortorder, names])将多个可迭代的笛卡尔积转换成 MultiIndex from_frame(df[, sortorder, names])将 DataFrame 对象转换为 MultiIndex set_levels(self, levels[, level, inplace, …])为 MultiIndex 设置新的 levels set_codes(self, codes[, level, inplace, …])为 MultiIndex 设置新的 codes sortlevel(self[, level, ascending, …])根据 level 进行排序 droplevel(self[, level])删除指定的 level swaplevel(self[, i, j])交换 level i 与 level i,即交换外层索引与内层索引 【03x03】提取值 对于这种有多层索引的对象,如果只传入一个参数,则会对外层索引进行提取,其中包含对应所有的内层索引,如果传入两个参数,则第一个参数表示外层索引,第二个参数表示内层索引,示例如下: >>> import pandas as pd>>> import numpy as np>>> obj = pd.Series(np.random.randn(12),index=[['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd'], [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]])>>> obja 0 0.550202 1 0.328784 2 1.422690b 0 -1.333477 1 -0.933809 2 -0.326541c 0 0.663686 1 0.943393 2 0.273106d 0 1.354037 1 -2.312847 2 -2.343777dtype: float64>>> >>> obj['b']0 -1.3334771 -0.9338092 -0.326541dtype: float64>>>>>> obj['b', 1]-0.9338094811708413>>> >>> obj[:, 2]a 1.422690b -0.326541c 0.273106d -2.343777dtype: float64 【03x04】交换分层与排序 MultiIndex 对象的 swaplevel() 方法可以交换外层与内层索引,sortlevel() 方法会先对外层索引进行排序,再对内层索引进行排序,默认是升序,如果设置 ascending 参数为 False 则会降序排列,示例如下: >>> import pandas as pd>>> import numpy as np>>> obj = pd.Series(np.random.randn(12),index=[['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd'], [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]])>>> obja 0 -0.110215 1 0.193075 2 -1.101706b 0 -1.325743 1 0.528418 2 -0.127081c 0 -0.733822 1 1.665262 2 0.127073d 0 1.262022 1 -1.170518 2 0.966334dtype: float64>>> >>> obj.swaplevel()0 a -0.1102151 a 0.1930752 a -1.1017060 b -1.3257431 b 0.5284182 b -0.1270810 c -0.7338221 c 1.6652622 c 0.1270730 d 1.2620221 d -1.1705182 d 0.966334dtype: float64>>> >>> obj.swaplevel().index.sortlevel()(MultiIndex([(0, 'a'), (0, 'b'), (0, 'c'), (0, 'd'), (1, 'a'), (1, 'b'), (1, 'c'), (1, 'd'), (2, 'a'), (2, 'b'), (2, 'c'), (2, 'd')], ), array([ 0, 3, 6, 9, 1, 4, 7, 10, 2, 5, 8, 11], dtype=int32)) 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106758103未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【01x00】Pandas 算术运算 【01x01】使用 NumPy 通用函数 【01x02】数据对齐 【01x03】DataFrame 与 Series 之间的运算 【01x04】Pandas 算术方法 【02x00】处理缺失值 【02x01】fill_value() 指定值与缺失值进行运算 【02x02】isnull() / notnull() 判断缺失值 【02x03】dropna() 删除缺失值 【02x04】fillna() 填充缺失值 Pandas 系列文章: Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象 Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作 Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理 Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引 Python 数据分析三剑客之 Pandas(五):统计计算与统计描述 Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并 Python 数据分析三剑客之 Pandas(七):合并数据集 Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换 Python 数据分析三剑客之 Pandas(九):时间序列 Python 数据分析三剑客之 Pandas(十):数据读写 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106743778未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【01x00】Pandas 算术运算 Pandas 继承了 NumPy 的功能,NumPy 的基本能力之一是快速对每个元素进行运算,既包括基本算术运算(加、减、乘、除),也包括更复杂的运算(三角函数、指数函数和对数函数等)。具体可以参考 NumPy 系列文章。 【01x01】使用 NumPy 通用函数 因为 Pandas 是建立在 NumPy 基础之上的,所以 NumPy 的通用函数同样适用于 Pandas 的 Series 和 DataFrame 对象,如下所示: >>> import pandas as pd>>> import numpy as np>>> rng = np.random.RandomState(42)>>> ser = pd.Series(rng.randint(0, 10, 4))>>> ser0 61 32 73 4dtype: int32>>> >>> obj = pd.DataFrame(rng.randint(0, 10, (3, 4)), columns=['A', 'B', 'C', 'D'])>>> obj A B C D0 6 9 2 61 7 4 3 72 7 2 5 4 使用 NumPy 通用函数,生成的结果是另一个保留索引的 Pandas 对象: >>> import pandas as pd>>> import numpy as np>>> rng = np.random.RandomState(42)>>> ser = pd.Series(rng.randint(0, 10, 4))>>> ser0 61 32 73 4dtype: int32>>> >>> np.exp(ser)0 403.4287931 20.0855372 1096.6331583 54.598150dtype: float64 >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame(rng.randint(0, 10, (3, 4)), columns=['A', 'B', 'C', 'D'])>>> np.sin(obj * np.pi / 4) A B C D0 -1.000000 7.071068e-01 1.000000 -1.000000e+001 -0.707107 1.224647e-16 0.707107 -7.071068e-012 -0.707107 1.000000e+00 -0.707107 1.224647e-16 【01x02】数据对齐 Pandas 最重要的一个功能是,它可以对不同索引的对象进行算术运算。在将对象相加时,如果存在不同的索引对,则结果的索引就是该索引对的并集。自动的数据对齐操作会在不重叠的索引处引入缺失值,即 NaN,缺失值会在算术运算过程中传播。 Series 对象的数据对齐操作: >>> import pandas as pd>>> obj1 = pd.Series([7.3, -2.5, 3.4, 1.5], index=['a', 'c', 'd', 'e'])>>> obj2 = pd.Series([-2.1, 3.6, -1.5, 4, 3.1], index=['a', 'c', 'e', 'f', 'g'])>>> obj1a 7.3c -2.5d 3.4e 1.5dtype: float64>>> >>> obj2a -2.1c 3.6e -1.5f 4.0g 3.1dtype: float64>>>>>> obj1 + obj2a 5.2c 1.1d NaNe 0.0f NaNg NaNdtype: float64 DataFrame 对象的数据对齐操作会同时发生在行和列上: >>> import pandas as pd>>> obj1 = pd.DataFrame(np.arange(9.).reshape((3, 3)), columns=list('bcd'), index=['Ohio', 'Texas', 'Colorado'])>>> obj2 = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'])>>> obj1 b c dOhio 0.0 1.0 2.0Texas 3.0 4.0 5.0Colorado 6.0 7.0 8.0>>> >>> obj2 b d eUtah 0.0 1.0 2.0Ohio 3.0 4.0 5.0Texas 6.0 7.0 8.0Oregon 9.0 10.0 11.0>>> >>> obj1 + obj2 b c d eColorado NaN NaN NaN NaNOhio 3.0 NaN 6.0 NaNOregon NaN NaN NaN NaNTexas 9.0 NaN 12.0 NaNUtah NaN NaN NaN NaN 【01x03】DataFrame 与 Series 之间的运算 首先回忆 NumPy 中的广播(参见:《Python 数据分析三剑客之 NumPy(二):数组索引 / 切片 / 广播 / 拼接 / 分割》),跟不同维度的 NumPy 数组一样,DataFrame 和 Series 之间算术运算也是有明确规定的。首先回忆一下 NumPy 中不同维度的数组之间的运算: >>> import numpy as np>>> arr = np.arange(12.).reshape((3, 4))>>> arrarray([[ 0., 1., 2., 3.], [ 4., 5., 6., 7.], [ 8., 9., 10., 11.]])>>> >>> arr[0]array([0., 1., 2., 3.])>>> >>> arr - arr[0]array([[0., 0., 0., 0.], [4., 4., 4., 4.], [8., 8., 8., 8.]]) 可以看到每一行都进行了减法运算,这正是 NumPy 中的广播,而 DataFrame 与 Series 之间的运算也类似,默认情况下,DataFrame 和 Series 之间的算术运算会将 Series 的索引匹配到 DataFrame 的列,然后沿着行一直向下广播: >>> import numpy as np>>> import pandas as pd>>> frame = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'), index=['AA', 'BB', 'CC', 'DD'])>>> frame b d eAA 0.0 1.0 2.0BB 3.0 4.0 5.0CC 6.0 7.0 8.0DD 9.0 10.0 11.0>>> >>> series = frame.iloc[0]>>> seriesb 0.0d 1.0e 2.0Name: AA, dtype: float64>>> >>> frame - series b d eAA 0.0 0.0 0.0BB 3.0 3.0 3.0CC 6.0 6.0 6.0DD 9.0 9.0 9.0 如果某个索引值在 DataFrame 的列或 Series 的索引中找不到,则参与运算的两个对象就会被重新索引以形成并集: >>> import numpy as np>>> import pandas as pd>>> frame = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'), index=['AA', 'BB', 'CC', 'DD'])>>> frame b d eAA 0.0 1.0 2.0BB 3.0 4.0 5.0CC 6.0 7.0 8.0DD 9.0 10.0 11.0>>> >>> series = pd.Series(range(3), index=['b', 'e', 'f'])>>> seriesb 0e 1f 2dtype: int64>>> >>> frame + series b d e fAA 0.0 NaN 3.0 NaNBB 3.0 NaN 6.0 NaNCC 6.0 NaN 9.0 NaNDD 9.0 NaN 12.0 NaN 如果希望匹配行且在列上广播,则必须使用算术运算方法,在方法中传入的轴(axis)就是希望匹配的轴。在下例中,我们的目的是匹配 DataFrame 的行索引(axis=‘index’ or axis=0)并进行广播: >>> import numpy as np>>> import pandas as pd>>> frame = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'), index=['AA', 'BB', 'CC', 'DD'])>>> frame b d eAA 0.0 1.0 2.0BB 3.0 4.0 5.0CC 6.0 7.0 8.0DD 9.0 10.0 11.0>>> >>> series = frame['d']>>> seriesAA 1.0BB 4.0CC 7.0DD 10.0Name: d, dtype: float64>>> >>> frame.sub(series, axis='index') b d eAA -1.0 0.0 1.0BB -1.0 0.0 1.0CC -1.0 0.0 1.0DD -1.0 0.0 1.0 【01x04】Pandas 算术方法 完整的 Pandas 算术方法见下表: 方法副本描述 add()radd()加法(+) sub()、subtract()rsub()减法(-) mul()、multiply()rmul()乘法(*) pow()rpow()指数(**) truediv()、div()、divide()rdiv()除法(/) floordiv()rfloordiv()底除(//) mod()rmod()求余(%) 副本均为原方法前加了个 r,它会翻转参数: >>> import pandas as pd>>> obj = pd.DataFrame(np.arange(12.).reshape((3, 4)), columns=list('abcd'))>>> obj a b c d0 0.0 1.0 2.0 3.01 4.0 5.0 6.0 7.02 8.0 9.0 10.0 11.0>>> >>> 1 / obj a b c d0 inf 1.000000 0.500000 0.3333331 0.250 0.200000 0.166667 0.1428572 0.125 0.111111 0.100000 0.090909>>> >>> obj.rdiv(1) a b c d0 inf 1.000000 0.500000 0.3333331 0.250 0.200000 0.166667 0.1428572 0.125 0.111111 0.100000 0.090909 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106743778未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【02x00】处理缺失值 在现实中遇到的数据很少是干净整齐的,许多数据集都会有数据缺失的现象,缺失值主要有三种形式:null、NaN(NAN,nan) 或 NA。 【02x01】fill_value() 指定值与缺失值进行运算 使用 add, sub, div, mul 等算术方法时,通过 fill_value 指定填充值,未对齐的数据将和填充值做运算。 Series 中的应用: >>> import pandas as pd>>> obj1 = pd.Series([1, 2, 3, 4, 5])>>> obj2 = pd.Series([6, 7])>>> >>> obj10 11 22 33 44 5dtype: int64>>> >>> obj20 61 7dtype: int64>>> >>> obj1.add(obj2)0 7.01 9.02 NaN3 NaN4 NaNdtype: float64>>> >>> obj1.add(obj2, fill_value=-1)0 7.01 9.02 2.03 3.04 4.0dtype: float64 DataFrame 中的应用: >>> import pandas as pd>>> import numpy as np>>> obj1 = pd.DataFrame(np.arange(12.).reshape((3, 4)), columns=list('abcd'))>>> obj2 = pd.DataFrame(np.arange(20.).reshape((4, 5)), columns=list('abcde'))>>> >>> obj2.loc[1, 'b'] = np.nan>>> >>> obj1 a b c d0 0.0 1.0 2.0 3.01 4.0 5.0 6.0 7.02 8.0 9.0 10.0 11.0>>> >>> obj2 a b c d e0 0.0 1.0 2.0 3.0 4.01 5.0 NaN 7.0 8.0 9.02 10.0 11.0 12.0 13.0 14.03 15.0 16.0 17.0 18.0 19.0>>> >>> obj1 + obj2 a b c d e0 0.0 2.0 4.0 6.0 NaN1 9.0 NaN 13.0 15.0 NaN2 18.0 20.0 22.0 24.0 NaN3 NaN NaN NaN NaN NaN>>> >>> obj1.add(obj2, fill_value=10) a b c d e0 0.0 2.0 4.0 6.0 14.01 9.0 15.0 13.0 15.0 19.02 18.0 20.0 22.0 24.0 24.03 25.0 26.0 27.0 28.0 29.0 【02x02】isnull() / notnull() 判断缺失值 isnull():为缺失值时为 True,否则为 False; notnull() 为缺失值时为 False,否则为 True。 >>> import numpy as np>>> import pandas as pd>>> obj = pd.Series([1, np.nan, 'hello', None])>>> obj0 11 NaN2 hello3 Nonedtype: object>>> >>> obj.isnull()0 False1 True2 False3 Truedtype: bool>>> >>> obj.notnull()0 True1 False2 True3 Falsedtype: bool 【02x03】dropna() 删除缺失值 dropna() 方法用于返回一个删除了缺失值的新 Series 或 DataFrame 对象。 在 Series 对象当中,dropna() 方法的语法如下(其他参数用法可参考在 DataFrame 中的应用): Series.dropna(self, axis=0, inplace=False, how=None) 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.Series.dropna.html >>> import numpy as np>>> import pandas as pd>>> obj = pd.Series([1, np.nan, 'hello', None])>>> obj0 11 NaN2 hello3 Nonedtype: object>>> >>> obj.dropna()0 12 hellodtype: object 在 DataFrame 对象中,dropna() 方法的语法如下: DataFrame.dropna(self, axis=0, how='any', thresh=None, subset=None, inplace=False) 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.dropna.html 参数描述 axis确定是否删除包含缺失值的行或列 0 或 'index':删除包含缺失值的行。1 或 'columns':删除包含缺失值的列 how'any':如果存在任何NA值,则删除该行或列。'all':如果所有值都是NA,则删除该行或列 thresh设置行或列中非缺失值的最小数量 不传递任何参数,将会删除任何包含缺失值的整行数据: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame([[1, np.nan, 2], [2, 3, 5], [np.nan, 4, 6]])>>> obj 0 1 20 1.0 NaN 21 2.0 3.0 52 NaN 4.0 6>>> >>> obj.dropna() 0 1 21 2.0 3.0 5 指定 axis 参数,删除包含缺失值的行或列: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame([[1, np.nan, 2], [2, 3, 5], [np.nan, 4, 6]])>>> obj 0 1 20 1.0 NaN 21 2.0 3.0 52 NaN 4.0 6>>> >>> obj.dropna(axis='columns') 20 21 52 6 指定 how 参数,'any':如果存在任何NA值,则删除该行或列。'all':如果所有值都是NA,则删除该行或列: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame([[1, np.nan, 2, np.nan], [2, 3, 5, np.nan], [np.nan, 4, 6, np.nan]])>>> obj 0 1 2 30 1.0 NaN 2 NaN1 2.0 3.0 5 NaN2 NaN 4.0 6 NaN>>> obj.dropna(axis='columns', how='all') 0 1 20 1.0 NaN 21 2.0 3.0 52 NaN 4.0 6 指定 thresh 参数,设置行或列中非缺失值的最小数量,以下示例中,第一行和第三行只有两个非缺失值,所以会被删除: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame([[1, np.nan, 2, np.nan], [2, 3, 5, np.nan], [np.nan, 4, 6, np.nan]])>>> obj 0 1 2 30 1.0 NaN 2 NaN1 2.0 3.0 5 NaN2 NaN 4.0 6 NaN>>>>>> obj.dropna(axis='rows', thresh=3) 0 1 2 31 2.0 3.0 5 NaN 【02x04】fillna() 填充缺失值 fillna() 方法可以将缺失值替换成有效的数值。 在 Series 对象中,fillna() 方法的语法如下: Series.fillna(self, value=None, method=None, axis=None, inplace=False, limit=None, downcast=None) 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.Series.fillna.html 参数描述 value用于填充的值(例如 0),或者是一个 dict / Series / DataFrame 值 指定要用于每个 index(对于 Series)或column(对于 DataFrame)的值 不在dict / Series / DataFrame中的值将不被填充。此值不能是列表 method填充方法:None ‘pad’ / ‘ffill’:将上一个有效观测值向前传播到下一个有效观测值 ‘backfill’ / ‘bfill’:使用下一个有效观察值来填补空白 axis0 or ‘index’,要填充缺失值的轴 >>> import pandas as pd>>> obj = pd.Series([1, np.nan, 2, None, 3], index=list('abcde'))>>> obja 1.0b NaNc 2.0d NaNe 3.0dtype: float64>>> >>> obj.fillna(0)a 1.0b 0.0c 2.0d 0.0e 3.0dtype: float64>>> >>> obj.fillna(method='ffill')a 1.0b 1.0c 2.0d 2.0e 3.0dtype: float64>>> >>> obj.fillna(method='bfill')a 1.0b 2.0c 2.0d 3.0e 3.0dtype: float64 在 DataFrame 对象中,fillna() 方法的语法如下: DataFrame.fillna(self, value=None, method=None, axis=None, inplace=False, limit=None, downcast=None) 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.fillna.html 参数描述 value用于填充的值(例如 0),或者是一个 dict / Series / DataFrame 值 指定要用于每个 index(对于 Series)或column(对于 DataFrame)的值 不在dict / Series / DataFrame中的值将不被填充。此值不能是列表 method填充方法:None ‘pad’ / ‘ffill’:将上一个有效观测值向前传播到下一个有效观测值 ‘backfill’ / ‘bfill’:使用下一个有效观察值来填补空白 axis0 or ‘index’,1 or ‘columns’,要填充缺失值的轴 在 DataFrame 对象中的用法和在 Series 对象中的用法大同小异,只不过 axis 参数多了一个选择: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame([[1, np.nan, 2, np.nan], [2, 3, 5, np.nan], [np.nan, 4, 6, np.nan]])>>> obj 0 1 2 30 1.0 NaN 2 NaN1 2.0 3.0 5 NaN2 NaN 4.0 6 NaN>>> >>> obj.fillna(method='ffill', axis=1) 0 1 2 30 1.0 1.0 2.0 2.01 2.0 3.0 5.0 5.02 NaN 4.0 6.0 6.0 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106743778未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【1】Index 索引对象 【2】Pandas 一般索引 【2.1】Series 索引 【2.1.1】head() / tail() 【2.1.2】行索引 【2.1.3】切片索引 【2.1.4】花式索引 【2.1.5】布尔索引 【2.2】DataFrame 索引 【2.2.1】head() / tail() 【2.2.2】列索引 【2.2.3】切片索引 【2.2.4】花式索引 【2.2.5】布尔索引 【3】索引器:loc 和 iloc 【3.1】loc 标签索引 【3.1.1】Series.loc 【3.1.2】DataFrame.loc 【3.2】iloc 位置索引 【3.2.1】Series.iloc 【3.2.2】DataFrame.iloc 【4】Pandas 重新索引 Pandas 系列文章: Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象 Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作 Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理 Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引 Python 数据分析三剑客之 Pandas(五):统计计算与统计描述 Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并 Python 数据分析三剑客之 Pandas(七):合并数据集 Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换 Python 数据分析三剑客之 Pandas(九):时间序列 Python 数据分析三剑客之 Pandas(十):数据读写 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106698307未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【1】Index 索引对象 Series 和 DataFrame 中的索引都是 Index 对象,为了保证数据的安全,索引对象是不可变的,如果尝试更改索引就会报错;常见的 Index 种类有:索引(Index),整数索引(Int64Index),层级索引(MultiIndex),时间戳类型(DatetimeIndex)。 一下代码演示了 Index 索引对象和其不可变的性质: >>> import pandas as pd>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> obj.indexIndex(['a', 'b', 'c', 'd'], dtype='object')>>> type(obj.index)<class 'pandas.core.indexes.base.Index'>>>> obj.index[0] = 'e'Traceback (most recent call last): File "<pyshell#28>", line 1, in <module> obj.index[0] = 'e' File "C:\Users\...\base.py", line 3909, in __setitem__ raise TypeError("Index does not support mutable operations")TypeError: Index does not support mutable operations index 索引对象常用属性 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.Index.html 属性描述 T转置 arrayindex 的数组形式,常见官方文档 dtype返回基础数据的 dtype 对象 hasnans是否有 NaN(缺失值) inferred_type返回一个字符串,表示 index 的类型 is_monotonic判断 index 是否是递增的 is_monotonic_decreasing判断 index 是否单调递减 is_monotonic_increasing判断 index 是否单调递增 is_uniqueindex 是否没有重复值 nbytes返回 index 中的字节数 ndimindex 的维度 nlevelsNumber of levels. shape返回一个元组,表示 index 的形状 sizeindex 的大小 values返回 index 中的值 / 数组 >>> import pandas as pd>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> obj.indexIndex(['a', 'b', 'c', 'd'], dtype='object')>>> >>> obj.index.array<PandasArray>['a', 'b', 'c', 'd']Length: 4, dtype: object>>> >>> obj.index.dtypedtype('O')>>> >>> obj.index.hasnansFalse>>>>>> obj.index.inferred_type'string'>>> >>> obj.index.is_monotonicTrue>>>>>> obj.index.is_monotonic_decreasingFalse>>> >>> obj.index.is_monotonic_increasingTrue>>> >>> obj.index.is_uniqueTrue>>> >>> obj.index.nbytes16>>>>>> obj.index.ndim1>>>>>> obj.index.nlevels1>>>>>> obj.index.shape(4,)>>> >>> obj.index.size4>>> >>> obj.index.valuesarray(['a', 'b', 'c', 'd'], dtype=object) index 索引对象常用方法 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.Index.html 方法描述 all(self, *args, **kwargs)判断所有元素是否为真,有 0 会被视为 False any(self, *args, **kwargs)判断是否至少有一个元素为真,均为 0 会被视为 False append(self, other)连接另一个 index,产生一个新的 index argmax(self[, axis, skipna])返回 index 中最大值的索引值 argmin(self[, axis, skipna])返回 index 中最小值的索引值 argsort(self, *args, **kwargs)对 index 从小到大排序,返回排序后的元素在原 index 中的索引值 delete(self, loc)删除指定索引位置的元素,返回删除后的新 index difference(self, other[, sort])在第一个 index 中删除第二个 index 中的元素,即差集 drop(self, labels[, errors])在原 index 中删除传入的值 drop_duplicates(self[, keep])删除重复值,keep 参数可选值如下: ‘first’:保留第一次出现的重复项; ‘last’:保留最后一次出现的重复项; False:不保留重复项 duplicated(self[, keep])判断是否为重复值,keep 参数可选值如下: ‘first’:第一次重复的为 False,其他为 True; ‘last’:最后一次重复的为 False,其他为 True; False:所有重复的均为 True dropna(self[, how])删除缺失值,即 NaN fillna(self[, value, downcast])用指定值填充缺失值,即 NaN equals(self, other)判断两个 index 是否相同 insert(self, loc, item)将元素插入到指定索引处,返回新的 index intersection(self, other[, sort])返回两个 index 的交集 isna(self)检测 index 元素是否为缺失值,即 NaN isnull(self)检测 index 元素是否为缺失值,即 NaN max(self[, axis, skipna])返回 index 的最大值 min(self[, axis, skipna])返回 index 的最小值 union(self, other[, sort])返回两个 index 的并集 unique(self[, level])返回 index 中的唯一值,相当于去除重复值 all(self, *args, **kwargs) 【官方文档】 >>> import pandas as pd>>> pd.Index([1, 2, 3]).all()True>>>>>> pd.Index([0, 1, 2]).all()False any(self, *args, **kwargs) 【官方文档】 >>> import pandas as pd>>> pd.Index([0, 0, 1]).any()True>>>>>> pd.Index([0, 0, 0]).any()False append(self, other) 【官方文档】 >>> import pandas as pd>>> pd.Index(['a', 'b', 'c']).append(pd.Index([1, 2, 3]))Index(['a', 'b', 'c', 1, 2, 3], dtype='object') argmax(self[, axis, skipna]) 【官方文档】 >>> import pandas as pd>>> pd.Index([5, 2, 3, 9, 1]).argmax()3 argmin(self[, axis, skipna]) 【官方文档】 >>> import pandas as pd>>> pd.Index([5, 2, 3, 9, 1]).argmin()4 argsort(self, *args, **kwargs) 【官方文档】 >>> import pandas as pd>>> pd.Index([5, 2, 3, 9, 1]).argsort()array([4, 1, 2, 0, 3], dtype=int32) delete(self, loc) 【官方文档】 >>> import pandas as pd>>> pd.Index([5, 2, 3, 9, 1]).delete(0)Int64Index([2, 3, 9, 1], dtype='int64') difference(self, other[, sort]) 【官方文档】 >>> import pandas as pd>>> idx1 = pd.Index([2, 1, 3, 4])>>> idx2 = pd.Index([3, 4, 5, 6])>>> idx1.difference(idx2)Int64Index([1, 2], dtype='int64')>>> idx1.difference(idx2, sort=False)Int64Index([2, 1], dtype='int64') drop(self, labels[, errors]) 【官方文档】 >>> import pandas as pd>>> pd.Index([5, 2, 3, 9, 1]).drop([2, 1])Int64Index([5, 3, 9], dtype='int64') drop_duplicates(self[, keep]) 【官方文档】 >>> import pandas as pd>>> idx = pd.Index(['lama', 'cow', 'lama', 'beetle', 'lama', 'hippo'])>>> idx.drop_duplicates(keep='first')Index(['lama', 'cow', 'beetle', 'hippo'], dtype='object')>>> idx.drop_duplicates(keep='last')Index(['cow', 'beetle', 'lama', 'hippo'], dtype='object')>>> idx.drop_duplicates(keep=False)Index(['cow', 'beetle', 'hippo'], dtype='object') duplicated(self[, keep]) 【官方文档】 >>> import pandas as pd>>> idx = pd.Index(['lama', 'cow', 'lama', 'beetle', 'lama'])>>> idx.duplicated()array([False, False, True, False, True])>>> idx.duplicated(keep='first')array([False, False, True, False, True])>>> idx.duplicated(keep='last')array([ True, False, True, False, False])>>> idx.duplicated(keep=False)array([ True, False, True, False, True]) dropna(self[, how]) 【官方文档】 >>> import numpy as np>>> import pandas as pd>>> pd.Index([2, 5, np.NaN, 6, np.NaN, np.NaN]).dropna()Float64Index([2.0, 5.0, 6.0], dtype='float64') fillna(self[, value, downcast]) 【官方文档】 >>> import numpy as np>>> import pandas as pd>>> pd.Index([2, 5, np.NaN, 6, np.NaN, np.NaN]).fillna(5)Float64Index([2.0, 5.0, 5.0, 6.0, 5.0, 5.0], dtype='float64') equals(self, other) 【官方文档】 >>> import pandas as pd>>> idx1 = pd.Index([5, 2, 3, 9, 1])>>> idx2 = pd.Index([5, 2, 3, 9, 1])>>> idx1.equals(idx2)True>>> >>> idx1 = pd.Index([5, 2, 3, 9, 1])>>> idx2 = pd.Index([5, 2, 4, 9, 1])>>> idx1.equals(idx2)False intersection(self, other[, sort]) 【官方文档】 >>> import pandas as pd>>> idx1 = pd.Index([1, 2, 3, 4])>>> idx2 = pd.Index([3, 4, 5, 6])>>> idx1.intersection(idx2)Int64Index([3, 4], dtype='int64') insert(self, loc, item) 【官方文档】 >>> import pandas as pd>>> pd.Index([5, 2, 3, 9, 1]).insert(2, 'A')Index([5, 2, 'A', 3, 9, 1], dtype='object') isna(self) 【官方文档】、isnull(self) 【官方文档】 >>> import numpy as np>>> import pandas as pd>>> pd.Index([2, 5, np.NaN, 6, np.NaN, np.NaN]).isna()array([False, False, True, False, True, True])>>> pd.Index([2, 5, np.NaN, 6, np.NaN, np.NaN]).isnull()array([False, False, True, False, True, True]) max(self[, axis, skipna]) 【官方文档】、min(self[, axis, skipna]) 【官方文档】 >>> import pandas as pd>>> pd.Index([5, 2, 3, 9, 1]).max()9>>> pd.Index([5, 2, 3, 9, 1]).min()1 union(self, other[, sort]) 【官方文档】 >>> import pandas as pd>>> idx1 = pd.Index([1, 2, 3, 4])>>> idx2 = pd.Index([3, 4, 5, 6])>>> idx1.union(idx2)Int64Index([1, 2, 3, 4, 5, 6], dtype='int64') unique(self[, level]) 【官方文档】 >>> import pandas as pd>>> pd.Index([5, 1, 3, 5, 1]).unique()Int64Index([5, 1, 3], dtype='int64') 【2】Pandas 一般索引 由于在 Pandas 中,由于有一些更高级的索引操作,比如重新索引,层级索引等,因此将一般的切片索引、花式索引、布尔索引等归纳为一般索引。 【2.1】Series 索引 【2.1.1】head() / tail() Series.head() 和 Series.tail() 方法可以获取的前五行和后五行数据,如果向 head() / tail() 里面传入参数,则会获取指定行: >>> import pandas as pd>>> import numpy as np>>> obj = pd.Series(np.random.randn(8))>>> obj0 -0.6434371 -0.3656522 -0.9665543 -0.0361274 1.0460955 -2.0483626 -1.8655517 1.344728dtype: float64>>> >>> obj.head()0 -0.6434371 -0.3656522 -0.9665543 -0.0361274 1.046095dtype: float64>>> >>> obj.head(3)0 -0.6434371 -0.3656522 -0.966554dtype: float64>>>>>> obj.tail()3 1.2212214 -1.3734965 1.0328436 0.0297347 -1.861485dtype: float64>>>>>> obj.tail(3)5 1.0328436 0.0297347 -1.861485dtype: float64 【2.1.2】行索引 Pandas 中可以按照位置进行索引,也可以按照索引名(index)进行索引,也可以用 Python 字典的表达式和方法来获取值: >>> import pandas as pd>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> obja 1b 5c -8d 2dtype: int64>>> obj['c']-8>>> obj[2]-8>>> 'b' in objTrue>>> obj.keys()Index(['a', 'b', 'c', 'd'], dtype='object')>>> list(obj.items())[('a', 1), ('b', 5), ('c', -8), ('d', 2)] 【2.1.3】切片索引 切片的方法有两种:按位置切片和按索引名(index)切片,注意:按位置切片时,不包含终止索引;按索引名(index)切片时,包含终止索引。 >>> import pandas as pd>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> obja 1b 5c -8d 2dtype: int64>>>>>> obj[1:3]b 5c -8dtype: int64>>>>>> obj[0:3:2]a 1c -8dtype: int64>>>>>> obj['b':'d']b 5c -8d 2dtype: int64 【2.1.4】花式索引 所谓的花式索引,就是间隔索引、不连续的索引,传递一个由索引名(index)或者位置参数组成的列表来一次性获得多个元素: >>> import pandas as pd>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> obja 1b 5c -8d 2dtype: int64>>> >>> obj[[0, 2]]a 1c -8dtype: int64>>> >>> obj[['a', 'c', 'd']]a 1c -8d 2dtype: int64 【2.1.5】布尔索引 可以通过一个布尔数组来索引目标数组,即通过布尔运算(如:比较运算符)来获取符合指定条件的元素的数组。 >>> import pandas as pd>>> obj = pd.Series([1, 5, -8, 2, -3], index=['a', 'b', 'c', 'd', 'e'])>>> obja 1b 5c -8d 2e -3dtype: int64>>> >>> obj[obj > 0]a 1b 5d 2dtype: int64>>> >>> obj > 0a Trueb Truec Falsed Truee Falsedtype: bool 【2.2】DataFrame 索引 【2.2.1】head() / tail() 和 Series 一样,DataFrame.head() 和 DataFrame.tail() 方法同样可以获取 DataFrame 的前五行和后五行数据,如果向 head() / tail() 里面传入参数,则会获取指定行: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame(np.random.randn(8,4), columns = ['a', 'b', 'c', 'd'])>>> obj a b c d0 -1.399390 0.521596 -0.869613 0.5066211 -0.748562 -0.364952 0.188399 -1.4025662 1.378776 -1.476480 0.361635 0.4511343 -0.206405 -1.188609 3.002599 0.5636504 0.993289 1.133748 1.177549 -2.5622865 -0.482157 1.069293 1.143983 -1.3030796 -1.199154 0.220360 0.801838 -0.1045337 -1.359816 -2.092035 2.003530 -0.151812>>> >>> obj.head() a b c d0 -1.399390 0.521596 -0.869613 0.5066211 -0.748562 -0.364952 0.188399 -1.4025662 1.378776 -1.476480 0.361635 0.4511343 -0.206405 -1.188609 3.002599 0.5636504 0.993289 1.133748 1.177549 -2.562286>>> >>> obj.head(3) a b c d0 -1.399390 0.521596 -0.869613 0.5066211 -0.748562 -0.364952 0.188399 -1.4025662 1.378776 -1.476480 0.361635 0.451134>>>>>> obj.tail() a b c d3 -0.206405 -1.188609 3.002599 0.5636504 0.993289 1.133748 1.177549 -2.5622865 -0.482157 1.069293 1.143983 -1.3030796 -1.199154 0.220360 0.801838 -0.1045337 -1.359816 -2.092035 2.003530 -0.151812>>> >>> obj.tail(3) a b c d5 -0.482157 1.069293 1.143983 -1.3030796 -1.199154 0.220360 0.801838 -0.1045337 -1.359816 -2.092035 2.003530 -0.151812 【2.2.2】列索引 DataFrame 可以按照列标签(columns)来进行列索引: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame(np.random.randn(7,2), columns = ['a', 'b'])>>> obj a b0 -1.198795 0.9283781 -2.878230 0.0146502 2.267475 0.3709523 0.639340 -1.3010414 -1.953444 0.1489345 -0.445225 0.4596326 0.097109 -2.592833>>>>>> obj['a']0 -1.1987951 -2.8782302 2.2674753 0.6393404 -1.9534445 -0.4452256 0.097109Name: a, dtype: float64>>> >>> obj[['a']] a0 -1.1987951 -2.8782302 2.2674753 0.6393404 -1.9534445 -0.4452256 0.097109>>> >>> type(obj['a'])<class 'pandas.core.series.Series'>>>> type(obj[['a']])<class 'pandas.core.frame.DataFrame'> 【2.2.3】切片索引 DataFrame 中的切片索引是针对行来操作的,切片的方法有两种:按位置切片和按索引名(index)切片,注意:按位置切片时,不包含终止索引;按索引名(index)切片时,包含终止索引。 >>> import pandas as pd>>> import numpy as np>>> data = np.random.randn(5,4)>>> index = ['I1', 'I2', 'I3', 'I4', 'I5']>>> columns = ['a', 'b', 'c', 'd']>>> obj = pd.DataFrame(data, index, columns)>>> obj a b c dI1 0.828676 -1.663337 1.753632 1.432487I2 0.368138 0.222166 0.902764 -1.436186I3 2.285615 -2.415175 -1.344456 -0.502214I4 3.224288 -0.500268 1.293596 -1.235549I5 -0.938833 -0.804433 -0.170047 -0.566766>>> >>> obj[0:3] a b c dI1 0.828676 -1.663337 1.753632 1.432487I2 0.368138 0.222166 0.902764 -1.436186I3 2.285615 -2.415175 -1.344456 -0.502214>>>>>> obj[0:4:2] a b c dI1 -0.042168 1.437354 -1.114545 0.830790I3 0.241506 0.018984 -0.499151 -1.190143>>>>>> obj['I2':'I4'] a b c dI2 0.368138 0.222166 0.902764 -1.436186I3 2.285615 -2.415175 -1.344456 -0.502214I4 3.224288 -0.500268 1.293596 -1.235549 【2.2.4】花式索引 和 Series 一样,所谓的花式索引,就是间隔索引、不连续的索引,传递一个由列名(columns)组成的列表来一次性获得多列元素: >>> import pandas as pd>>> import numpy as np>>> data = np.random.randn(5,4)>>> index = ['I1', 'I2', 'I3', 'I4', 'I5']>>> columns = ['a', 'b', 'c', 'd']>>> obj = pd.DataFrame(data, index, columns)>>> obj a b c dI1 -1.083223 -0.182874 -0.348460 -1.572120I2 -0.205206 -0.251931 1.180131 0.847720I3 -0.980379 0.325553 -0.847566 -0.882343I4 -0.638228 -0.282882 -0.624997 -0.245980I5 -0.229769 1.002930 -0.226715 -0.916591>>> >>> obj[['a', 'd']] a dI1 -1.083223 -1.572120I2 -0.205206 0.847720I3 -0.980379 -0.882343I4 -0.638228 -0.245980I5 -0.229769 -0.916591 【2.2.5】布尔索引 可以通过一个布尔数组来索引目标数组,即通过布尔运算(如:比较运算符)来获取符合指定条件的元素的数组。 >>> import pandas as pd>>> import numpy as np>>> data = np.random.randn(5,4)>>> index = ['I1', 'I2', 'I3', 'I4', 'I5']>>> columns = ['a', 'b', 'c', 'd']>>> obj = pd.DataFrame(data, index, columns)>>> obj a b c dI1 -0.602984 -0.135716 0.999689 -0.339786I2 0.911130 -0.092485 -0.914074 -0.279588I3 0.849606 -0.420055 -1.240389 -0.179297I4 0.249986 -1.250668 0.329416 -1.105774I5 -0.743816 0.430647 -0.058126 -0.337319>>> >>> obj[obj > 0] a b c dI1 NaN NaN 0.999689 NaNI2 0.911130 NaN NaN NaNI3 0.849606 NaN NaN NaNI4 0.249986 NaN 0.329416 NaNI5 NaN 0.430647 NaN NaN>>> >>> obj > 0 a b c dI1 False False True FalseI2 True False False FalseI3 True False False FalseI4 True False True FalseI5 False True False False 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106698307未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【3】索引器:loc 和 iloc loc 是标签索引、iloc 是位置索引,注意:在 Pandas1.0.0 之前还有 ix 方法(即可按标签也可按位置索引),在 Pandas1.0.0 之后已被移除。 【3.1】loc 标签索引 loc 标签索引,即根据 index 和 columns 来选择数据。 【3.1.1】Series.loc 在 Series 中,允许输入: 单个标签,例如 5 或 'a',(注意,5 是 index 的名称,而不是位置索引); 标签列表或数组,例如 ['a', 'b', 'c']; 带有标签的切片对象,例如 'a':'f'。 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.Series.loc.html >>> import pandas as np>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> obja 1b 5c -8d 2dtype: int64>>> >>> obj.loc['a']1>>> >>> obj.loc['a':'c']a 1b 5c -8dtype: int64>>>>>> obj.loc[['a', 'd']]a 1d 2dtype: int64 【3.1.2】DataFrame.loc 在 DataFrame 中,第一个参数索引行,第二个参数是索引列,允许输入的格式和 Series 大同小异。 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.loc.html >>> import pandas as pd>>> obj = pd.DataFrame([[1, 2, 3], [4, 5, 6], [7, 8, 9]], index=['a', 'b', 'c'], columns=['A', 'B', 'C'])>>> obj A B Ca 1 2 3b 4 5 6c 7 8 9>>> >>> obj.loc['a']A 1B 2C 3Name: a, dtype: int64>>> >>> obj.loc['a':'c'] A B Ca 1 2 3b 4 5 6c 7 8 9>>> >>> obj.loc[['a', 'c']] A B Ca 1 2 3c 7 8 9>>> >>> obj.loc['b', 'B']5>>> obj.loc['b', 'A':'C']A 4B 5C 6Name: b, dtype: int64 【3.2】iloc 位置索引 作用和 loc 一样,不过是基于索引的编号来索引,即根据 index 和 columns 的位置编号来选择数据。 【3.2.1】Series.iloc 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.Series.iloc.html 在 Series 中,允许输入: 整数,例如 5; 整数列表或数组,例如 [4, 3, 0]; 具有整数的切片对象,例如 1:7。 >>> import pandas as np>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> obja 1b 5c -8d 2dtype: int64>>> >>> obj.iloc[1]5>>> >>> obj.iloc[0:2]a 1b 5dtype: int64>>> >>> obj.iloc[[0, 1, 3]]a 1b 5d 2dtype: int64 【3.2.2】DataFrame.iloc 官方文档:https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.iloc.html 在 DataFrame 中,第一个参数索引行,第二个参数是索引列,允许输入的格式和 Series 大同小异: >>> import pandas as pd>>> obj = pd.DataFrame([[1, 2, 3], [4, 5, 6], [7, 8, 9]], index=['a', 'b', 'c'], columns=['A', 'B', 'C'])>>> obj A B Ca 1 2 3b 4 5 6c 7 8 9>>> >>> obj.iloc[1]A 4B 5C 6Name: b, dtype: int64>>> >>> obj.iloc[0:2] A B Ca 1 2 3b 4 5 6>>> >>> obj.iloc[[0, 2]] A B Ca 1 2 3c 7 8 9>>> >>> obj.iloc[1, 2]6>>> >>> obj.iloc[1, 0:2]A 4B 5Name: b, dtype: int64 【4】Pandas 重新索引 Pandas 对象的一个重要方法是 reindex,其作用是创建一个新对象,它的数据符合新的索引。以 DataFrame.reindex 为例(Series 类似),基本语法如下: DataFrame.reindex(self, labels=None, index=None, columns=None, axis=None, method=None, copy=True, level=None, fill_value=nan, limit=None, tolerance=None) 部分参数描述如下:(完整参数解释参见官方文档) 参数描述 index用作索引的新序列,既可以是 index 实例,也可以是其他序列型的 Python 数据结构 method插值(填充)方式,取值如下: None:不填补空白; pad / ffill:将上一个有效的观测值向前传播到下一个有效的观测值; backfill / bfill:使用下一个有效观察值来填补空白; nearest:使用最近的有效观测值来填补空白。 fill_value在重新索引的过程中,需要引入缺失值时使用的替代值 limit前向或后向填充时的最大填充量 tolerance向前或向后填充时,填充不准确匹配项的最大间距(绝对值距离) level在 Multilndex 的指定级别上匹配简单索引,否则选其子集 copy默认为 True,无论如何都复制;如果为 False,则新旧相等就不复制 reindex 将会根据新索引进行重排。如果某个索引值当前不存在,就引入缺失值: >>> import pandas as pd>>> obj = pd.Series([4.5, 7.2, -5.3, 3.6], index=['d', 'b', 'a', 'c'])>>> objd 4.5b 7.2a -5.3c 3.6dtype: float64>>> >>> obj2 = obj.reindex(['a', 'b', 'c', 'd', 'e'])>>> obj2a -5.3b 7.2c 3.6d 4.5e NaNdtype: float64 对于时间序列这样的有序数据,重新索引时可能需要做一些插值处理。method 选项即可达到此目的,例如,使用 ffill 可以实现前向值填充: >>> import pandas as pd>>> obj = pd.Series(['blue', 'purple', 'yellow'], index=[0, 2, 4])>>> obj0 blue2 purple4 yellowdtype: object>>> >>> obj2 = obj.reindex(range(6), method='ffill')>>> obj20 blue1 blue2 purple3 purple4 yellow5 yellowdtype: object 借助 DataFrame,reindex可以修改(行)索引和列。只传递一个序列时,会重新索引结果的行: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame(np.arange(9).reshape((3, 3)), index=['a', 'c', 'd'], columns=['Ohio', 'Texas', 'California'])>>> obj Ohio Texas Californiaa 0 1 2c 3 4 5d 6 7 8>>> >>> obj2 = obj.reindex(['a', 'b', 'c', 'd'])>>> obj2 Ohio Texas Californiaa 0.0 1.0 2.0b NaN NaN NaNc 3.0 4.0 5.0d 6.0 7.0 8.0 列可以用 columns 关键字重新索引: >>> import pandas as pd>>> import numpy as np>>> obj = pd.DataFrame(np.arange(9).reshape((3, 3)), index=['a', 'c', 'd'], columns=['Ohio', 'Texas', 'California'])>>> obj Ohio Texas Californiaa 0 1 2c 3 4 5d 6 7 8>>> >>> states = ['Texas', 'Utah', 'California']>>> obj.reindex(columns=states) Texas Utah Californiaa 1 NaN 2c 4 NaN 5d 7 NaN 8 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106698307未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【01x00】了解 Pandas 【02x00】Pandas 数据结构 【03x00】Series 对象 【03x01】通过 list 构建 Series 【03x02】通过 dict 构建 Series 【03x03】获取其数据和索引 【03x04】通过索引获取数据 【03x05】使用函数运算 【03x06】name 属性 【04x00】DataFrame 对象 【03x01】通过 ndarray 构建 DataFrame 【03x02】通过 dict 构建 DataFrame 【03x03】获取其数据和索引 【03x04】通过索引获取数据 【03x05】修改列的值 【03x06】增加 / 删除列 【03x07】name 属性 Pandas 系列文章: Python 数据分析三剑客之 Pandas(一):认识 Pandas 及其 Series、DataFrame 对象 Python 数据分析三剑客之 Pandas(二):Index 索引对象以及各种索引操作 Python 数据分析三剑客之 Pandas(三):算术运算与缺失值的处理 Python 数据分析三剑客之 Pandas(四):函数应用、映射、排序和层级索引 Python 数据分析三剑客之 Pandas(五):统计计算与统计描述 Python 数据分析三剑客之 Pandas(六):GroupBy 数据分裂、应用与合并 Python 数据分析三剑客之 Pandas(七):合并数据集 Python 数据分析三剑客之 Pandas(八):数据重塑、重复数据处理与数据替换 Python 数据分析三剑客之 Pandas(九):时间序列 Python 数据分析三剑客之 Pandas(十):数据读写 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106676693未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【01x00】了解 Pandas Pandas 是 Python 的一个数据分析包,是基于 NumPy 构建的,最初由 AQR Capital Management 于 2008 年 4 月开发,并于 2009 年底开源出来,目前由专注于 Python 数据包开发的 PyData 开发团队继续开发和维护,属于 PyData 项目的一部分。 Pandas 最初被作为金融数据分析工具而开发出来,因此,Pandas 为时间序列分析提供了很好的支持。Pandas 的名称来自于面板数据(panel data)和 Python 数据分析(data analysis)。panel data 是经济学中关于多维数据集的一个术语,在 Pandas 中也提供了 panel 的数据类型。 Pandas 经常和其它工具一同使用,如数值计算工具 NumPy 和 SciPy,分析库 statsmodels 和 scikit-learn,数据可视化库 Matplotlib 等,虽然 Pandas 采用了大量的 NumPy 编码风格,但二者最大的不同是 Pandas 是专门为处理表格和混杂数据设计的。而 NumPy 更适合处理统一的数值数组数据。 【以下对 Pandas 的解释翻译自官方文档:https://pandas.pydata.org/docs/getting_started/overview.html#package-overview】 Pandas 是 Python 的核心数据分析支持库,提供了快速、灵活、明确的数据结构,旨在简单、直观地处理关系型、标记型数据。Pandas 的目标是成为 Python 数据分析实践与实战的必备高级工具,其长远目标是成为最强大、最灵活、可以支持任何语言的开源数据分析工具。经过多年不懈的努力,Pandas 离这个目标已经越来越近了。 Pandas 适用于处理以下类型的数据: 与 SQL 或 Excel 表类似的,含异构列的表格数据; 有序和无序(非固定频率)的时间序列数据; 带行列标签的矩阵数据,包括同构或异构型数据; 任意其它形式的观测、统计数据集, 数据转入 Pandas 数据结构时不必事先标记。 Pandas 的主要数据结构是 Series(一维数据)与 DataFrame(二维数据),这两种数据结构足以处理- 金融、统计、社会科学、工程等领域里的大多数典型用例。对于 R 语言用户,DataFrame 提供了比 R 语言 data.frame 更丰富的功能。Pandas 基于 NumPy 开发,可以与其它第三方科学计算支持库完美集成。 Pandas 就像一把万能瑞士军刀,下面仅列出了它的部分优势 : 处理浮点与非浮点数据里的缺失数据,表示为 NaN; 大小可变:插入或删除 DataFrame 等多维对象的列; 自动、显式数据对齐:显式地将对象与一组标签对齐,也可以忽略标签,在 Series、DataFrame 计算时自动与数据对齐; 强大、灵活的分组(group by)功能:拆分-应用-组合数据集,聚合、转换数据; 把 Python 和 NumPy 数据结构里不规则、不同索引的数据轻松地转换为 DataFrame 对象; 基于智能标签,对大型数据集进行切片、花式索引、子集分解等操作; 直观地合并和连接数据集; 灵活地重塑和旋转数据集; 轴支持分层标签(每个刻度可能有多个标签); 强大的 IO 工具,读取平面文件(CSV 等支持分隔符的文件)、Excel 文件、数据库等来源的数据,以及从超快 HDF5 格式保存 / 加载数据; 时间序列:支持日期范围生成、频率转换、移动窗口统计、移动窗口线性回归、日期位移等时间序列功能。 这些功能主要是为了解决其它编程语言、科研环境的痛点。处理数据一般分为几个阶段:数据整理与清洗、数据分析与建模、数据可视化与制表,Pandas 是处理数据的理想工具。 其它说明: Pandas 速度很快。Pandas 的很多底层算法都用 Cython 优化过。然而,为了保持通用性,必然要牺牲一些性能,如果专注某一功能,完全可以开发出比 Pandas 更快的专用工具。 Pandas 是 statsmodels 的依赖项,因此,Pandas 也是 Python 中统计计算生态系统的重要组成部分。 Pandas 已广泛应用于金融领域。 【02x00】Pandas 数据结构 Pandas 的主要数据结构是 Series(带标签的一维同构数组)与 DataFrame(带标签的,大小可变的二维异构表格)。 Pandas 数据结构就像是低维数据的容器。比如,DataFrame 是 Series 的容器,Series 则是标量的容器。使用这种方式,可以在容器中以字典的形式插入或删除对象。 此外,通用 API 函数的默认操作要顾及时间序列与截面数据集的方向。当使用 Ndarray 存储二维或三维数据时,编写函数要注意数据集的方向,这对用户来说是一种负担;如果不考虑 C 或 Fortran 中连续性对性能的影响,一般情况下,不同的轴在程序里其实没有什么区别。Pandas 里,轴的概念主要是为了给数据赋予更直观的语义,即用更恰当的方式表示数据集的方向。这样做可以让用户编写数据转换函数时,少费点脑子。 处理 DataFrame 等表格数据时,对比 Numpy,index(行)或 columns(列)比 axis 0 和 axis 1 更直观。用这种方式迭代 DataFrame 的列,代码更易读易懂: for col in df.columns: series = df[col] # do something with series 【03x00】Series 对象 Series 是带标签的一维数组,可存储整数、浮点数、字符串、Python 对象等类型的数据。轴标签统称为索引。调用 pandas.Series 函数即可创建 Series,基本语法如下: pandas.Series(data=None[, index=None, dtype=None, name=None, copy=False, fastpath=False]) 参数描述 data数组类型,可迭代的,字典或标量值,存储在序列中的数据 index索引(数据标签),值必须是可哈希的,并且具有与数据相同的长度, 允许使用非唯一索引值。如果未提供,将默认为RangeIndex(0,1,2,…,n) dtype输出系列的数据类型。可选项,如果未指定,则将从数据中推断,具体参考官网 dtypes 介绍 namestr 类型,可选项,给 Series 命名 copybool 类型,可选项,默认 False,是否复制输入数据 【03x01】通过 list 构建 Series 一般情况下我们只会用到 data 和 index 参数,可以通过 list(列表) 构建 Series,示例如下: >>> import pandas as pd>>> obj = pd.Series([1, 5, -8, 2])>>> obj0 11 52 -83 2dtype: int64 由于我们没有为数据指定索引,于是会自动创建一个 0 到 N-1(N 为数据的长度)的整数型索引,左边一列是自动创建的索引(index),右边一列是数据(data)。 此外,还可以自定义索引(index): >>> import pandas as pd>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> obja 1b 5c -8d 2dtype: int64 索引(index)也可以通过赋值的方式就地修改: >>> import pandas as pd>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> obja 1b 5c -8d 2dtype: int64>>> obj.index = ['Bob', 'Steve', 'Jeff', 'Ryan']>>> objBob 1Steve 5Jeff -8Ryan 2dtype: int64 【03x02】通过 dict 构建 Series 通过 字典(dict) 构建 Series,字典的键(key)会作为索引(index),字典的值(value)会作为数据(data),示例如下: >>> import pandas as pd>>> data = {'Beijing': 21530000, 'Shanghai': 24280000, 'Wuhan': 11210000, 'Zhejiang': 58500000}>>> obj = pd.Series(data)>>> objBeijing 21530000Shanghai 24280000Wuhan 11210000Zhejiang 58500000dtype: int64 如果你想按照某个特定的顺序输出结果,可以传入排好序的字典的键以改变顺序: >>> import pandas as pd>>> data = {'Beijing': 21530000, 'Shanghai': 24280000, 'Wuhan': 11210000, 'Zhejiang': 58500000}>>> cities = ['Guangzhou', 'Wuhan', 'Zhejiang', 'Shanghai']>>> obj = pd.Series(data, index=cities)>>> objGuangzhou NaNWuhan 11210000.0Zhejiang 58500000.0Shanghai 24280000.0dtype: float64 注意:data 为字典,且未设置 index 参数时: 如果 Python >= 3.6 且 Pandas >= 0.23,Series 按字典的插入顺序排序索引。 如果 Python < 3.6 或 Pandas < 0.23,Series 按字母顺序排序索引。 【03x03】获取其数据和索引 我们可以通过 Series 的 values 和 index 属性获取其数据和索引对象: >>> import pandas as pd>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> obj.valuesarray([ 1, 5, -8, 2], dtype=int64)>>> obj.indexIndex(['a', 'b', 'c', 'd'], dtype='object') 【03x04】通过索引获取数据 与普通 NumPy 数组相比,Pandas 可以通过索引的方式选取 Series 中的单个或一组值,获取一组值时,传入的是一个列表,列表中的元素是索引值,另外还可以通过索引来修改其对应的值: >>> import pandas as pd>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> obja 1b 5c -8d 2dtype: int64>>> obj['a']1>>> obj['a'] = 3>>> obj[['a', 'b', 'c']]a 3b 5c -8dtype: int64 【03x05】使用函数运算 在 Pandas 中可以使用 NumPy 函数或类似 NumPy 的运算(如根据布尔型数组进行过滤、标量乘法、应用数学函数等): >>> import pandas as pd>>> import numpy as np>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> obj[obj > 0]a 1b 5d 2dtype: int64>>> obj * 2a 2b 10c -16d 4dtype: int64>>> np.exp(obj)a 2.718282b 148.413159c 0.000335d 7.389056dtype: float64 除了这些运算函数以外,还可以将 Series 看成是一个定长的有序字典,因为它是索引值到数据值的一个映射。它可以用在许多原本需要字典参数的函数中: >>> import pandas as pd>>> obj = pd.Series([1, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> 'a' in objTrue>>> 'e' in objFalse 和 NumPy 类似,Pandas 中也有 NaN(即非数字,not a number),在 Pandas 中,它用于表示缺失值,Pandas 的 isnull 和 notnull 函数可用于检测缺失数据: >>> import pandas as pd>>> import numpy as np>>> obj = pd.Series([np.NaN, 5, -8, 2], index=['a', 'b', 'c', 'd'])>>> obja NaNb 5.0c -8.0d 2.0dtype: float64>>> pd.isnull(obj)a Trueb Falsec Falsed Falsedtype: bool>>> pd.notnull(obj)a Falseb Truec Trued Truedtype: bool>>> obj.isnull()a Trueb Falsec Falsed Falsedtype: bool>>> obj.notnull()a Falseb Truec Trued Truedtype: bool 【03x06】name 属性 可以在 pandas.Series 方法中为 Series 对象指定一个 name: >>> import pandas as pd>>> data = {'Beijing': 21530000, 'Shanghai': 24280000, 'Wuhan': 11210000, 'Zhejiang': 58500000}>>> obj = pd.Series(data, name='population')>>> objBeijing 21530000Shanghai 24280000Wuhan 11210000Zhejiang 58500000Name: population, dtype: int64 也可以通过 name 和 index.name 属性为 Series 对象和其索引指定 name: >>> import pandas as pd>>> data = {'Beijing': 21530000, 'Shanghai': 24280000, 'Wuhan': 11210000, 'Zhejiang': 58500000}>>> obj = pd.Series(data)>>> obj.name = 'population'>>> obj.index.name = 'cities'>>> objcitiesBeijing 21530000Shanghai 24280000Wuhan 11210000Zhejiang 58500000Name: population, dtype: int64 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106676693未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【04x00】DataFrame 对象 DataFrame 是一个表格型的数据结构,它含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔值等)。DataFrame 既有行索引也有列索引,它可以被看做由 Series 组成的字典(共用同一个索引)。DataFrame 中的数据是以一个或多个二维块存放的(而不是列表、字典或别的一维数据结构)。 类似多维数组/表格数据 (如Excel、R 语言中的 data.frame); 每列数据可以是不同的类型; 索引包括列索引和行索引 基本语法如下: pandas.DataFrame(data=None, index: Optional[Collection] = None, columns: Optional[Collection] = None, dtype: Union[str, numpy.dtype, ExtensionDtype, None] = None, copy: bool = False) 参数描述 datandarray 对象(结构化或同类的)、可迭代的或者字典形式,存储在序列中的数据 index数组类型,索引(数据标签),如果未提供,将默认为 RangeIndex(0,1,2,…,n) columns列标签。如果未提供,则将默认为 RangeIndex(0、1、2、…、n) dtype输出系列的数据类型。可选项,如果未指定,则将从数据中推断,具体参考官网 dtypes 介绍 copybool 类型,可选项,默认 False,是否复制输入数据,仅影响 DataFrame/2d ndarray 输入 【03x01】通过 ndarray 构建 DataFrame >>> import numpy as np>>> import pandas as pd>>> data = np.random.randn(5,3)>>> dataarray([[-2.16231157, 0.44967198, -0.73131523], [ 1.18982913, 0.94670798, 0.82973421], [-1.57680831, -0.99732066, 0.96432 ], [-0.77483149, -1.23802881, 0.44061227], [ 1.77666419, 0.24931983, -1.12960153]])>>> obj = pd.DataFrame(data)>>> obj 0 1 20 -2.162312 0.449672 -0.7313151 1.189829 0.946708 0.8297342 -1.576808 -0.997321 0.9643203 -0.774831 -1.238029 0.4406124 1.776664 0.249320 -1.129602 指定索引(index)和列标签(columns),和 Series 对象类似,可以在构建的时候添加索引和标签,也可以直接通过赋值的方式就地修改: >>> import numpy as np>>> import pandas as pd>>> data = np.random.randn(5,3)>>> index = ['a', 'b', 'c', 'd', 'e']>>> columns = ['A', 'B', 'C']>>> obj = pd.DataFrame(data, index, columns)>>> obj A B Ca -1.042909 -0.238236 -1.050308b 0.587079 0.739683 -0.233624c -0.451254 -0.638496 1.708807d -0.620158 -1.875929 -0.432382e -1.093815 0.396965 -0.759479>>>>>> obj.index = ['A1', 'A2', 'A3', 'A4', 'A5']>>> obj.columns = ['B1', 'B2', 'B3']>>> obj B1 B2 B3A1 -1.042909 -0.238236 -1.050308A2 0.587079 0.739683 -0.233624A3 -0.451254 -0.638496 1.708807A4 -0.620158 -1.875929 -0.432382A5 -1.093815 0.396965 -0.759479 【03x02】通过 dict 构建 DataFrame 通过 字典(dict) 构建 DataFrame,字典的键(key)会作为列标签(columns),字典的值(value)会作为数据(data),示例如下: >>> import pandas as pd>>> data = {'city': ['Wuhan', 'Wuhan', 'Wuhan', 'Beijing', 'Beijing', 'Beijing'], 'year': [2017, 2018, 2019, 2017, 2018, 2019], 'people': [10892900, 11081000, 11212000, 21707000, 21542000, 21536000]}>>> obj = pd.DataFrame(data)>>> obj city year people0 Wuhan 2017 108929001 Wuhan 2018 110810002 Wuhan 2019 112120003 Beijing 2017 217070004 Beijing 2018 215420005 Beijing 2019 21536000 如果指定了列序列,则 DataFrame 的列就会按照指定顺序进行排列,如果传入的列在数据中找不到,就会在结果中产生缺失值(NaN): >>> import pandas as pd>>> data = {'city': ['Wuhan', 'Wuhan', 'Wuhan', 'Beijing', 'Beijing', 'Beijing'], 'year': [2017, 2018, 2019, 2017, 2018, 2019], 'people': [10892900, 11081000, 11212000, 21707000, 21542000, 21536000]}>>> pd.DataFrame(data) city year people0 Wuhan 2017 108929001 Wuhan 2018 110810002 Wuhan 2019 112120003 Beijing 2017 217070004 Beijing 2018 215420005 Beijing 2019 21536000>>> pd.DataFrame(data, columns=['year', 'city', 'people']) year city people0 2017 Wuhan 108929001 2018 Wuhan 110810002 2019 Wuhan 112120003 2017 Beijing 217070004 2018 Beijing 215420005 2019 Beijing 21536000>>> pd.DataFrame(data, columns=['year', 'city', 'people', 'money']) year city people money0 2017 Wuhan 10892900 NaN1 2018 Wuhan 11081000 NaN2 2019 Wuhan 11212000 NaN3 2017 Beijing 21707000 NaN4 2018 Beijing 21542000 NaN5 2019 Beijing 21536000 NaN 注意:data 为字典,且未设置 columns 参数时: Python > = 3.6 且 Pandas > = 0.23,DataFrame 的列按字典的插入顺序排序。 Python < 3.6 或 Pandas < 0.23,DataFrame 的列按字典键的字母排序。 【03x03】获取其数据和索引 和 Series 一样,DataFrame 也可以通过其 values 和 index 属性获取其数据和索引对象: >>> import numpy as np>>> import pandas as pd>>> data = {'city': ['Wuhan', 'Wuhan', 'Wuhan', 'Beijing', 'Beijing', 'Beijing'], 'year': [2017, 2018, 2019, 2017, 2018, 2019], 'people': [10892900, 11081000, 11212000, 21707000, 21542000, 21536000]}>>> obj = pd.DataFrame(data)>>> obj.indexRangeIndex(start=0, stop=6, step=1)>>> obj.valuesarray([['Wuhan', 2017, 10892900], ['Wuhan', 2018, 11081000], ['Wuhan', 2019, 11212000], ['Beijing', 2017, 21707000], ['Beijing', 2018, 21542000], ['Beijing', 2019, 21536000]], dtype=object) 【03x04】通过索引获取数据 通过类似字典标记的方式或属性的方式,可以将 DataFrame 的列获取为一个 Series 对象; 行也可以通过位置或名称的方式进行获取,比如用 loc 属性; 对于特别大的 DataFrame,有一个 head 方法可以选取前五行数据。 用法示例: >>> import numpy as np>>> import pandas as pd>>> data = {'city': ['Wuhan', 'Wuhan', 'Wuhan', 'Beijing', 'Beijing', 'Beijing'], 'year': [2017, 2018, 2019, 2017, 2018, 2019], 'people': [10892900, 11081000, 11212000, 21707000, 21542000, 21536000]}>>> obj = pd.DataFrame(data)>>> obj city year people0 Wuhan 2017 108929001 Wuhan 2018 110810002 Wuhan 2019 112120003 Beijing 2017 217070004 Beijing 2018 215420005 Beijing 2019 21536000>>>>>> obj['city']0 Wuhan1 Wuhan2 Wuhan3 Beijing4 Beijing5 BeijingName: city, dtype: object>>>>>> obj.year0 20171 20182 20193 20174 20185 2019Name: year, dtype: int64>>>>>> type(obj.year)<class 'pandas.core.series.Series'>>>>>>> obj.loc[2]city Wuhanyear 2019people 11212000Name: 2, dtype: object>>>>>> obj.head() city year people0 Wuhan 2017 108929001 Wuhan 2018 110810002 Wuhan 2019 112120003 Beijing 2017 217070004 Beijing 2018 21542000 【03x05】修改列的值 列可以通过赋值的方式进行修改。在下面示例中,分别给"money"列赋上一个标量值和一组值: >>> import pandas as pd>>> import numpy as np>>> data = {'city': ['Wuhan', 'Wuhan', 'Wuhan', 'Beijing', 'Beijing', 'Beijing'], 'year': [2017, 2018, 2019, 2017, 2018, 2019], 'people': [10892900, 11081000, 11212000, 21707000, 21542000, 21536000], 'money':[np.NaN, np.NaN, np.NaN, np.NaN, np.NaN, np.NaN]}>>> obj = pd.DataFrame(data, index=['A', 'B', 'C', 'D', 'E', 'F'])>>> obj city year people moneyA Wuhan 2017 10892900 NaNB Wuhan 2018 11081000 NaNC Wuhan 2019 11212000 NaND Beijing 2017 21707000 NaNE Beijing 2018 21542000 NaNF Beijing 2019 21536000 NaN>>>>>> obj['money'] = 6666666666>>> obj city year people moneyA Wuhan 2017 10892900 6666666666B Wuhan 2018 11081000 6666666666C Wuhan 2019 11212000 6666666666D Beijing 2017 21707000 6666666666E Beijing 2018 21542000 6666666666F Beijing 2019 21536000 6666666666>>>>>> obj['money'] = np.arange(100000000, 700000000, 100000000)>>> obj city year people moneyA Wuhan 2017 10892900 100000000B Wuhan 2018 11081000 200000000C Wuhan 2019 11212000 300000000D Beijing 2017 21707000 400000000E Beijing 2018 21542000 500000000F Beijing 2019 21536000 600000000 将列表或数组赋值给某个列时,其长度必须跟 DataFrame 的长度相匹配。如果赋值的是一个 Series,就会精确匹配 DataFrame 的索引: >>> import pandas as pd>>> import numpy as np>>> data = {'city': ['Wuhan', 'Wuhan', 'Wuhan', 'Beijing', 'Beijing', 'Beijing'], 'year': [2017, 2018, 2019, 2017, 2018, 2019], 'people': [10892900, 11081000, 11212000, 21707000, 21542000, 21536000], 'money':[np.NaN, np.NaN, np.NaN, np.NaN, np.NaN, np.NaN]}>>> obj = pd.DataFrame(data, index=['A', 'B', 'C', 'D', 'E', 'F'])>>> obj city year people moneyA Wuhan 2017 10892900 NaNB Wuhan 2018 11081000 NaNC Wuhan 2019 11212000 NaND Beijing 2017 21707000 NaNE Beijing 2018 21542000 NaNF Beijing 2019 21536000 NaN>>> >>> new_data = pd.Series([5670000000, 6890000000, 7890000000], index=['A', 'C', 'E'])>>> obj['money'] = new_data>>> obj city year people moneyA Wuhan 2017 10892900 5.670000e+09B Wuhan 2018 11081000 NaNC Wuhan 2019 11212000 6.890000e+09D Beijing 2017 21707000 NaNE Beijing 2018 21542000 7.890000e+09F Beijing 2019 21536000 NaN 【03x06】增加 / 删除列 为不存在的列赋值会创建出一个新列,关键字 del 用于删除列: >>> import pandas as pd>>> data = {'city': ['Wuhan', 'Wuhan', 'Wuhan', 'Beijing', 'Beijing', 'Beijing'], 'year': [2017, 2018, 2019, 2017, 2018, 2019], 'people': [10892900, 11081000, 11212000, 21707000, 21542000, 21536000]}>>> obj = pd.DataFrame(data)>>> obj city year people0 Wuhan 2017 108929001 Wuhan 2018 110810002 Wuhan 2019 112120003 Beijing 2017 217070004 Beijing 2018 215420005 Beijing 2019 21536000>>> >>> obj['northern'] = obj['city'] == 'Beijing'>>> obj city year people northern0 Wuhan 2017 10892900 False1 Wuhan 2018 11081000 False2 Wuhan 2019 11212000 False3 Beijing 2017 21707000 True4 Beijing 2018 21542000 True5 Beijing 2019 21536000 True>>> >>> del obj['northern']>>> obj city year people0 Wuhan 2017 108929001 Wuhan 2018 110810002 Wuhan 2019 112120003 Beijing 2017 217070004 Beijing 2018 215420005 Beijing 2019 21536000 【03x07】name 属性 可以通过 index.name 和 columns.name 属性设置索引(index)和列标签(columns)的 name,注意 DataFrame 对象是没有 name 属性的: >>> import pandas as pd>>> data = {'city': ['Wuhan', 'Wuhan', 'Wuhan', 'Beijing', 'Beijing', 'Beijing'], 'year': [2017, 2018, 2019, 2017, 2018, 2019], 'people': [10892900, 11081000, 11212000, 21707000, 21542000, 21536000]}>>> obj = pd.DataFrame(data)>>> obj.index.name = 'index'>>> obj.columns.name = 'columns'>>> objcolumns city year peopleindex 0 Wuhan 2017 108929001 Wuhan 2018 110810002 Wuhan 2019 112120003 Beijing 2017 217070004 Beijing 2018 215420005 Beijing 2019 21536000 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106676693未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【1x00】介绍(Introduction) 【2x00】准备工作(Setup) 【3x00】关联(Correlation) 【01】散点图(Scatter plot) 【02】带边界的气泡图(Bubble plot with Encircling) 【03】带线性回归最佳拟合线的散点图(Scatter plot with linear regression line of best fit) 【04】抖动图(Jittering with stripplot) 【05】计数图(Counts Plot) 【06】边缘直方图(Marginal Histogram) 【07】边缘箱形图(Marginal Boxplot) 【08】相关图(Correllogram) 【09】成对图(Pairwise Plot) 【4x00】偏差(Deviation) 【10】发散型条形图(Diverging Bars) 【11】发散型文本图(Diverging Texts) 【12】发散型散点图(Diverging Dot Plot) 【13】带标记的发散型棒棒糖图(Diverging Lollipop Chart with Markers) 【14】面积图(Area Chart) 【5x00】排序(Ranking) 【15】有序条形图(Ordered Bar Chart) 【16】棒棒糖图(Lollipop Chart) 【17】点图(Dot Plot) 【18】坡度图(Slope Chart) 【19】哑铃图(Dumbbell Plot) 【6x00】分布(Distribution) 【20】连续变量的直方图(Histogram for Continuous Variable) 【21】分类变量的直方图(Histogram for Categorical Variable) 【22】密度图(Density Plot) 【23】直方图密度曲线(Density Curves with Histogram) 【24】山峰叠峦图 / 欢乐图(Joy Plot) 【25】分布式点图(Distributed Dot Plot) 【26】箱形图(Box Plot) 【27】点 + 箱形图(Dot + Box Plot) 【28】小提琴图(Violin Plot) 【29】人口金字塔图(Population Pyramid) 【30】分类图(Categorical Plots) 【7x00】组成(Composition) 【31】华夫饼图(Waffle Chart) 【32】饼图(Pie Chart) 【33】矩阵树形图(Treemap) 【34】条形图(Bar Chart) 【8x00】变化(Change) 【35】时间序列图(Time Series Plot) 【36】带波峰和波谷注释的时间序列图(Time Series with Peaks and Troughs Annotated) 【37】自相关 (ACF) 和部分自相关 (PACF) 图(Autocorrelation (ACF) and Partial Autocorrelation (PACF) Plot) 【38】交叉相关图(Cross Correlation plot) 【39】时间序列分解图(Time Series Decomposition Plot) 【40】多重时间序列(Multiple Time Series) 【41】使用次要的 Y 轴来绘制不同范围的图形(Plotting with different scales using secondary Y axis) 【42】带误差带的时间序列(Time Series with Error Bands) 【43】堆积面积图(Stacked Area Chart) 【44】未堆积面积图(Area Chart UnStacked) 【45】日历热力图(Calendar Heat Map) 【46】季节图(Seasonal Plot) 【9x00】分组( Groups) 【47】树状图(Dendrogram) 【48】聚类图(Cluster Plot) 【49】安德鲁斯曲线(Andrews Curve) 【50】平行坐标图(Parallel Coordinates) Matplotlib 系列文章: Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件 Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性 Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性 Python 数据分析三剑客之 Matplotlib(四):线性图的绘制 Python 数据分析三剑客之 Matplotlib(五):散点图的绘制 Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制 Python 数据分析三剑客之 Matplotlib(七):饼状图的绘制 Python 数据分析三剑客之 Matplotlib(八):等高线 / 等值线图的绘制 Python 数据分析三剑客之 Matplotlib(九):极区图 / 极坐标图 / 雷达图的绘制 Python 数据分析三剑客之 Matplotlib(十):3D 图的绘制 Python 数据分析三剑客之 Matplotlib(十一):最热门最常用的 50 个图表【译文】 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 翻译丨TRHX 作者丨Selva Prabhakaran 原文丨《Top 50 matplotlib Visualizations – The Master Plots (with full python code)》 ★ 本文中的示例原作者使用的编辑器为 Jupyter Notebook; ★ 译者使用 PyCharm 测试原文中有部分代码不太准确,部分已进行修改,对应有注释说明; ★ 运行本文代码,需要安装 Matplotlib 和 Seaborn 等可视化库,其他的一些辅助可视化库已在代码部分作标注; ★ 示例中用到的数据均储存在作者的 GitHub:https://github.com/selva86/datasets,因此运行程序可能需要FQ; ★ 译者英文水平有限,若遇到翻译模糊的词建议参考原文来理解。 ★ 本文50个示例代码已打包为 .py 文件,可直接下载:https://download.csdn.net/download/qq_36759224/12507219 这里是一段物理防爬虫文本,请读者忽略。本译文首发于 CSDN,作者 Selva Prabhakaran,译者 TRHX。本文链接:https://itrhx.blog.csdn.net/article/details/106558131原文链接:https://www.machinelearningplus.com/plots/top-50-matplotlib-visualizations-the-master-plots-python/ 【1x00】介绍(Introduction) 在数据分析和可视化中最常用的、最有价值的前 50 个 Matplotlib 图表。这些图表会让你懂得在不同情况下合理使用 Python 的 Matplotlib 和 Seaborn 库来达到数据可视化效果。 这些图表根据可视化目标的 7 个不同情景进行分组。 例如,如果要想象两个变量之间的关系,请查看“关联”部分下的图表。 或者,如果您想要显示值如何随时间变化,请查看“变化”部分,依此类推。 有效图表的重要特征: 在不歪曲事实的情况下传达正确和必要的信息; 设计简单,不必太费力就能理解它; 从审美角度支持信息而不是掩盖信息; 信息没有超负荷。 【2x00】准备工作(Setup) 在代码运行前先引入下面的基本设置,当然,个别图表可能会重新定义显示要素。 # !pip install brewer2mplimport numpy as npimport pandas as pdimport matplotlib as mplimport matplotlib.pyplot as pltimport seaborn as snsimport warnings; warnings.filterwarnings(action='once')large = 22; med = 16; small = 12params = {'axes.titlesize': large, 'legend.fontsize': med, 'figure.figsize': (16, 10), 'axes.labelsize': med, 'axes.titlesize': med, 'xtick.labelsize': med, 'ytick.labelsize': med, 'figure.titlesize': large}plt.rcParams.update(params)plt.style.use('seaborn-whitegrid')sns.set_style("white")%matplotlib inline# Versionprint(mpl.__version__) #> 3.0.0print(sns.__version__) #> 0.9.0 【3x00】关联(Correlation) 关联图用于可视化两个或多个变量之间的关系。也就是说,一个变量相对于另一个变量如何变化。 【01】散点图(Scatter plot) 散点图是研究两个变量之间关系的经典和基本的绘图。如果数据中有多个组,则可能需要以不同的颜色显示每个组。在 Matplotlib 中,您可以使用 plt.scatterplot() 方便地执行此操作。 # Import dataset midwest = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/midwest_filter.csv")# Prepare Data # Create as many colors as there are unique midwest['category']categories = np.unique(midwest['category'])colors = [plt.cm.tab10(i/float(len(categories)-1)) for i in range(len(categories))]# Draw Plot for Each Categoryplt.figure(figsize=(16, 10), dpi= 80, facecolor='w', edgecolor='k')for i, category in enumerate(categories): plt.scatter('area', 'poptotal', data=midwest.loc[midwest.category==category, :], s=20, cmap=colors[i], label=str(category))# 原文 c=colors[i] 已修改为 cmap=colors[i]# Decorationsplt.gca().set(xlim=(0.0, 0.1), ylim=(0, 90000), xlabel='Area', ylabel='Population')plt.xticks(fontsize=12); plt.yticks(fontsize=12)plt.title("Scatterplot of Midwest Area vs Population", fontsize=22)plt.legend(fontsize=12)plt.show() 【02】带边界的气泡图(Bubble plot with Encircling) 有时候您想在一个边界内显示一组点来强调它们的重要性。在本例中,您将从被包围的数据中获取记录,并将其传递给下面的代码中描述的 encircle()。 from matplotlib import patchesfrom scipy.spatial import ConvexHullimport warnings; warnings.simplefilter('ignore')sns.set_style("white")# Step 1: Prepare Datamidwest = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/midwest_filter.csv")# As many colors as there are unique midwest['category']categories = np.unique(midwest['category'])colors = [plt.cm.tab10(i/float(len(categories)-1)) for i in range(len(categories))]# Step 2: Draw Scatterplot with unique color for each categoryfig = plt.figure(figsize=(16, 10), dpi=80, facecolor='w', edgecolor='k')for i, category in enumerate(categories): plt.scatter('area', 'poptotal', data=midwest.loc[midwest.category == category, :], s='dot_size', cmap=colors[i], label=str(category), edgecolors='black', linewidths=.5)# 原文 c=colors[i] 已修改为 cmap=colors[i]# Step 3: Encircling# https://stackoverflow.com/questions/44575681/how-do-i-encircle-different-data-sets-in-scatter-plotdef encircle(x,y, ax=None, **kw): if not ax: ax = plt.gca() p = np.c_[x, y] hull = ConvexHull(p) poly = plt.Polygon(p[hull.vertices, :], **kw) ax.add_patch(poly)# Select data to be encircledmidwest_encircle_data = midwest.loc[midwest.state=='IN', :]# Draw polygon surrounding verticesencircle(midwest_encircle_data.area, midwest_encircle_data.poptotal, ec="k", fc="gold", alpha=0.1)encircle(midwest_encircle_data.area, midwest_encircle_data.poptotal, ec="firebrick", fc="none", linewidth=1.5)# Step 4: Decorationsplt.gca().set(xlim=(0.0, 0.1), ylim=(0, 90000), xlabel='Area', ylabel='Population')plt.xticks(fontsize=12); plt.yticks(fontsize=12)plt.title("Bubble Plot with Encircling", fontsize=22)plt.legend(fontsize=12)plt.show() 【03】带线性回归最佳拟合线的散点图(Scatter plot with linear regression line of best fit) 如果你想了解两个变量之间是如何变化的,那么最佳拟合线就是常用的方法。下图显示了数据中不同组之间的最佳拟合线的差异。若要禁用分组并只为整个数据集绘制一条最佳拟合线,请从 sns.lmplot() 方法中删除 hue ='cyl' 参数。 # Import Datadf = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/mpg_ggplot2.csv")df_select = df.loc[df.cyl.isin([4, 8]), :]# Plotsns.set_style("white")gridobj = sns.lmplot(x="displ", y="hwy", hue="cyl", data=df_select, height=7, aspect=1.6, robust=True, palette='tab10', scatter_kws=dict(s=60, linewidths=.7, edgecolors='black'))# Decorationsgridobj.set(xlim=(0.5, 7.5), ylim=(0, 50))plt.title("Scatterplot with line of best fit grouped by number of cylinders", fontsize=20)plt.show() 针对每一组数据绘制线性回归线(Each regression line in its own column),可以通过在 sns.lmplot() 中设置 col=groupingcolumn 参数来实现,如下: # Import Datadf = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/mpg_ggplot2.csv")df_select = df.loc[df.cyl.isin([4, 8]), :]# Each line in its own columnsns.set_style("white")gridobj = sns.lmplot(x="displ", y="hwy", data=df_select, height=7, robust=True, palette='Set1', col="cyl", scatter_kws=dict(s=60, linewidths=.7, edgecolors='black'))# Decorationsgridobj.set(xlim=(0.5, 7.5), ylim=(0, 50))plt.show() 【04】抖动图(Jittering with stripplot) 通常,多个数据点具有完全相同的 X 和 Y 值。 此时多个点绘制会重叠并隐藏。为避免这种情况,可以将数据点稍微抖动,以便可以直观地看到它们。 使用 seaborn 库的 stripplot() 方法可以很方便的实现这个功能。 # Import Datadf = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/mpg_ggplot2.csv")# Draw Stripplotfig, ax = plt.subplots(figsize=(16,10), dpi= 80)sns.stripplot(df.cty, df.hwy, jitter=0.25, size=8, ax=ax, linewidth=.5)# Decorationsplt.title('Use jittered plots to avoid overlapping of points', fontsize=22)plt.show() 【05】计数图(Counts Plot) 避免点重叠问题的另一个选择是根据点的位置增加点的大小。所以,点的大小越大,它周围的点就越集中。 # Import Datadf = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/mpg_ggplot2.csv")df_counts = df.groupby(['hwy', 'cty']).size().reset_index(name='counts')# Draw Stripplotfig, ax = plt.subplots(figsize=(16,10), dpi= 80) # 原文代码# sns.stripplot(df_counts.cty, df_counts.hwy, size=df_counts.counts*2, ax=ax)# 纠正代码sns.stripplot(df_counts.cty, df_counts.hwy, sizes=df_counts.counts*2, ax=ax)# Decorationsplt.title('Counts Plot - Size of circle is bigger as more points overlap', fontsize=22)plt.show() 【06】边缘直方图(Marginal Histogram) 边缘直方图是具有沿 X 和 Y 轴变量的直方图。 这用于可视化 X 和 Y 之间的关系以及单独的 X 和 Y 的单变量分布。 这种图经常用于探索性数据分析(EDA)。 # Import Datadf = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/mpg_ggplot2.csv")# Create Fig and gridspecfig = plt.figure(figsize=(16, 10), dpi= 80)grid = plt.GridSpec(4, 4, hspace=0.5, wspace=0.2)# Define the axesax_main = fig.add_subplot(grid[:-1, :-1])ax_right = fig.add_subplot(grid[:-1, -1], xticklabels=[], yticklabels=[])ax_bottom = fig.add_subplot(grid[-1, 0:-1], xticklabels=[], yticklabels=[])# Scatterplot on main axax_main.scatter('displ', 'hwy', s=df.cty*4, c=df.manufacturer.astype('category').cat.codes, alpha=.9, data=df, cmap="tab10", edgecolors='gray', linewidths=.5)# histogram on the rightax_bottom.hist(df.displ, 40, histtype='stepfilled', orientation='vertical', color='deeppink')ax_bottom.invert_yaxis()# histogram in the bottomax_right.hist(df.hwy, 40, histtype='stepfilled', orientation='horizontal', color='deeppink')# Decorationsax_main.set(title='Scatterplot with Histograms \n displ vs hwy', xlabel='displ', ylabel='hwy')ax_main.title.set_fontsize(20)for item in ([ax_main.xaxis.label, ax_main.yaxis.label] + ax_main.get_xticklabels() + ax_main.get_yticklabels()): item.set_fontsize(14)xlabels = ax_main.get_xticks().tolist()ax_main.set_xticklabels(xlabels)plt.show() 【07】边缘箱形图(Marginal Boxplot) 边缘箱形图与边缘直方图具有相似的用途。 然而,箱线图有助于精确定位 X 和 Y 的中位数、第25和第75百分位数。 # Import Datadf = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/mpg_ggplot2.csv")# Create Fig and gridspecfig = plt.figure(figsize=(16, 10), dpi= 80)grid = plt.GridSpec(4, 4, hspace=0.5, wspace=0.2)# Define the axesax_main = fig.add_subplot(grid[:-1, :-1])ax_right = fig.add_subplot(grid[:-1, -1], xticklabels=[], yticklabels=[])ax_bottom = fig.add_subplot(grid[-1, 0:-1], xticklabels=[], yticklabels=[])# Scatterplot on main axax_main.scatter('displ', 'hwy', s=df.cty*5, c=df.manufacturer.astype('category').cat.codes, alpha=.9, data=df, cmap="Set1", edgecolors='black', linewidths=.5)# Add a graph in each partsns.boxplot(df.hwy, ax=ax_right, orient="v")sns.boxplot(df.displ, ax=ax_bottom, orient="h")# Decorations ------------------# Remove x axis name for the boxplotax_bottom.set(xlabel='')ax_right.set(ylabel='')# Main Title, Xlabel and YLabelax_main.set(title='Scatterplot with Histograms \n displ vs hwy', xlabel='displ', ylabel='hwy')# Set font size of different componentsax_main.title.set_fontsize(20)for item in ([ax_main.xaxis.label, ax_main.yaxis.label] + ax_main.get_xticklabels() + ax_main.get_yticklabels()): item.set_fontsize(14)plt.show() 【08】相关图(Correllogram) 相关图用于直观地查看给定数据帧(或二维数组)中所有可能的数值变量对之间的相关性度量。 # Import Datasetdf = pd.read_csv("https://github.com/selva86/datasets/raw/master/mtcars.csv")# Plotplt.figure(figsize=(12, 10), dpi=80)sns.heatmap(df.corr(), xticklabels=df.corr().columns, yticklabels=df.corr().columns, cmap='RdYlGn', center=0, annot=True)# Decorationsplt.title('Correlogram of mtcars', fontsize=22)plt.xticks(fontsize=12)plt.yticks(fontsize=12)plt.show() 【09】成对图(Pairwise Plot) 成对图是探索性分析中最受欢迎的一种方法,用来理解所有可能的数值变量对之间的关系。它是二元分析的必备工具。 # Load Datasetdf = sns.load_dataset('iris')# Plotplt.figure(figsize=(10, 8), dpi=80)sns.pairplot(df, kind="scatter", hue="species", plot_kws=dict(s=80, edgecolor="white", linewidth=2.5))plt.show() # Load Datasetdf = sns.load_dataset('iris')# Plotplt.figure(figsize=(10, 8), dpi=80)sns.pairplot(df, kind="reg", hue="species")plt.show() 【4x00】偏差(Deviation) 【10】发散型条形图(Diverging Bars) 如果您想根据单个指标查看项目的变化情况,并可视化此差异的顺序和数量,那么散型条形图是一个很好的工具。 它有助于快速区分数据组的性能,并且非常直观,并且可以立即传达这一点。 # Prepare Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/mtcars.csv")x = df.loc[:, ['mpg']]df['mpg_z'] = (x - x.mean())/x.std()df['colors'] = ['red' if x < 0 else 'green' for x in df['mpg_z']]df.sort_values('mpg_z', inplace=True)df.reset_index(inplace=True)# Draw plotplt.figure(figsize=(14,10), dpi= 80)plt.hlines(y=df.index, xmin=0, xmax=df.mpg_z, color=df.colors, alpha=0.4, linewidth=5)# Decorationsplt.gca().set(ylabel='$Model$', xlabel='$Mileage$')plt.yticks(df.index, df.cars, fontsize=12)plt.title('Diverging Bars of Car Mileage', fontdict={'size':20})plt.grid(linestyle='--', alpha=0.5)plt.show() 【11】发散型文本图(Diverging Texts) 发散型文本图与发散型条形图相似,如果你希望以一种美观的方式显示图表中每个项目的值,就可以使用这种方法。 # Prepare Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/mtcars.csv")x = df.loc[:, ['mpg']]df['mpg_z'] = (x - x.mean())/x.std()df['colors'] = ['red' if x < 0 else 'green' for x in df['mpg_z']]df.sort_values('mpg_z', inplace=True)df.reset_index(inplace=True)# Draw plotplt.figure(figsize=(14, 14), dpi=80)plt.hlines(y=df.index, xmin=0, xmax=df.mpg_z)for x, y, tex in zip(df.mpg_z, df.index, df.mpg_z): t = plt.text(x, y, round(tex, 2), horizontalalignment='right' if x < 0 else 'left', verticalalignment='center', fontdict={'color':'red' if x < 0 else 'green', 'size':14})# Decorationsplt.yticks(df.index, df.cars, fontsize=12)plt.title('Diverging Text Bars of Car Mileage', fontdict={'size':20})plt.grid(linestyle='--', alpha=0.5)plt.xlim(-2.5, 2.5)plt.show() 【12】发散型散点图(Diverging Dot Plot) 发散型散点图类似于发散型条形图。 但是,与发散型条形图相比,没有条形会减少组之间的对比度和差异。 # Prepare Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/mtcars.csv")x = df.loc[:, ['mpg']]df['mpg_z'] = (x - x.mean())/x.std()df['colors'] = ['red' if x < 0 else 'darkgreen' for x in df['mpg_z']]df.sort_values('mpg_z', inplace=True)df.reset_index(inplace=True)# Draw plotplt.figure(figsize=(14, 16), dpi=80)plt.scatter(df.mpg_z, df.index, s=450, alpha=.6, color=df.colors)for x, y, tex in zip(df.mpg_z, df.index, df.mpg_z): t = plt.text(x, y, round(tex, 1), horizontalalignment='center', verticalalignment='center', fontdict={'color': 'white'})# Decorations# Lighten bordersplt.gca().spines["top"].set_alpha(.3)plt.gca().spines["bottom"].set_alpha(.3)plt.gca().spines["right"].set_alpha(.3)plt.gca().spines["left"].set_alpha(.3)plt.yticks(df.index, df.cars)plt.title('Diverging Dotplot of Car Mileage', fontdict={'size': 20})plt.xlabel('$Mileage$')plt.grid(linestyle='--', alpha=0.5)plt.xlim(-2.5, 2.5)plt.show() 【13】带标记的发散型棒棒糖图(Diverging Lollipop Chart with Markers) 带有标记的棒棒糖提供了一种灵活的方式,强调您想要引起注意的任何重要数据点并在图表中适当地给出推理。 # Prepare Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/mtcars.csv")x = df.loc[:, ['mpg']]df['mpg_z'] = (x - x.mean())/x.std()df['colors'] = 'black'# color fiat differentlydf.loc[df.cars == 'Fiat X1-9', 'colors'] = 'darkorange'df.sort_values('mpg_z', inplace=True)df.reset_index(inplace=True)# Draw plotimport matplotlib.patches as patchesplt.figure(figsize=(14, 16), dpi=80)plt.hlines(y=df.index, xmin=0, xmax=df.mpg_z, color=df.colors, alpha=0.4, linewidth=1)plt.scatter(df.mpg_z, df.index, color=df.colors, s=[600 if x == 'Fiat X1-9' else 300 for x in df.cars], alpha=0.6)plt.yticks(df.index, df.cars)plt.xticks(fontsize=12)# Annotateplt.annotate('Mercedes Models', xy=(0.0, 11.0), xytext=(1.0, 11), xycoords='data', fontsize=15, ha='center', va='center', bbox=dict(boxstyle='square', fc='firebrick'), arrowprops=dict(arrowstyle='-[, widthB=2.0, lengthB=1.5', lw=2.0, color='steelblue'), color='white')# Add Patchesp1 = patches.Rectangle((-2.0, -1), width=.3, height=3, alpha=.2, facecolor='red')p2 = patches.Rectangle((1.5, 27), width=.8, height=5, alpha=.2, facecolor='green')plt.gca().add_patch(p1)plt.gca().add_patch(p2)# Decorateplt.title('Diverging Bars of Car Mileage', fontdict={'size': 20})plt.grid(linestyle='--', alpha=0.5)plt.show() 【14】面积图(Area Chart) 通过对轴和线之间的区域进行着色,面积图不仅强调波峰和波谷,还强调波峰和波谷的持续时间。 高点持续时间越长,线下面积越大。 import numpy as npimport pandas as pd# Prepare Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/economics.csv", parse_dates=['date']).head(100)x = np.arange(df.shape[0])y_returns = (df.psavert.diff().fillna(0)/df.psavert.shift(1)).fillna(0) * 100# Plotplt.figure(figsize=(16, 10), dpi=80)plt.fill_between(x[1:], y_returns[1:], 0, where=y_returns[1:] >= 0, facecolor='green', interpolate=True, alpha=0.7)plt.fill_between(x[1:], y_returns[1:], 0, where=y_returns[1:] <= 0, facecolor='red', interpolate=True, alpha=0.7)# Annotateplt.annotate('Peak \n1975', xy=(94.0, 21.0), xytext=(88.0, 28), bbox=dict(boxstyle='square', fc='firebrick'), arrowprops=dict(facecolor='steelblue', shrink=0.05), fontsize=15, color='white')# Decorationsxtickvals = [str(m)[:3].upper()+"-"+str(y) for y, m in zip(df.date.dt.year, df.date.dt.month_name())]plt.gca().set_xticks(x[::6])plt.gca().set_xticklabels(xtickvals[::6], rotation=90, fontdict={'horizontalalignment': 'center', 'verticalalignment': 'center_baseline'})plt.ylim(-35, 35)plt.xlim(1, 100)plt.title("Month Economics Return %", fontsize=22)plt.ylabel('Monthly returns %')plt.grid(alpha=0.5)plt.show() 【5x00】排序(Ranking) 【15】有序条形图(Ordered Bar Chart) 有序条形图有效地传达了项目的排序顺序。在图表上方添加度量标准的值,用户就可以从图表本身获得精确的信息。 # Prepare Datadf_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")df = df_raw[['cty', 'manufacturer']].groupby('manufacturer').apply(lambda x: x.mean())df.sort_values('cty', inplace=True)df.reset_index(inplace=True)# Draw plotimport matplotlib.patches as patchesfig, ax = plt.subplots(figsize=(16,10), facecolor='white', dpi= 80)ax.vlines(x=df.index, ymin=0, ymax=df.cty, color='firebrick', alpha=0.7, linewidth=20)# Annotate Textfor i, cty in enumerate(df.cty): ax.text(i, cty+0.5, round(cty, 1), horizontalalignment='center')# Title, Label, Ticks and Ylimax.set_title('Bar Chart for Highway Mileage', fontdict={'size':22})ax.set(ylabel='Miles Per Gallon', ylim=(0, 30))plt.xticks(df.index, df.manufacturer.str.upper(), rotation=60, horizontalalignment='right', fontsize=12)# Add patches to color the X axis labelsp1 = patches.Rectangle((.57, -0.005), width=.33, height=.13, alpha=.1, facecolor='green', transform=fig.transFigure)p2 = patches.Rectangle((.124, -0.005), width=.446, height=.13, alpha=.1, facecolor='red', transform=fig.transFigure)fig.add_artist(p1)fig.add_artist(p2)plt.show() 【16】棒棒糖图(Lollipop Chart) 棒棒糖图表以一种视觉上令人愉悦的方式提供与有序条形图类似的目的。 # Prepare Datadf_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")df = df_raw[['cty', 'manufacturer']].groupby('manufacturer').apply(lambda x: x.mean())df.sort_values('cty', inplace=True)df.reset_index(inplace=True)# Draw plotfig, ax = plt.subplots(figsize=(16, 10), dpi=80)ax.vlines(x=df.index, ymin=0, ymax=df.cty, color='firebrick', alpha=0.7, linewidth=2)ax.scatter(x=df.index, y=df.cty, s=75, color='firebrick', alpha=0.7)# Title, Label, Ticks and Ylimax.set_title('Lollipop Chart for Highway Mileage', fontdict={'size': 22})ax.set_ylabel('Miles Per Gallon')ax.set_xticks(df.index)ax.set_xticklabels(df.manufacturer.str.upper(), rotation=60, fontdict={'horizontalalignment': 'right', 'size': 12})ax.set_ylim(0, 30)# Annotatefor row in df.itertuples(): ax.text(row.Index, row.cty+.5, s=round(row.cty, 2), horizontalalignment='center', verticalalignment='bottom', fontsize=14)plt.show() 【17】点图(Dot Plot) 点图可以表示项目的排名顺序。由于它是沿水平轴对齐的,所以可以更容易地看到点之间的距离。 # Prepare Datadf_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")df = df_raw[['cty', 'manufacturer']].groupby('manufacturer').apply(lambda x: x.mean())df.sort_values('cty', inplace=True)df.reset_index(inplace=True)# Draw plotfig, ax = plt.subplots(figsize=(16, 10), dpi=80)ax.hlines(y=df.index, xmin=11, xmax=26, color='gray', alpha=0.7, linewidth=1, linestyles='dashdot')ax.scatter(y=df.index, x=df.cty, s=75, color='firebrick', alpha=0.7)# Title, Label, Ticks and Ylimax.set_title('Dot Plot for Highway Mileage', fontdict={'size': 22})ax.set_xlabel('Miles Per Gallon')ax.set_yticks(df.index)ax.set_yticklabels(df.manufacturer.str.title(), fontdict={'horizontalalignment': 'right'})ax.set_xlim(10, 27)plt.show() 【18】坡度图(Slope Chart) 坡度图最适合比较给定人员/项目的“前”和“后”位置。 import matplotlib.lines as mlines# Import Datadf = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/gdppercap.csv")left_label = [str(c) + ', ' + str(round(y)) for c, y in zip(df.continent, df['1952'])]right_label = [str(c) + ', ' + str(round(y)) for c, y in zip(df.continent, df['1957'])]klass = ['red' if (y1 - y2) < 0 else 'green' for y1, y2 in zip(df['1952'], df['1957'])]# draw line# https://stackoverflow.com/questions/36470343/how-to-draw-a-line-with-matplotlib/36479941def newline(p1, p2, color='black'): ax = plt.gca() l = mlines.Line2D([p1[0], p2[0]], [p1[1], p2[1]], color='red' if p1[1] - p2[1] > 0 else 'green', marker='o', markersize=6) ax.add_line(l) return lfig, ax = plt.subplots(1, 1, figsize=(14, 14), dpi=80)# Vertical Linesax.vlines(x=1, ymin=500, ymax=13000, color='black', alpha=0.7, linewidth=1, linestyles='dotted')ax.vlines(x=3, ymin=500, ymax=13000, color='black', alpha=0.7, linewidth=1, linestyles='dotted')# Pointsax.scatter(y=df['1952'], x=np.repeat(1, df.shape[0]), s=10, color='black', alpha=0.7)ax.scatter(y=df['1957'], x=np.repeat(3, df.shape[0]), s=10, color='black', alpha=0.7)# Line Segmentsand Annotationfor p1, p2, c in zip(df['1952'], df['1957'], df['continent']): newline([1, p1], [3, p2]) ax.text(1 - 0.05, p1, c + ', ' + str(round(p1)), horizontalalignment='right', verticalalignment='center', fontdict={'size': 14}) ax.text(3 + 0.05, p2, c + ', ' + str(round(p2)), horizontalalignment='left', verticalalignment='center', fontdict={'size': 14})# 'Before' and 'After' Annotationsax.text(1 - 0.05, 13000, 'BEFORE', horizontalalignment='right', verticalalignment='center', fontdict={'size': 18, 'weight': 700})ax.text(3 + 0.05, 13000, 'AFTER', horizontalalignment='left', verticalalignment='center', fontdict={'size': 18, 'weight': 700})# Decorationax.set_title("Slopechart: Comparing GDP Per Capita between 1952 vs 1957", fontdict={'size': 22})ax.set(xlim=(0, 4), ylim=(0, 14000), ylabel='Mean GDP Per Capita')ax.set_xticks([1, 3])ax.set_xticklabels(["1952", "1957"])plt.yticks(np.arange(500, 13000, 2000), fontsize=12)# Lighten bordersplt.gca().spines["top"].set_alpha(.0)plt.gca().spines["bottom"].set_alpha(.0)plt.gca().spines["right"].set_alpha(.0)plt.gca().spines["left"].set_alpha(.0)plt.show() 【19】哑铃图(Dumbbell Plot) 哑铃图传达了各种项目的“前”和“后”位置以及项目的等级顺序。如果您希望可视化特定项目/计划对不同对象的影响,那么它非常有用。 import matplotlib.lines as mlines# Import Datadf = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/health.csv")df.sort_values('pct_2014', inplace=True)df.reset_index(inplace=True)# Func to draw line segmentdef newline(p1, p2, color='black'): ax = plt.gca() l = mlines.Line2D([p1[0], p2[0]], [p1[1], p2[1]], color='skyblue') ax.add_line(l) return l# Figure and Axesfig, ax = plt.subplots(1, 1, figsize=(14, 14), facecolor='#f7f7f7', dpi=80)# Vertical Linesax.vlines(x=.05, ymin=0, ymax=26, color='black', alpha=1, linewidth=1, linestyles='dotted')ax.vlines(x=.10, ymin=0, ymax=26, color='black', alpha=1, linewidth=1, linestyles='dotted')ax.vlines(x=.15, ymin=0, ymax=26, color='black', alpha=1, linewidth=1, linestyles='dotted')ax.vlines(x=.20, ymin=0, ymax=26, color='black', alpha=1, linewidth=1, linestyles='dotted')# Pointsax.scatter(y=df['index'], x=df['pct_2013'], s=50, color='#0e668b', alpha=0.7)ax.scatter(y=df['index'], x=df['pct_2014'], s=50, color='#a3c4dc', alpha=0.7)# Line Segmentsfor i, p1, p2 in zip(df['index'], df['pct_2013'], df['pct_2014']): newline([p1, i], [p2, i])# Decorationax.set_facecolor('#f7f7f7')ax.set_title("Dumbell Chart: Pct Change - 2013 vs 2014", fontdict={'size': 22})ax.set(xlim=(0, .25), ylim=(-1, 27), ylabel='Mean GDP Per Capita')ax.set_xticks([.05, .1, .15, .20])ax.set_xticklabels(['5%', '15%', '20%', '25%'])ax.set_xticklabels(['5%', '15%', '20%', '25%'])plt.show() 【6x00】分布(Distribution) 【20】连续变量的直方图(Histogram for Continuous Variable) 连续变量的直方图显示给定变量的频率分布。下面的图表基于分类变量对频率条进行分组,从而更深入地了解连续变量和分类变量。 # Import Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Prepare datax_var = 'displ'groupby_var = 'class'df_agg = df.loc[:, [x_var, groupby_var]].groupby(groupby_var)vals = [df[x_var].values.tolist() for i, df in df_agg]# Drawplt.figure(figsize=(16, 9), dpi=80)colors = [plt.cm.Spectral(i / float(len(vals) - 1)) for i in range(len(vals))]n, bins, patches = plt.hist(vals, 30, stacked=True, density=False, color=colors[:len(vals)])# Decorationplt.legend({group: col for group, col in zip(np.unique(df[groupby_var]).tolist(), colors[:len(vals)])})plt.title(f"Stacked Histogram of ${x_var}$ colored by ${groupby_var}$", fontsize=22)plt.xlabel(x_var)plt.ylabel("Frequency")plt.ylim(0, 25)plt.xticks(ticks=bins[::3], labels=[round(b, 1) for b in bins[::3]])plt.show() 【21】分类变量的直方图(Histogram for Categorical Variable) 分类变量的直方图显示该变量的频率分布。通过给条形图上色,您可以将分布与表示颜色的另一个类型变量相关联。 # Import Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Prepare datax_var = 'manufacturer'groupby_var = 'class'df_agg = df.loc[:, [x_var, groupby_var]].groupby(groupby_var)vals = [df[x_var].values.tolist() for i, df in df_agg]# Drawplt.figure(figsize=(16, 9), dpi=80)colors = [plt.cm.Spectral(i / float(len(vals) - 1)) for i in range(len(vals))]n, bins, patches = plt.hist(vals, df[x_var].unique().__len__(), stacked=True, density=False, color=colors[:len(vals)])# Decorationplt.legend({group: col for group, col in zip(np.unique(df[groupby_var]).tolist(), colors[:len(vals)])})plt.title(f"Stacked Histogram of ${x_var}$ colored by ${groupby_var}$", fontsize=22)plt.xlabel(x_var)plt.ylabel("Frequency")plt.ylim(0, 40)plt.xticks(ticks=bins, labels=np.unique(df[x_var]).tolist(), rotation=90, horizontalalignment='left')plt.show() 【22】密度图(Density Plot) 密度图是连续变量分布可视化的常用工具。通过按“response”变量对它们进行分组,您可以检查 X 和 Y 之间的关系。如果出于代表性目的来描述城市里程分布如何随气缸数而变化,请参见下面的情况。 # Import Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Draw Plotplt.figure(figsize=(16, 10), dpi=80)sns.kdeplot(df.loc[df['cyl'] == 4, "cty"], shade=True, color="g", label="Cyl=4", alpha=.7)sns.kdeplot(df.loc[df['cyl'] == 5, "cty"], shade=True, color="deeppink", label="Cyl=5", alpha=.7)sns.kdeplot(df.loc[df['cyl'] == 6, "cty"], shade=True, color="dodgerblue", label="Cyl=6", alpha=.7)sns.kdeplot(df.loc[df['cyl'] == 8, "cty"], shade=True, color="orange", label="Cyl=8", alpha=.7)# Decorationplt.title('Density Plot of City Mileage by n_Cylinders', fontsize=22)plt.legend()plt.show() 【23】直方图密度曲线(Density Curves with Histogram) 具有直方图的密度曲线将两个图所传达的信息集合在一起,因此您可以将它们都放在一个图形中,而不是放在两个图形中。 # Import Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Draw Plotplt.figure(figsize=(13, 10), dpi=80)sns.distplot(df.loc[df['class'] == 'compact', "cty"], color="dodgerblue", label="Compact", hist_kws={'alpha': .7}, kde_kws={'linewidth': 3})sns.distplot(df.loc[df['class'] == 'suv', "cty"], color="orange", label="SUV", hist_kws={'alpha': .7}, kde_kws={'linewidth': 3})sns.distplot(df.loc[df['class'] == 'minivan', "cty"], color="g", label="minivan", hist_kws={'alpha': .7}, kde_kws={'linewidth': 3})plt.ylim(0, 0.35)# Decorationplt.title('Density Plot of City Mileage by Vehicle Type', fontsize=22)plt.legend()plt.show() 【24】山峰叠峦图 / 欢乐图(Joy Plot) Joy Plot 允许不同组的密度曲线重叠,这是一种很好的可视化方法,可以直观地显示大量分组之间的关系。它看起来赏心悦目,清楚地传达了正确的信息。它可以使用基于 matplotlib 的 joypy 包轻松构建。 【译者 TRHX 注:Joy Plot 看起来就像是山峰叠峦,山峦起伏,层次分明,但取名为 Joy,欢乐的意思,所以不太好翻译,在使用该方法时要先安装 joypy 库】 # !pip install joypy# Import Dataimport joypy# 原文没有 import joypy,译者 TRHX 添加mpg = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Draw Plotplt.figure(figsize=(16, 10), dpi=80)fig, axes = joypy.joyplot(mpg, column=['hwy', 'cty'], by="class", ylim='own', figsize=(14, 10))# Decorationplt.title('Joy Plot of City and Highway Mileage by Class', fontsize=22)plt.show() 【25】分布式点图(Distributed Dot Plot) 分布点图显示按组分割的点的单变量分布。点越暗,数据点在该区域的集中程度就越高。通过对中值进行不同的着色,这些组的真实位置立即变得明显。 import matplotlib.patches as mpatches# Prepare Datadf_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")cyl_colors = {4: 'tab:red', 5: 'tab:green', 6: 'tab:blue', 8: 'tab:orange'}df_raw['cyl_color'] = df_raw.cyl.map(cyl_colors)# Mean and Median city mileage by makedf = df_raw[['cty', 'manufacturer']].groupby('manufacturer').apply(lambda x: x.mean())df.sort_values('cty', ascending=False, inplace=True)df.reset_index(inplace=True)df_median = df_raw[['cty', 'manufacturer']].groupby('manufacturer').apply(lambda x: x.median())# Draw horizontal linesfig, ax = plt.subplots(figsize=(16, 10), dpi=80)ax.hlines(y=df.index, xmin=0, xmax=40, color='gray', alpha=0.5, linewidth=.5, linestyles='dashdot')# Draw the Dotsfor i, make in enumerate(df.manufacturer): df_make = df_raw.loc[df_raw.manufacturer == make, :] # 原文代码 # ax.scatter(y=np.repeat(i, df_make.shape[0]), x='cty', data=df_make, s=75, edgecolors='gray', c='w', alpha=0.5) # 纠正代码 ax.scatter(y=list(np.repeat(i, df_make.shape[0])), x='cty', data=df_make, s=75, edgecolors='gray', c='w', alpha=0.5) ax.scatter(y=i, x='cty', data=df_median.loc[df_median.index == make, :], s=75, c='firebrick')# Annotateax.text(33, 13, "$red \; dots \; are \; the \: median$", fontdict={'size': 12}, color='firebrick')# Decorationsred_patch = plt.plot([], [], marker="o", ms=10, ls="", mec=None, color='firebrick', label="Median")plt.legend(handles=red_patch)ax.set_title('Distribution of City Mileage by Make', fontdict={'size': 22})ax.set_xlabel('Miles Per Gallon (City)', alpha=0.7)ax.set_yticks(df.index)ax.set_yticklabels(df.manufacturer.str.title(), fontdict={'horizontalalignment': 'right'}, alpha=0.7)ax.set_xlim(1, 40)plt.xticks(alpha=0.7)plt.gca().spines["top"].set_visible(False)plt.gca().spines["bottom"].set_visible(False)plt.gca().spines["right"].set_visible(False)plt.gca().spines["left"].set_visible(False)plt.grid(axis='both', alpha=.4, linewidth=.1)plt.show() 【26】箱形图(Box Plot) 箱形图是可视化分布的一种好方法,同时牢记中位数,第 25 个第 75 个四分位数和离群值。 但是,在解释方框的大小时需要小心,这可能会扭曲该组中包含的点数。 因此,手动提供每个框中的观察次数可以帮助克服此缺点。 例如,左侧的前两个框,尽管它们分别具有 5 和 47 个 obs,但是却具有相同大小, 因此,有必要写下该组中的观察数。 # Import Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Draw Plotplt.figure(figsize=(13, 10), dpi=80)sns.boxplot(x='class', y='hwy', data=df, notch=False)# Add N Obs inside boxplot (optional)def add_n_obs(df, group_col, y): medians_dict = {grp[0]: grp[1][y].median() for grp in df.groupby(group_col)} xticklabels = [x.get_text() for x in plt.gca().get_xticklabels()] n_obs = df.groupby(group_col)[y].size().values for (x, xticklabel), n_ob in zip(enumerate(xticklabels), n_obs): plt.text(x, medians_dict[xticklabel] * 1.01, "#obs : " + str(n_ob), horizontalalignment='center', fontdict={'size': 14}, color='white')add_n_obs(df, group_col='class', y='hwy')# Decorationplt.title('Box Plot of Highway Mileage by Vehicle Class', fontsize=22)plt.ylim(10, 40)plt.show() 【27】点 + 箱形图(Dot + Box Plot) 点 + 箱形图传达类似于分组的箱形图信息。此外,这些点还提供了每组中有多少数据点的含义。 # Import Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Draw Plotplt.figure(figsize=(13,10), dpi= 80)sns.boxplot(x='class', y='hwy', data=df, hue='cyl')sns.stripplot(x='class', y='hwy', data=df, color='black', size=3, jitter=1)for i in range(len(df['class'].unique())-1): plt.vlines(i+.5, 10, 45, linestyles='solid', colors='gray', alpha=0.2)# Decorationplt.title('Box Plot of Highway Mileage by Vehicle Class', fontsize=22)plt.legend(title='Cylinders')plt.show() 【28】小提琴图(Violin Plot) 小提琴图是箱形图在视觉上令人愉悦的替代品。 小提琴的形状或面积取决于它所持有的观察次数。 但是,小提琴图可能更难以阅读,并且在专业设置中不常用。 # Import Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Draw Plotplt.figure(figsize=(13, 10), dpi=80)sns.violinplot(x='class', y='hwy', data=df, scale='width', inner='quartile')# Decorationplt.title('Violin Plot of Highway Mileage by Vehicle Class', fontsize=22)plt.show() 【29】人口金字塔图(Population Pyramid) 人口金字塔可用于显示按体积排序的组的分布。或者它也可以用于显示人口的逐级过滤,因为它是用来显示有多少人通过一个营销漏斗(Marketing Funnel)的每个阶段。 # Read datadf = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/email_campaign_funnel.csv")# Draw Plotplt.figure(figsize=(13, 10), dpi=80)group_col = 'Gender'order_of_bars = df.Stage.unique()[::-1]colors = [plt.cm.Spectral(i / float(len(df[group_col].unique()) - 1)) for i in range(len(df[group_col].unique()))]for c, group in zip(colors, df[group_col].unique()): sns.barplot(x='Users', y='Stage', data=df.loc[df[group_col] == group, :], order=order_of_bars, color=c, label=group)# Decorationsplt.xlabel("$Users$")plt.ylabel("Stage of Purchase")plt.yticks(fontsize=12)plt.title("Population Pyramid of the Marketing Funnel", fontsize=22)plt.legend()plt.show() 【30】分类图(Categorical Plots) 由 seaborn 库提供的分类图可用于可视化彼此相关的两个或更多分类变量的计数分布。 # Load Datasettitanic = sns.load_dataset("titanic")# Plotg = sns.catplot("alive", col="deck", col_wrap=4, data=titanic[titanic.deck.notnull()], kind="count", height=3.5, aspect=.8, palette='tab20')# 译者 TRHX 注释掉了这一行代码# fig.suptitle('sf')plt.show() # Load Datasettitanic = sns.load_dataset("titanic")# Plotsns.catplot(x="age", y="embark_town", hue="sex", col="class", data=titanic[titanic.embark_town.notnull()], orient="h", height=5, aspect=1, palette="tab10", kind="violin", dodge=True, cut=0, bw=.2)# 译者 TRHX 添加了这行代码plt.show() 【7x00】组成(Composition) 【31】华夫饼图(Waffle Chart) 华夫饼图可以使用 pywaffle 包创建,用于显示较大群体中的组的组成。 【译者 TRHX 注:在使用该方法时要先安装 pywaffle 库】 # ! pip install pywaffle# Reference: https://stackoverflow.com/questions/41400136/how-to-do-waffle-charts-in-python-square-piechartfrom pywaffle import Waffle# Importdf_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Prepare Datadf = df_raw.groupby('class').size().reset_index(name='counts')n_categories = df.shape[0]colors = [plt.cm.inferno_r(i / float(n_categories)) for i in range(n_categories)]# Draw Plot and Decoratefig = plt.figure( FigureClass=Waffle, plots={ '111': { 'values': df['counts'], 'labels': ["{0} ({1})".format(n[0], n[1]) for n in df[['class', 'counts']].itertuples()], 'legend': {'loc': 'upper left', 'bbox_to_anchor': (1.05, 1), 'fontsize': 12}, 'title': {'label': '# Vehicles by Class', 'loc': 'center', 'fontsize': 18} }, }, rows=7, colors=colors, figsize=(16, 9))# 译者 TRHX 添加了这行代码plt.show() # ! pip install pywafflefrom pywaffle import Waffle# Import# 译者 TRHX 取消注释了这行代码df_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Prepare Data# By Class Datadf_class = df_raw.groupby('class').size().reset_index(name='counts_class')n_categories = df_class.shape[0]colors_class = [plt.cm.Set3(i / float(n_categories)) for i in range(n_categories)]# By Cylinders Datadf_cyl = df_raw.groupby('cyl').size().reset_index(name='counts_cyl')n_categories = df_cyl.shape[0]colors_cyl = [plt.cm.Spectral(i / float(n_categories)) for i in range(n_categories)]# By Make Datadf_make = df_raw.groupby('manufacturer').size().reset_index(name='counts_make')n_categories = df_make.shape[0]colors_make = [plt.cm.tab20b(i / float(n_categories)) for i in range(n_categories)]# Draw Plot and Decoratefig = plt.figure( FigureClass=Waffle, plots={ '311': { 'values': df_class['counts_class'], 'labels': ["{1}".format(n[0], n[1]) for n in df_class[['class', 'counts_class']].itertuples()], 'legend': {'loc': 'upper left', 'bbox_to_anchor': (1.05, 1), 'fontsize': 12, 'title': 'Class'}, 'title': {'label': '# Vehicles by Class', 'loc': 'center', 'fontsize': 18}, 'colors': colors_class }, '312': { 'values': df_cyl['counts_cyl'], 'labels': ["{1}".format(n[0], n[1]) for n in df_cyl[['cyl', 'counts_cyl']].itertuples()], 'legend': {'loc': 'upper left', 'bbox_to_anchor': (1.05, 1), 'fontsize': 12, 'title': 'Cyl'}, 'title': {'label': '# Vehicles by Cyl', 'loc': 'center', 'fontsize': 18}, 'colors': colors_cyl }, '313': { 'values': df_make['counts_make'], 'labels': ["{1}".format(n[0], n[1]) for n in df_make[['manufacturer', 'counts_make']].itertuples()], 'legend': {'loc': 'upper left', 'bbox_to_anchor': (1.05, 1), 'fontsize': 12, 'title': 'Manufacturer'}, 'title': {'label': '# Vehicles by Make', 'loc': 'center', 'fontsize': 18}, 'colors': colors_make } }, rows=9, figsize=(16, 14))# 译者 TRHX 添加了这行代码plt.show() 【32】饼图(Pie Chart) 饼图是显示组成的经典方法。然而,现在一般不宜使用,因为馅饼部分的面积有时会产生误导。因此,如果要使用饼图,强烈建议您显式地记下饼图每个部分的百分比或数字。 # Importdf_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Prepare Datadf = df_raw.groupby('class').size()# Make the plot with pandas'''原代码:df.plot(kind='pie', subplots=True, figsize=(8, 8), dpi=80)译者 TRHX 删除了 dpi= 80'''df.plot(kind='pie', subplots=True, figsize=(8, 8))plt.title("Pie Chart of Vehicle Class - Bad")plt.ylabel("")plt.show() # Importdf_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Prepare Datadf = df_raw.groupby('class').size().reset_index(name='counts')# Draw Plotfig, ax = plt.subplots(figsize=(12, 7), subplot_kw=dict(aspect="equal"), dpi=80)data = df['counts']categories = df['class']explode = [0, 0, 0, 0, 0, 0.1, 0]def func(pct, allvals): absolute = int(pct / 100. * np.sum(allvals)) return "{:.1f}% ({:d} )".format(pct, absolute)wedges, texts, autotexts = ax.pie(data, autopct=lambda pct: func(pct, data), textprops=dict(color="w"), colors=plt.cm.Dark2.colors, startangle=140, explode=explode)# Decorationax.legend(wedges, categories, title="Vehicle Class", loc="center left", bbox_to_anchor=(1, 0, 0.5, 1))plt.setp(autotexts, size=10, weight=700)ax.set_title("Class of Vehicles: Pie Chart")plt.show() 【33】矩阵树形图(Treemap) 矩阵树形图类似于饼图,它可以更好地完成工作而不会误导每个组的贡献。 【译者 TRHX 注:在使用该方法时要先安装 squarify 库】 # pip install squarifyimport squarify# Import Datadf_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Prepare Datadf = df_raw.groupby('class').size().reset_index(name='counts')labels = df.apply(lambda x: str(x[0]) + "\n (" + str(x[1]) + ")", axis=1)sizes = df['counts'].values.tolist()colors = [plt.cm.Spectral(i / float(len(labels))) for i in range(len(labels))]# Draw Plotplt.figure(figsize=(12, 8), dpi=80)squarify.plot(sizes=sizes, label=labels, color=colors, alpha=.8)# Decorateplt.title('Treemap of Vechile Class')plt.axis('off')plt.show() 【34】条形图(Bar Chart) 条形图是一种基于计数或任何给定度量的可视化项的经典方法。在下面的图表中,我为每个项目使用了不同的颜色,但您通常可能希望为所有项目选择一种颜色,除非您按组对它们进行着色。颜色名称存储在下面代码中的 all_colors 中。您可以通过在 plt.plot() 中设置 color 参数来更改条形的颜色。 import random# Import Datadf_raw = pd.read_csv("https://github.com/selva86/datasets/raw/master/mpg_ggplot2.csv")# Prepare Datadf = df_raw.groupby('manufacturer').size().reset_index(name='counts')n = df['manufacturer'].unique().__len__()+1all_colors = list(plt.cm.colors.cnames.keys())random.seed(100)c = random.choices(all_colors, k=n)# Plot Barsplt.figure(figsize=(16,10), dpi= 80)plt.bar(df['manufacturer'], df['counts'], color=c, width=.5)for i, val in enumerate(df['counts'].values): plt.text(i, val, float(val), horizontalalignment='center', verticalalignment='bottom', fontdict={'fontweight':500, 'size':12})# Decorationplt.gca().set_xticklabels(df['manufacturer'], rotation=60, horizontalalignment= 'right')plt.title("Number of Vehicles by Manaufacturers", fontsize=22)plt.ylabel('# Vehicles')plt.ylim(0, 45)plt.show() 【8x00】变化(Change) 【35】时间序列图(Time Series Plot) 时间序列图用于可视化给定指标随时间的变化。在这里你可以看到 1949 年到 1969 年间的航空客运量是如何变化的。 # Import Datadf = pd.read_csv('https://github.com/selva86/datasets/raw/master/AirPassengers.csv')# Draw Plotplt.figure(figsize=(16, 10), dpi=80)plt.plot('date', 'traffic', data=df, color='tab:red')# Decorationplt.ylim(50, 750)xtick_location = df.index.tolist()[::12]xtick_labels = [x[-4:] for x in df.date.tolist()[::12]]plt.xticks(ticks=xtick_location, labels=xtick_labels, rotation=0, fontsize=12, horizontalalignment='center', alpha=.7)plt.yticks(fontsize=12, alpha=.7)plt.title("Air Passengers Traffic (1949 - 1969)", fontsize=22)plt.grid(axis='both', alpha=.3)# Remove bordersplt.gca().spines["top"].set_alpha(0.0)plt.gca().spines["bottom"].set_alpha(0.3)plt.gca().spines["right"].set_alpha(0.0)plt.gca().spines["left"].set_alpha(0.3)plt.show() 【36】带波峰和波谷注释的时间序列图(Time Series with Peaks and Troughs Annotated) 下面的时间序列绘制了所有的波峰和波谷,并注释了所选特殊事件的发生。 # Import Datadf = pd.read_csv('https://github.com/selva86/datasets/raw/master/AirPassengers.csv')# Get the Peaks and Troughsdata = df['traffic'].valuesdoublediff = np.diff(np.sign(np.diff(data)))peak_locations = np.where(doublediff == -2)[0] + 1doublediff2 = np.diff(np.sign(np.diff(-1 * data)))trough_locations = np.where(doublediff2 == -2)[0] + 1# Draw Plotplt.figure(figsize=(16, 10), dpi=80)plt.plot('date', 'traffic', data=df, color='tab:blue', label='Air Traffic')plt.scatter(df.date[peak_locations], df.traffic[peak_locations], marker=mpl.markers.CARETUPBASE, color='tab:green', s=100, label='Peaks')plt.scatter(df.date[trough_locations], df.traffic[trough_locations], marker=mpl.markers.CARETDOWNBASE, color='tab:red', s=100, label='Troughs')# Annotatefor t, p in zip(trough_locations[1::5], peak_locations[::3]): plt.text(df.date[p], df.traffic[p] + 15, df.date[p], horizontalalignment='center', color='darkgreen') plt.text(df.date[t], df.traffic[t] - 35, df.date[t], horizontalalignment='center', color='darkred')# Decorationplt.ylim(50, 750)xtick_location = df.index.tolist()[::6]xtick_labels = df.date.tolist()[::6]plt.xticks(ticks=xtick_location, labels=xtick_labels, rotation=90, fontsize=12, alpha=.7)plt.title("Peak and Troughs of Air Passengers Traffic (1949 - 1969)", fontsize=22)plt.yticks(fontsize=12, alpha=.7)# Lighten bordersplt.gca().spines["top"].set_alpha(.0)plt.gca().spines["bottom"].set_alpha(.3)plt.gca().spines["right"].set_alpha(.0)plt.gca().spines["left"].set_alpha(.3)plt.legend(loc='upper left')plt.grid(axis='y', alpha=.3)plt.show() 【37】自相关 (ACF) 和部分自相关 (PACF) 图(Autocorrelation (ACF) and Partial Autocorrelation (PACF) Plot) 自相关图(ACF图)显示了时间序列与其自身滞后的相关性。 每条垂直线(在自相关图上)表示系列与滞后 0 之间的滞后的相关性。图中的蓝色阴影区域是显著性级别。 那些位于蓝线之上的滞后是显著的滞后。 那么如何解释呢? 对于航空乘客来说,我们看到超过 14 个滞后已经越过蓝线,因此意义重大。这意味着,14 年前的航空客运量对今天的交通量产生了影响。 另一方面,部分自相关图(PACF)显示了任何给定滞后(时间序列)相对于当前序列的自相关,但消除了中间滞后的贡献。 from statsmodels.graphics.tsaplots import plot_acf, plot_pacf# Import Datadf = pd.read_csv('https://github.com/selva86/datasets/raw/master/AirPassengers.csv')# Draw Plotfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 6), dpi=80)plot_acf(df.traffic.tolist(), ax=ax1, lags=50)plot_pacf(df.traffic.tolist(), ax=ax2, lags=20)# Decorate# lighten the bordersax1.spines["top"].set_alpha(.3); ax2.spines["top"].set_alpha(.3)ax1.spines["bottom"].set_alpha(.3); ax2.spines["bottom"].set_alpha(.3)ax1.spines["right"].set_alpha(.3); ax2.spines["right"].set_alpha(.3)ax1.spines["left"].set_alpha(.3); ax2.spines["left"].set_alpha(.3)# font size of tick labelsax1.tick_params(axis='both', labelsize=12)ax2.tick_params(axis='both', labelsize=12)plt.show() 【38】交叉相关图(Cross Correlation plot) 交叉相关图显示了两个时间序列相互之间的滞后。 import statsmodels.tsa.stattools as stattools# Import Datadf = pd.read_csv('https://github.com/selva86/datasets/raw/master/mortality.csv')x = df['mdeaths']y = df['fdeaths']# Compute Cross Correlationsccs = stattools.ccf(x, y)[:100]nlags = len(ccs)# Compute the Significance level# ref: https://stats.stackexchange.com/questions/3115/cross-correlation-significance-in-r/3128#3128conf_level = 2 / np.sqrt(nlags)# Draw Plotplt.figure(figsize=(12, 7), dpi=80)plt.hlines(0, xmin=0, xmax=100, color='gray') # 0 axisplt.hlines(conf_level, xmin=0, xmax=100, color='gray')plt.hlines(-conf_level, xmin=0, xmax=100, color='gray')plt.bar(x=np.arange(len(ccs)), height=ccs, width=.3)# Decorationplt.title('$Cross\; Correlation\; Plot:\; mdeaths\; vs\; fdeaths$', fontsize=22)plt.xlim(0, len(ccs))plt.show() 【39】时间序列分解图(Time Series Decomposition Plot) 时间序列分解图将时间序列分解为趋势、季节和残差分量。 from statsmodels.tsa.seasonal import seasonal_decomposefrom dateutil.parser import parse# Import Datadf = pd.read_csv('https://github.com/selva86/datasets/raw/master/AirPassengers.csv')dates = pd.DatetimeIndex([parse(d).strftime('%Y-%m-01') for d in df['date']])df.set_index(dates, inplace=True)# Decomposeresult = seasonal_decompose(df['traffic'], model='multiplicative')# Plotplt.rcParams.update({'figure.figsize': (10, 10)})result.plot().suptitle('Time Series Decomposition of Air Passengers')plt.show() 【40】多重时间序列(Multiple Time Series) 您可以在同一图表上绘制多个测量相同值的时间序列,如下所示。 # Import Datadf = pd.read_csv('https://github.com/selva86/datasets/raw/master/mortality.csv')# Define the upper limit, lower limit, interval of Y axis and colorsy_LL = 100y_UL = int(df.iloc[:, 1:].max().max() * 1.1)y_interval = 400mycolors = ['tab:red', 'tab:blue', 'tab:green', 'tab:orange']# Draw Plot and Annotatefig, ax = plt.subplots(1, 1, figsize=(16, 9), dpi=80)columns = df.columns[1:]for i, column in enumerate(columns): plt.plot(df.date.values, df[column].values, lw=1.5, color=mycolors[i]) plt.text(df.shape[0] + 1, df[column].values[-1], column, fontsize=14, color=mycolors[i])# Draw Tick linesfor y in range(y_LL, y_UL, y_interval): plt.hlines(y, xmin=0, xmax=71, colors='black', alpha=0.3, linestyles="--", lw=0.5)# Decorationsplt.tick_params(axis="both", which="both", bottom=False, top=False, labelbottom=True, left=False, right=False, labelleft=True)# Lighten bordersplt.gca().spines["top"].set_alpha(.3)plt.gca().spines["bottom"].set_alpha(.3)plt.gca().spines["right"].set_alpha(.3)plt.gca().spines["left"].set_alpha(.3)plt.title('Number of Deaths from Lung Diseases in the UK (1974-1979)', fontsize=22)plt.yticks(range(y_LL, y_UL, y_interval), [str(y) for y in range(y_LL, y_UL, y_interval)], fontsize=12)plt.xticks(range(0, df.shape[0], 12), df.date.values[::12], horizontalalignment='left', fontsize=12)plt.ylim(y_LL, y_UL)plt.xlim(-2, 80)plt.show() 【41】使用次要的 Y 轴来绘制不同范围的图形(Plotting with different scales using secondary Y axis) 如果要显示在同一时间点测量两个不同数量的两个时间序列,则可以在右侧的次要 Y 轴上再绘制第二个系列。 # Import Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/economics.csv")x = df['date']y1 = df['psavert']y2 = df['unemploy']# Plot Line1 (Left Y Axis)fig, ax1 = plt.subplots(1, 1, figsize=(16, 9), dpi=80)ax1.plot(x, y1, color='tab:red')# Plot Line2 (Right Y Axis)ax2 = ax1.twinx() # instantiate a second axes that shares the same x-axisax2.plot(x, y2, color='tab:blue')# Decorations# ax1 (left Y axis)ax1.set_xlabel('Year', fontsize=20)ax1.tick_params(axis='x', rotation=0, labelsize=12)ax1.set_ylabel('Personal Savings Rate', color='tab:red', fontsize=20)ax1.tick_params(axis='y', rotation=0, labelcolor='tab:red')ax1.grid(alpha=.4)# ax2 (right Y axis)ax2.set_ylabel("# Unemployed (1000's)", color='tab:blue', fontsize=20)ax2.tick_params(axis='y', labelcolor='tab:blue')ax2.set_xticks(np.arange(0, len(x), 60))ax2.set_xticklabels(x[::60], rotation=90, fontdict={'fontsize': 10})ax2.set_title("Personal Savings Rate vs Unemployed: Plotting in Secondary Y Axis", fontsize=22)fig.tight_layout()plt.show() 【42】带误差带的时间序列(Time Series with Error Bands) 如果您有一个时间序列数据集,其中每个时间点(日期/时间戳)有多个观测值,则可以构造具有误差带的时间序列。下面您可以看到一些基于一天中不同时间的订单的示例。还有一个关于45天内到达的订单数量的例子。 在这种方法中,订单数量的平均值用白线表示。并计算95%的置信区间,并围绕平均值绘制。 from scipy.stats import sem# Import Datadf = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/user_orders_hourofday.csv")df_mean = df.groupby('order_hour_of_day').quantity.mean()df_se = df.groupby('order_hour_of_day').quantity.apply(sem).mul(1.96)# Plotplt.figure(figsize=(16, 10), dpi=80)plt.ylabel("# Orders", fontsize=16)x = df_mean.indexplt.plot(x, df_mean, color="white", lw=2)plt.fill_between(x, df_mean - df_se, df_mean + df_se, color="#3F5D7D")# Decorations# Lighten bordersplt.gca().spines["top"].set_alpha(0)plt.gca().spines["bottom"].set_alpha(1)plt.gca().spines["right"].set_alpha(0)plt.gca().spines["left"].set_alpha(1)plt.xticks(x[::2], [str(d) for d in x[::2]], fontsize=12)plt.title("User Orders by Hour of Day (95% confidence)", fontsize=22)plt.xlabel("Hour of Day")s, e = plt.gca().get_xlim()plt.xlim(s, e)# Draw Horizontal Tick linesfor y in range(8, 20, 2): plt.hlines(y, xmin=s, xmax=e, colors='black', alpha=0.5, linestyles="--", lw=0.5)plt.show() "Data Source: https://www.kaggle.com/olistbr/brazilian-ecommerce#olist_orders_dataset.csv"from dateutil.parser import parsefrom scipy.stats import sem# Import Datadf_raw = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/orders_45d.csv', parse_dates=['purchase_time', 'purchase_date'])# Prepare Data: Daily Mean and SE Bandsdf_mean = df_raw.groupby('purchase_date').quantity.mean()df_se = df_raw.groupby('purchase_date').quantity.apply(sem).mul(1.96)# Plotplt.figure(figsize=(16, 10), dpi=80)plt.ylabel("# Daily Orders", fontsize=16)x = [d.date().strftime('%Y-%m-%d') for d in df_mean.index]plt.plot(x, df_mean, color="white", lw=2)plt.fill_between(x, df_mean - df_se, df_mean + df_se, color="#3F5D7D")# Decorations# Lighten bordersplt.gca().spines["top"].set_alpha(0)plt.gca().spines["bottom"].set_alpha(1)plt.gca().spines["right"].set_alpha(0)plt.gca().spines["left"].set_alpha(1)plt.xticks(x[::6], [str(d) for d in x[::6]], fontsize=12)plt.title("Daily Order Quantity of Brazilian Retail with Error Bands (95% confidence)", fontsize=20)# Axis limitss, e = plt.gca().get_xlim()plt.xlim(s, e - 2)plt.ylim(4, 10)# Draw Horizontal Tick linesfor y in range(5, 10, 1): plt.hlines(y, xmin=s, xmax=e, colors='black', alpha=0.5, linestyles="--", lw=0.5)plt.show() 【43】堆积面积图(Stacked Area Chart) 堆积面积图提供了多个时间序列的贡献程度的可视化表示,以便相互比较。 # Import Datadf = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/nightvisitors.csv')# Decide Colorsmycolors = ['tab:red', 'tab:blue', 'tab:green', 'tab:orange', 'tab:brown', 'tab:grey', 'tab:pink', 'tab:olive']# Draw Plot and Annotatefig, ax = plt.subplots(1, 1, figsize=(16, 9), dpi=80)columns = df.columns[1:]labs = columns.values.tolist()# Prepare datax = df['yearmon'].values.tolist()y0 = df[columns[0]].values.tolist()y1 = df[columns[1]].values.tolist()y2 = df[columns[2]].values.tolist()y3 = df[columns[3]].values.tolist()y4 = df[columns[4]].values.tolist()y5 = df[columns[5]].values.tolist()y6 = df[columns[6]].values.tolist()y7 = df[columns[7]].values.tolist()y = np.vstack([y0, y2, y4, y6, y7, y5, y1, y3])# Plot for each columnlabs = columns.values.tolist()ax = plt.gca()ax.stackplot(x, y, labels=labs, colors=mycolors, alpha=0.8)# Decorationsax.set_title('Night Visitors in Australian Regions', fontsize=18)ax.set(ylim=[0, 100000])ax.legend(fontsize=10, ncol=4)plt.xticks(x[::5], fontsize=10, horizontalalignment='center')plt.yticks(np.arange(10000, 100000, 20000), fontsize=10)plt.xlim(x[0], x[-1])# Lighten bordersplt.gca().spines["top"].set_alpha(0)plt.gca().spines["bottom"].set_alpha(.3)plt.gca().spines["right"].set_alpha(0)plt.gca().spines["left"].set_alpha(.3)plt.show() 【44】未堆积面积图(Area Chart UnStacked) 未堆积的面积图用于可视化两个或多个序列彼此之间的进度(起伏)。在下面的图表中,你可以清楚地看到,随着失业持续时间的中位数增加,个人储蓄率是如何下降的。未堆积面积图很好地展示了这一现象。 # Import Datadf = pd.read_csv("https://github.com/selva86/datasets/raw/master/economics.csv")# Prepare Datax = df['date'].values.tolist()y1 = df['psavert'].values.tolist()y2 = df['uempmed'].values.tolist()mycolors = ['tab:red', 'tab:blue', 'tab:green', 'tab:orange', 'tab:brown', 'tab:grey', 'tab:pink', 'tab:olive']columns = ['psavert', 'uempmed']# Draw Plotfig, ax = plt.subplots(1, 1, figsize=(16, 9), dpi=80)ax.fill_between(x, y1=y1, y2=0, label=columns[1], alpha=0.5, color=mycolors[1], linewidth=2)ax.fill_between(x, y1=y2, y2=0, label=columns[0], alpha=0.5, color=mycolors[0], linewidth=2)# Decorationsax.set_title('Personal Savings Rate vs Median Duration of Unemployment', fontsize=18)ax.set(ylim=[0, 30])ax.legend(loc='best', fontsize=12)plt.xticks(x[::50], fontsize=10, horizontalalignment='center')plt.yticks(np.arange(2.5, 30.0, 2.5), fontsize=10)plt.xlim(-10, x[-1])# Draw Tick linesfor y in np.arange(2.5, 30.0, 2.5): plt.hlines(y, xmin=0, xmax=len(x), colors='black', alpha=0.3, linestyles="--", lw=0.5)# Lighten bordersplt.gca().spines["top"].set_alpha(0)plt.gca().spines["bottom"].set_alpha(.3)plt.gca().spines["right"].set_alpha(0)plt.gca().spines["left"].set_alpha(.3)plt.show() 【45】日历热力图(Calendar Heat Map) 与时间序列相比,日历地图是另一种基于时间的数据可视化的不太受欢迎的方法。虽然在视觉上很吸引人,但数值并不十分明显。然而,它能很好地描绘极端值和假日效果。 【译者 TRHX 注:在使用该方法时要先安装 calmap 库】 import matplotlib as mplimport calmap# Import Datadf = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/yahoo.csv", parse_dates=['date'])df.set_index('date', inplace=True)# Plotplt.figure(figsize=(16, 10), dpi=80)calmap.calendarplot(df['2014']['VIX.Close'], fig_kws={'figsize': (16, 10)}, yearlabel_kws={'color': 'black', 'fontsize': 14}, subplot_kws={'title': 'Yahoo Stock Prices'})plt.show() 【46】季节图(Seasonal Plot) 季节图可用于比较上一季度同一天(年/月/周等)时间序列的表现。 from dateutil.parser import parse# Import Datadf = pd.read_csv('https://github.com/selva86/datasets/raw/master/AirPassengers.csv')# Prepare datadf['year'] = [parse(d).year for d in df.date]df['month'] = [parse(d).strftime('%b') for d in df.date]years = df['year'].unique()# 译者 TRHX 添加了该行代码df.rename(columns={'value': 'traffic'}, inplace=True)# Draw Plotmycolors = ['tab:red', 'tab:blue', 'tab:green', 'tab:orange', 'tab:brown', 'tab:grey', 'tab:pink', 'tab:olive', 'deeppink', 'steelblue', 'firebrick', 'mediumseagreen']plt.figure(figsize=(16, 10), dpi=80)for i, y in enumerate(years): plt.plot('month', 'traffic', data=df.loc[df.year == y, :], color=mycolors[i], label=y) plt.text(df.loc[df.year == y, :].shape[0] - .9, df.loc[df.year == y, 'traffic'][-1:].values[0], y, fontsize=12, color=mycolors[i])# Decorationplt.ylim(50, 750)plt.xlim(-0.3, 11)plt.ylabel('$Air Traffic$')plt.yticks(fontsize=12, alpha=.7)plt.title("Monthly Seasonal Plot: Air Passengers Traffic (1949 - 1969)", fontsize=22)plt.grid(axis='y', alpha=.3)# Remove bordersplt.gca().spines["top"].set_alpha(0.0)plt.gca().spines["bottom"].set_alpha(0.5)plt.gca().spines["right"].set_alpha(0.0)plt.gca().spines["left"].set_alpha(0.5)# plt.legend(loc='upper right', ncol=2, fontsize=12)plt.show() 【9x00】分组( Groups) 【47】树状图(Dendrogram) 树状图根据给定的距离度量将相似的点组合在一起,并根据点的相似性将它们组织成树状链接。 import scipy.cluster.hierarchy as shc# Import Datadf = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/USArrests.csv')# Plotplt.figure(figsize=(16, 10), dpi=80)plt.title("USArrests Dendograms", fontsize=22)dend = shc.dendrogram(shc.linkage(df[['Murder', 'Assault', 'UrbanPop', 'Rape']], method='ward'), labels=df.State.values, color_threshold=100)plt.xticks(fontsize=12)plt.show() 【48】聚类图(Cluster Plot) 聚类图可以用来划分属于同一个聚类的点。下面是一个基于 USArrests 数据集将美国各州分成 5 组的代表性示例。这个聚类图使用 ‘murder’ 和 ‘assault’ 作为 X 轴和 Y 轴。或者,您可以将第一个主元件用作 X 轴和 Y 轴。 【译者 TRHX 注:在使用该方法时要先安装 sklearn 库】 from sklearn.cluster import AgglomerativeClusteringfrom scipy.spatial import ConvexHull# Import Datadf = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/USArrests.csv')# Agglomerative Clusteringcluster = AgglomerativeClustering(n_clusters=5, affinity='euclidean', linkage='ward')cluster.fit_predict(df[['Murder', 'Assault', 'UrbanPop', 'Rape']])# Plotplt.figure(figsize=(14, 10), dpi=80)plt.scatter(df.iloc[:, 0], df.iloc[:, 1], c=cluster.labels_, cmap='tab10')# Encircledef encircle(x, y, ax=None, **kw): if not ax: ax = plt.gca() p = np.c_[x, y] hull = ConvexHull(p) poly = plt.Polygon(p[hull.vertices,:], **kw) ax.add_patch(poly)# Draw polygon surrounding verticesencircle(df.loc[cluster.labels_ == 0, 'Murder'], df.loc[cluster.labels_ == 0, 'Assault'], ec="k", fc="gold", alpha=0.2, linewidth=0)encircle(df.loc[cluster.labels_ == 1, 'Murder'], df.loc[cluster.labels_ == 1, 'Assault'], ec="k", fc="tab:blue", alpha=0.2, linewidth=0)encircle(df.loc[cluster.labels_ == 2, 'Murder'], df.loc[cluster.labels_ == 2, 'Assault'], ec="k", fc="tab:red", alpha=0.2, linewidth=0)encircle(df.loc[cluster.labels_ == 3, 'Murder'], df.loc[cluster.labels_ == 3, 'Assault'], ec="k", fc="tab:green", alpha=0.2, linewidth=0)encircle(df.loc[cluster.labels_ == 4, 'Murder'], df.loc[cluster.labels_ == 4, 'Assault'], ec="k", fc="tab:orange", alpha=0.2, linewidth=0)# Decorationsplt.xlabel('Murder'); plt.xticks(fontsize=12)plt.ylabel('Assault'); plt.yticks(fontsize=12)plt.title('Agglomerative Clustering of USArrests (5 Groups)', fontsize=22)plt.show() 【49】安德鲁斯曲线(Andrews Curve) 安德鲁斯曲线有助于可视化是否存在基于给定分组的数值特征的固有分组。如果特征(数据集中的列)不能帮助区分组(cyl),则行将不会像下图所示被很好地分隔开。 from pandas.plotting import andrews_curves# Importdf = pd.read_csv("https://github.com/selva86/datasets/raw/master/mtcars.csv")df.drop(['cars', 'carname'], axis=1, inplace=True)# Plotplt.figure(figsize=(12, 9), dpi=80)andrews_curves(df, 'cyl', colormap='Set1')# Lighten bordersplt.gca().spines["top"].set_alpha(0)plt.gca().spines["bottom"].set_alpha(.3)plt.gca().spines["right"].set_alpha(0)plt.gca().spines["left"].set_alpha(.3)plt.title('Andrews Curves of mtcars', fontsize=22)plt.xlim(-3, 3)plt.grid(alpha=0.3)plt.xticks(fontsize=12)plt.yticks(fontsize=12)plt.show() 【50】平行坐标图(Parallel Coordinates) 平行坐标有助于可视化功能是否有助于有效地隔离组。如果一个分离受到影响,则该特征可能在预测该组时非常有用。 from pandas.plotting import parallel_coordinates# Import Datadf_final = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/diamonds_filter.csv")# Plotplt.figure(figsize=(12, 9), dpi=80)parallel_coordinates(df_final, 'cut', colormap='Dark2')# Lighten bordersplt.gca().spines["top"].set_alpha(0)plt.gca().spines["bottom"].set_alpha(.3)plt.gca().spines["right"].set_alpha(0)plt.gca().spines["left"].set_alpha(.3)plt.title('Parallel Coordinated of Diamonds', fontsize=22)plt.grid(alpha=0.3)plt.xticks(fontsize=12)plt.yticks(fontsize=12)plt.show() 这里是一段物理防爬虫文本,请读者忽略。本译文首发于 CSDN,作者 Selva Prabhakaran,译者 TRHX。本文链接:https://itrhx.blog.csdn.net/article/details/106558131原文链接:https://www.machinelearningplus.com/plots/top-50-matplotlib-visualizations-the-master-plots-python/
文章目录 【01x00】了解 mplot3d Toolkit 【01x01】Axes3D 对象创建方法一:Axes3D(fig) 【01x02】Axes3D 对象创建方法二:add_subplot 【01x03】Axes3D 对象创建方法三:gca 【02x00】cmap 与 colorbar 【03x00】3D 线性图:Axes3D.plot 【04x00】3D 散点图:Axes3D.scatter 【05x00】3D 线框图:Axes3D.plot_wireframe 【06x00】3D 曲面图:Axes3D.plot_surface 【07x00】3D 柱状图:Axes3D.bar 【08x00】3D 箭头图:Axes3D.quiver 【09x00】3D 等高线图:Axes3D.contour 【10x00】3D 等高线填充图:Axes3D.contourf 【11x00】3D 三角曲面图:Axes3D.plot_trisurf 【12x00】将 2D 图像聚合到 3D 图像中:Axes3D.add_collection3d 【13x00】3D 图添加文本描述:Axes3D.text Matplotlib 系列文章: Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件 Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性 Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性 Python 数据分析三剑客之 Matplotlib(四):线性图的绘制 Python 数据分析三剑客之 Matplotlib(五):散点图的绘制 Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制 Python 数据分析三剑客之 Matplotlib(七):饼状图的绘制 Python 数据分析三剑客之 Matplotlib(八):等高线 / 等值线图的绘制 Python 数据分析三剑客之 Matplotlib(九):极区图 / 极坐标图 / 雷达图的绘制 Python 数据分析三剑客之 Matplotlib(十):3D 图的绘制 Python 数据分析三剑客之 Matplotlib(十一):最热门最常用的 50 个图表【译文】 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106558131未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【01x00】了解 mplot3d Toolkit mplot3d Toolkit 即 mplot3d 工具包,在 matplotlib 中使用 mplot3d 工具包可以绘制 3D 图。 mplot3d 官方文档:https://matplotlib.org/tutorials/toolkits/mplot3d.html 在 matplotlib 中,figure 为画布,axes 为绘图区,fig.add_subplot()、plt.subplot() 方法均可以创建子图,在绘制 3D 图时,某些 2D 图的参数也适用于 3D 图,在本文的示例中,可能会用到的一些没有具体解释的函数或者参数,其用法均可在前面的系列文章中找到: 《Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件》 《Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性》 《Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性》 绘制 3D 图的步骤:创建 Axes3D 对象,然后调用 Axes3D 的不同方法来绘制不同类型的 3D 图。以下介绍三种 Axes3D 对象创建的方法。 【01x01】Axes3D 对象创建方法一:Axes3D(fig) 在 Matplotlib 1.0.0 版本中,绘制 3D 图需要先导入 Axes3D 包,获取 figure 画布对象 fig 后,通过 Axes3D(fig) 方法来创建 Axes3D 对象,具体方法如下: import numpy as npimport matplotlib.pyplot as pltfrom mpl_toolkits.mplot3d import Axes3D# 获取 figure 画布并创建 Axes3D 对象fig = plt.figure()ax = Axes3D(fig)# 数据坐标z = np.linspace(0, 15, 1000)x = np.sin(z)y = np.cos(z)# 绘制线性图ax.plot(x, y, z)plt.show() 【01x02】Axes3D 对象创建方法二:add_subplot 在 Matplotlib 3.2.0 版本中,绘制 3D 图可以通过创建子图,然后指定 projection 参数 为 3d 即可,返回的 ax 为 Axes3D 对象,以下两种方法均可: import numpy as npimport matplotlib.pyplot as plt# 获取 figure 画布并通过子图创建 Axes3D 对象fig = plt.figure()ax = fig.add_subplot(111, projection='3d')# 数据坐标z = np.linspace(0, 15, 1000)x = np.sin(z)y = np.cos(z)# 绘制线性图ax.plot(x, y, z)plt.show() import numpy as npimport matplotlib.pyplot as plt# 通过子图创建 Axes3D 对象ax = plt.subplot(111, projection='3d')# 数据坐标z = np.linspace(0, 15, 1000)x = np.sin(z)y = np.cos(z)# 绘制线性图ax.plot(x, y, z)plt.show() 【01x03】Axes3D 对象创建方法三:gca 除了以上两种方法以外,还可以先获取画布对象 fig,再通过 fig.gca() 方法获取当前绘图区(gca = Get Current Axes),然后指定 projection 参数 为 3d 即可,返回的 ax 为 Axes3D 对象。 import numpy as npimport matplotlib.pyplot as plt# 依次获取画布和绘图区并创建 Axes3D 对象fig = plt.figure()ax = fig.gca(projection='3d')# 数据坐标z = np.linspace(0, 15, 1000)x = np.sin(z)y = np.cos(z)# 绘制线性图ax.plot(x, y, z)plt.show() 以上三种方法运行结果均为下图: 【02x00】cmap 与 colorbar 默认情况下,散点图、线性图、曲面图等将以纯色着色,但可以通过提供 cmap 参数支持颜色映射。cmap 参数用于设置一些特殊的颜色组合,如渐变色等,参数取值通常为 Colormap 中的值,具体取值可参见下图: 官方文档:https://matplotlib.org/tutorials/colors/colormaps.html 如果使用了 cmap 参数,则可以使用 pyplot.colorbar() 函数来绘制一个色条,即颜色对照条。 基本语法:matplotlib.pyplot.colorbar([mappable=None, cax=None, ax=None, **kw]) 部分参数解释如下表,其他参数,如长度,宽度等请参考官方文档。 参数描述 mappable要设置色条的图像对象,该参数对于 Figure.colorbar 方法是必需的,但对于 pyplot.colorbar 函数是可选的 cax可选项,要绘制色条的轴 ax可选项,设置色条的显示位置,通常在一个画布上有多个子图时使用 **kw可选项,其他关键字参数,参考官方文档 【03x00】3D 线性图:Axes3D.plot 基本方法:Axes3D.plot(xs, ys[, zs, zdir='z', *args, **kwargs]) 参数描述 xs一维数组,点的 x 轴坐标 ys一维数组,点的 y 轴坐标 zs一维数组,可选项,点的 z 轴坐标 zdir可选项,在 3D 轴上绘制 2D 数据时,数据必须以 xs,ys 的形式传递, 若此时将 zdir 设置为 ‘y’,数据将会被绘制到 x-z 轴平面上,默认为 ‘z’ **kwargs其他关键字参数,可选项,可参见 matplotlib.axes.Axes.plot import numpy as npimport matplotlib.pyplot as plt# 设置中文显示plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']# 依次获取画布和绘图区并创建 Axes3D 对象fig = plt.figure()ax = fig.gca(projection='3d')# 第一条3D线性图数据theta = np.linspace(-4 * np.pi, 4 * np.pi, 100)z1 = np.linspace(-2, 2, 100)r = z1**2 + 1x1 = r * np.sin(theta)y1 = r * np.cos(theta)# 第二条3D线性图数据z2 = np.linspace(-3, 3, 100)x2 = np.sin(z2)y2 = np.cos(z2)# 绘制3D线性图ax.plot(x1, y1, z1, color='b', label='3D 线性图一')ax.plot(x2, y2, z2, color='r', label='3D 线性图二')# 设置标题、轴标签、图例,也可以直接使用 plt.title、plt.xlabel、plt.legend...ax.set_title('绘制 3D 线性图示例', pad=15, fontsize='12')ax.set_xlabel('x 轴', color='r', fontsize='12')ax.set_ylabel('y 轴', color='g', fontsize='12')ax.set_zlabel('z 轴', color='b', fontsize='12')ax.legend()plt.show() 【04x00】3D 散点图:Axes3D.scatter 基本方法:Axes3D.scatter(xs, ys[, zs=0, zdir='z', s=20, c=None, depthshade=True, *args, **kwargs]) 参数描述 xs一维数组,点的 x 轴坐标 ys一维数组,点的 y 轴坐标 zs一维数组,可选项,点的 z 轴坐标 zdir可选项,在 3D 轴上绘制 2D 数据时,数据必须以 xs,ys 的形式传递, 若此时将 zdir 设置为 ‘y’,数据将会被绘制到 x-z 轴平面上,默认为 ‘z’ s标量或数组类型,可选项,标记的大小,默认 20 c标记的颜色,可选项,可以是单个颜色或者一个颜色列表 支持英文颜色名称及其简写、十六进制颜色码等,更多颜色示例参见官网 Color Demo depthshadebool 值,可选项,默认 True,是否为散点标记着色以提供深度外观 **kwargs其他关键字参数,可选项,可参见 scatter import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']# 依次获取画布和绘图区并创建 Axes3D 对象fig = plt.figure()ax = fig.gca(projection='3d')n = 100def randrange(n, vmin, vmax): return (vmax - vmin)*np.random.rand(n) + vmin'''定义绘制 n 个随机点,设置每一组数据点的样式和范围x轴数据位于[23,32]区间,y轴数据位于[0,100]区间,z轴数据位于[zlow,zhigh]区间'''for m, zlow, zhigh in [('o', -50, -25), ('^', -30, -5)]: xs = randrange(n, 23, 32) ys = randrange(n, 0, 100) zs = randrange(n, zlow, zhigh) ax.scatter(xs, ys, zs, marker=m)# 设置标题、轴标签、图例,也可以直接使用 plt.title、plt.xlabel...ax.set_title('绘制 3D 散点图示例', pad=15, fontsize='12')ax.set_xlabel('x 轴', color='b')ax.set_ylabel('y 轴', color='b')ax.set_zlabel('z 轴', color='b')plt.show() 【05x00】3D 线框图:Axes3D.plot_wireframe 基本方法:Axes3D.plot_wireframe(X, Y, Z[, *args, **kwargs]) 参数描述 X二维数组,x 轴数据 Y二维数组,y 轴数据 Z二维数组,z 轴数据 **kwargs其他关键字参数,可选项,如线条样式颜色等,可参见 Line3DCollection import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']# 获取 figure 画布并通过子图创建 Axes3D 对象fig = plt.figure()ax = fig.add_subplot(111, projection='3d')# 定义Z轴坐标的生成方法def f(m, n): return np.sin(np.sqrt(m ** 2 + n ** 2))# 设置3D线框图数据x = np.linspace(-6, 6, 30)y = np.linspace(-6, 6, 30)# 生成网格点坐标矩阵,该方法在系列文章八中有具体介绍X, Y = np.meshgrid(x, y)Z = f(X, Y)# 绘制3D线框图ax.plot_wireframe(X, Y, Z, color='c')# 设置标题、轴标签、图例,也可以直接使用 plt.title、plt.xlabel...ax.set_title('绘制 3D 线框图示例', pad=15, fontsize='12')ax.set_xlabel('x 轴')ax.set_ylabel('y 轴')ax.set_zlabel('z 轴')plt.show() 【06x00】3D 曲面图:Axes3D.plot_surface 基本方法:Axes3D.plot_surface(X, Y, Z[, *args, vmin=None, vmax=None, **kwargs]) 参数描述 X二维数组,x 轴数据 Y二维数组,y 轴数据 Z二维数组,z 轴数据 vmin / vmax规定数据界限 **kwargs其他关键字参数,可选项,如线条样式颜色等,可参见 Line3DCollection import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']# 获取 figure 画布并通过子图创建 Axes3D 对象fig = plt.figure()ax = fig.add_subplot(111, projection='3d')# 设置3D曲面图数据X = np.arange(-5, 5, 0.25)Y = np.arange(-5, 5, 0.25)# 生成网格点坐标矩阵,该方法在系列文章八中有具体介绍X, Y = np.meshgrid(X, Y)R = np.sqrt(X**2 + Y**2)Z = np.sin(R)# 绘制3D曲面图并添加色条(长度0.8)surface = ax.plot_surface(X, Y, Z, cmap='rainbow', antialiased=False)fig.colorbar(surface, shrink=0.8)# 设置标题、轴标签、图例,也可以直接使用 plt.title、plt.xlabel...ax.set_title('绘制 3D 曲面图示例', pad=15, fontsize='12')ax.set_xlabel('x 轴')ax.set_ylabel('y 轴')ax.set_zlabel('z 轴')# 调整观察角度和方位角,俯仰角25度,方位角40度ax.view_init(25, 40)# 设置Z轴刻度界限ax.set_zlim(-2, 2)plt.show() 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106558131未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【07x00】3D 柱状图:Axes3D.bar 基本方法:Axes3D.bar(left, height, zs=0, zdir='z', *args, **kwargs) 参数描述 left一维数组,柱状图最左侧位置的 x 坐标 height一维数组,柱状图的高度(y 坐标) zs第 i 个多边形将出现在平面 y=zs[i] 上 zdir可选项,在 3D 轴上绘制 2D 数据时,数据必须以 xs,ys 的形式传递, 若此时将 zdir 设置为 ‘y’,数据将会被绘制到 x-z 轴平面上,默认为 ‘z’ **kwargs其他关键字参数,参见 matplotlib.axes.Axes.bar import matplotlib.pyplot as pltimport numpy as npplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']# 获取 figure 画布并通过子图创建 Axes3D 对象fig = plt.figure()ax = fig.add_subplot(111, projection='3d')colors = ['r', 'g', 'b', 'y']yticks = [3, 2, 1, 0]# 设置3D柱状图数据并绘制图像for c, k in zip(colors, yticks): xs = np.arange(20) ys = np.random.rand(20) cs = [c] * len(xs) ax.bar(xs, ys, zs=k, zdir='y', color=cs, alpha=0.8)# 设置图像标题、坐标标签以及范围ax.set_title('绘制 3D 柱状图示例', pad=15, fontsize='12')ax.set_xlabel('X 轴')ax.set_ylabel('Y 轴')ax.set_zlabel('Z 轴')ax.set_yticks(yticks)plt.show() 【08x00】3D 箭头图:Axes3D.quiver 基本方法:Axes3D.quiver(X, Y, Z, U, V, W, length=1, arrow_length_ratio=0.3, pivot='tail', normalize=False, **kwargs) 参数描述 X, Y, Z数组形式,箭头位置的 x、y 和 z 轴坐标(默认为箭头尾部) U, V, W数组形式,箭头向量的 x、y 和 z 轴分量 lengthfloat 类型,每个箭筒的长度,默认为 1.0 arrow_length_ratiofloat 类型,箭头相对于箭身的比率,默认为 0.3 pivot箭头在网格点上的位置;箭头围绕该点旋转,因此命名为 pivot,默认为 ‘tail’ 可选项:'tail':尾部;'middle':中间;'tip':尖端 normalizebool 类型,如果为 True,则所有箭头的长度都将相同 默认为 False,即箭头的长度取决于 U、V、W 的值 **kwargs其他关键字参数,参见 LineCollection import matplotlib.pyplot as pltimport numpy as npplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']# 依次获取画布和绘图区并创建 Axes3D 对象fig = plt.figure()ax = fig.gca(projection='3d')# 设置箭头位置x, y, z = np.meshgrid(np.arange(-0.8, 1, 0.2), np.arange(-0.8, 1, 0.2), np.arange(-0.8, 1, 0.8))# 设置箭头数据u = np.sin(np.pi * x) * np.cos(np.pi * y) * np.cos(np.pi * z)v = -np.cos(np.pi * x) * np.sin(np.pi * y) * np.cos(np.pi * z)w = (np.sqrt(2.0 / 3.0) * np.cos(np.pi * x) * np.cos(np.pi * y) * np.sin(np.pi * z))# 绘制 3D 箭头图ax.quiver(x, y, z, u, v, w, length=0.1, normalize=True)# 设置图像标题、坐标标签ax.set_title('绘制 3D 箭头图示例', pad=15, fontsize='12')ax.set_xlabel('X 轴')ax.set_ylabel('Y 轴')ax.set_zlabel('Z 轴')# 调整观察角度,俯仰角20度ax.view_init(20)plt.show() 【09x00】3D 等高线图:Axes3D.contour 基本方法:Axes3D.contour(X, Y, Z[, *args, extend3d=False, stride=5, zdir='z', offset=None, **kwargs]) 参数描述 X一维数组,x 轴数据 Y一维数组,y 轴数据 Z一维数组,z 轴数据 extend3dbool 值,可选项,是否以 3D 延伸轮廓,默认 False strideint 类型,可选项,用于延伸轮廓的步长 zdir可选项,在 3D 轴上绘制 2D 数据时,数据必须以 xs,ys 的形式传递, 若此时将 zdir 设置为 ‘y’,数据将会被绘制到 x-z 轴平面上,默认为 ‘z’ offset标量,可选项,如果指定,则在垂直于 zdir 的平面上的位置绘制轮廓线的投影 **kwargs其他关键字参数,可选项,可参见 matplotlib.axes.Axes.contour import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']# 获取 figure 画布并通过子图创建 Axes3D 对象fig = plt.figure(figsize=(8, 4.8))ax = fig.add_subplot(111, projection='3d')# 设置等高线数据X = np.arange(-2.0, 2.0, 0.01)Y = np.arange(-2.0, 2.0, 0.01)# 生成网格点坐标矩阵m, n = np.meshgrid(X, Y)# 指定一个函数用于计算每个点的高度,也可以直接使用二维数组储存每个点的高度def f(a, b): return (1 - b ** 5 + a ** 5) * np.exp(-a ** 2 - b ** 2)# 绘制3D等高线图并添加色条图(长度0.8)contour = ax.contour(X, Y, f(m, n), cmap='rainbow')fig.colorbar(contour, shrink=0.8)# 设置标题、轴标签、图例,也可以直接使用 plt.title、plt.xlabel...ax.set_title('绘制 3D 等高线图示例', pad=15, fontsize='12')ax.set_xlabel('x 轴')ax.set_ylabel('y 轴')ax.set_zlabel('z 轴')plt.show() 【10x00】3D 等高线填充图:Axes3D.contourf 基本语法:Axes3D.contourf(X, Y, Z[, *args, zdir='z', offset=None, **kwargs]) 参数描述 X一维数组,x 轴数据 Y一维数组,y 轴数据 Z一维数组,z 轴数据 zdir可选项,在 3D 轴上绘制 2D 数据时,数据必须以 xs,ys 的形式传递, 若此时将 zdir 设置为 ‘y’,数据将会被绘制到 x-z 轴平面上,默认为 ‘z’ offset标量,可选项,如果指定,则在垂直于 zdir 的平面上的位置绘制轮廓线的投影 **kwargs其他关键字参数,可选项,可参见 matplotlib.axes.Axes.contourf import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']# 获取 figure 画布并通过子图创建 Axes3D 对象fig = plt.figure(figsize=(8, 4.8))ax = fig.add_subplot(111, projection='3d')# 设置等高线数据X = np.arange(-2.0, 2.0, 0.01)Y = np.arange(-2.0, 2.0, 0.01)# 生成网格点坐标矩阵m, n = np.meshgrid(X, Y)# 指定一个函数用于计算每个点的高度,也可以直接使用二维数组储存每个点的高度def f(a, b): return (1 - b ** 5 + a ** 5) * np.exp(-a ** 2 - b ** 2)# 绘制3D等高线图并添加色条图(长度0.8)contourf = ax.contourf(X, Y, f(m, n), cmap='rainbow')fig.colorbar(contourf, shrink=0.8)# 设置标题、轴标签、图例,也可以直接使用 plt.title、plt.xlabel...ax.set_title('绘制 3D 等高线填充图示例', pad=15, fontsize='12')ax.set_xlabel('x 轴')ax.set_ylabel('y 轴')ax.set_zlabel('z 轴')plt.show() 【11x00】3D 三角曲面图:Axes3D.plot_trisurf 基本方法:Axes3D.plot_trisurf(X, Y, Z[, *args, color=None, vmin=None, vmax=None, **kwargs]) 参数描述 X一维数组,x 轴数据 Y一维数组,y 轴数据 Z一维数组,z 轴数据 color曲面表面的颜色 vmin / vmax规定数据界限 **kwargs可选项,其他关键字参数,可参见 Poly3DCollection import matplotlib.pyplot as pltimport numpy as npplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']# 获取 figure 画布并通过子图创建 Axes3D 对象fig = plt.figure()ax = fig.add_subplot(111, projection='3d')n_radii = 8n_angles = 36radii = np.linspace(0.125, 1.0, n_radii)angles = np.linspace(0, 2*np.pi, n_angles, endpoint=False)[..., np.newaxis]x = np.append(0, (radii*np.cos(angles)).flatten())y = np.append(0, (radii*np.sin(angles)).flatten())z = np.sin(-x*y)# 绘制3D三角曲面图并添加色条(长度0.8)trisurf = ax.plot_trisurf(x, y, z, cmap='rainbow')fig.colorbar(trisurf, shrink=0.8)# 设置标题、轴标签、图例,也可以直接使用 plt.title、plt.xlabel...ax.set_title('绘制 3D 三角曲面图示例', pad=15, fontsize='12')ax.set_xlabel('x 轴')ax.set_ylabel('y 轴')ax.set_zlabel('z 轴')plt.show() import numpy as npimport matplotlib.pyplot as pltimport matplotlib.tri as mtriplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']fig = plt.figure(figsize=(15, 6))# ============ 第一个示例图 ============ #ax = fig.add_subplot(1, 2, 1, projection='3d')u = np.linspace(0, 2.0 * np.pi, endpoint=True, num=50)v = np.linspace(-0.5, 0.5, endpoint=True, num=10)u, v = np.meshgrid(u, v)u, v = u.flatten(), v.flatten()x = (1 + 0.5 * v * np.cos(u / 2.0)) * np.cos(u)y = (1 + 0.5 * v * np.cos(u / 2.0)) * np.sin(u)z = 0.5 * v * np.sin(u / 2.0)tri = mtri.Triangulation(u, v)trisurf_1 = ax.plot_trisurf(x, y, z, triangles=tri.triangles, cmap='cool')fig.colorbar(trisurf_1, shrink=0.8)ax.set_zlim(-1, 1)ax.set_title('绘制 3D 三角曲面图示例一', pad=15, fontsize='12')ax.set_xlabel('x 轴')ax.set_ylabel('y 轴')ax.set_zlabel('z 轴')# ============ 第二个示例图 ============ #ax = fig.add_subplot(1, 2, 2, projection='3d')n_angles = 36n_radii = 8min_radius = 0.25radii = np.linspace(min_radius, 0.95, n_radii)angles = np.linspace(0, 2*np.pi, n_angles, endpoint=False)angles = np.repeat(angles[..., np.newaxis], n_radii, axis=1)angles[:, 1::2] += np.pi/n_anglesx = (radii*np.cos(angles)).flatten()y = (radii*np.sin(angles)).flatten()z = (np.cos(radii)*np.cos(3*angles)).flatten()triang = mtri.Triangulation(x, y)xmid = x[triang.triangles].mean(axis=1)ymid = y[triang.triangles].mean(axis=1)mask = xmid**2 + ymid**2 < min_radius**2triang.set_mask(mask)trisurf_2 = ax.plot_trisurf(triang, z, cmap='hsv')fig.colorbar(trisurf_2, shrink=0.8)ax.set_title('绘制 3D 三角曲面图示例二', pad=15, fontsize='12')ax.set_xlabel('x 轴')ax.set_ylabel('y 轴')ax.set_zlabel('z 轴')plt.show() 【12x00】将 2D 图像聚合到 3D 图像中:Axes3D.add_collection3d 基本方法:Axes3D.add_collection3d(col, zs=0, zdir='z') 参数描述 colPolyCollection / LineCollection / PatchCollection 对象 zs第 i 个多边形将出现在平面 y=zs[i] 上 zdir可选项,在 3D 轴上绘制 2D 数据时,数据必须以 xs,ys 的形式传递, 若此时将 zdir 设置为 ‘y’,数据将会被绘制到 x-z 轴平面上,默认为 ‘z’ 该函数一般用来向图形中添加 3D 集合对象,以下用一个示例来展示某个地区在不同年份和不同月份的降水量: import numpy as npimport matplotlib.pyplot as pltfrom matplotlib.collections import PolyCollectionplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']fig = plt.figure()ax = fig.gca(projection='3d')np.random.seed(59)month = np.arange(0, 13)years = [2017, 2018, 2019, 2020]precipitation = []for year in years: value = np.random.rand(len(month)) * 300 value[0], value[-1] = 0, 0 precipitation.append(list(zip(month, value)))poly = PolyCollection(precipitation, facecolors=['r', 'g', 'b', 'y'], alpha=.6)ax.add_collection3d(poly, zs=years, zdir='y')ax.set_title('2D 图像聚合到 3D 图像示例', pad=15, fontsize='12')ax.set_xlabel('月份')ax.set_ylabel('年份')ax.set_zlabel('降水量')ax.set_xlim3d(0, 12)ax.set_ylim3d(2016, 2021)ax.set_zlim3d(0, 300)plt.show() 此外,该方法也常被用于绘制 3D 多边形图,即多边体,示例如下: import matplotlib.pyplot as pltfrom mpl_toolkits.mplot3d.art3d import Poly3DCollection, Line3DCollectionplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']fig = plt.figure()ax = fig.gca(projection='3d')# 六面体顶点和面verts = [(0, 0, 0), (0, 1, 0), (1, 1, 0), (1, 0, 0), (0, 0, 1), (0, 1, 1), (1, 1, 1), (1, 0, 1)]faces = [[0, 1, 2, 3], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [0, 3, 7, 4]]# 获取每个面的顶点poly3d = [[verts[vert_id] for vert_id in face] for face in faces]# 绘制顶点x, y, z = zip(*verts)ax.scatter(x, y, z)# 绘制多边形面ax.add_collection3d(Poly3DCollection(poly3d, facecolors='w', linewidths=1, alpha=0.5))# 绘制多边形的边ax.add_collection3d(Line3DCollection(poly3d, colors='k', linewidths=0.5, linestyles=':'))# 设置图像标题、坐标标签以及范围ax.set_title('绘制多边体示例', pad=15, fontsize='12')ax.set_xlabel('X 轴')ax.set_ylabel('Y 轴')ax.set_zlabel('Z 轴')ax.set_xlim3d(-0.5, 1.5)ax.set_ylim3d(-0.5, 1.5)ax.set_zlim3d(-0.5, 1.5)plt.show() 【13x00】3D 图添加文本描述:Axes3D.text 基本方法:Axes3D.text(x, y, z, s[, zdir=None, **kwargs]) 参数描述 x, y, z文本位置的 x、y、z 轴坐标 s要添加的文本 zdir可选项,若将 zdir 设置为 ‘y’,文本将会被投影到 x-z 轴平面上,默认为 None **kwargs其他关键字参数,参见 matplotlib.text import matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']# 依次获取画布和绘图区并创建 Axes3D 对象fig = plt.figure()ax = fig.gca(projection='3d')# Demo 1: zdir 参数用法zdirs = (None, 'x', 'y', 'z', (1, 1, 0), (1, 1, 1))xs = (1, 4, 4, 9, 4, 1)ys = (2, 5, 8, 10, 1, 2)zs = (10, 3, 8, 9, 1, 8)for zdir, x, y, z in zip(zdirs, xs, ys, zs): label = '(%d, %d, %d), dir=%s' % (x, y, z, zdir) ax.text(x, y, z, label, zdir)# Demo 2:设置颜色ax.text(9, 0, 0, "red", color='red')# Demo 3: text2D,位置(0,0)为左下角,(1,1)为右上角。ax.text2D(0.05, 0.95, "2D Text", transform=ax.transAxes)# 设置坐标轴界限和标签ax.set_xlim(0, 10)ax.set_ylim(0, 10)ax.set_zlim(0, 10)ax.set_xlabel('X 轴')ax.set_ylabel('Y 轴')ax.set_zlabel('Z 轴')plt.show() 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106558131未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【1x00】了解极坐标 【2x00】基本方法 matplotlib.pyplot.polar() 【3x00】绘制极坐标 【4x00】绘制雷达图 【4x01】理解 numpy.concatenate() 【4x02】理解 pyplot.thetagrids() 【4x03】绘制雷达图 【5x00】高级用法:绘制极坐标散点图 【5x01】方法一:pyplot.scatter() 与 pyplot.polar() 【5x02】方法二:pyplot.scatter() 与 pyplot.subplot() 【5x03】方法三:pyplot.scatter() 与 pyplot.axes() 【6x00】高级用法:绘制极坐标柱状图 【6x01】方法一:pyplot.bar() 与 pyplot.polar() 【6x02】方法二:pyplot.bar() 与 pyplot.subplot() 【6x03】方法三:pyplot.bar() 与 pyplot.axes() Matplotlib 系列文章: Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件 Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性 Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性 Python 数据分析三剑客之 Matplotlib(四):线性图的绘制 Python 数据分析三剑客之 Matplotlib(五):散点图的绘制 Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制 Python 数据分析三剑客之 Matplotlib(七):饼状图的绘制 Python 数据分析三剑客之 Matplotlib(八):等高线 / 等值线图的绘制 Python 数据分析三剑客之 Matplotlib(九):极区图 / 极坐标图 / 雷达图的绘制 Python 数据分析三剑客之 Matplotlib(十):3D 图的绘制 Python 数据分析三剑客之 Matplotlib(十一):最热门最常用的 50 个图表【译文】 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106162412未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【1x00】了解极坐标 参考百度百科:极坐标,属于二维坐标系统,创始人是牛顿,主要应用于数学领域。极坐标是指在平面内取一个定点 O,叫极点,引一条射线 Ox,叫做极轴,再选定一个长度单位和角度的正方向(通常取逆时针方向)。对于平面内任何一点 M,用 ρ 表示线段 OM 的长度(有时也用 r 表示),θ 表示从 Ox 到 OM 的角度,ρ 叫做点 M 的极径,θ 叫做点 M 的极角,有序数对 (ρ,θ) 就叫点 M 的极坐标,这样建立的坐标系叫做极坐标系。通常情况下,M 的极径坐标单位为 1(长度单位),极角坐标单位为 rad(或°)。 【2x00】基本方法 matplotlib.pyplot.polar() matplotlib.pyplot.polar() 方法可用于绘制极坐标图。 基本语法:polar(theta, r, **kwargs) theta:点的角坐标,以弧度单位传入参数; r:点的半径坐标; **kwargs:可选项,其他 Line2D 属性,常用属性见表一。 拓展:数学上通常是用弧度而非角度,弧度单位缩写为 rad,2π rad = 360°,1° ≈ 0.0174533 rad,1 rad ≈ 57.29578°。 角度转换为弧度公式:弧度 = 角度 ÷ 180 × π 弧度转换为角度公式:角度 = 弧度 × 180 ÷ π 表一:Line2D 部分属性,完整属性参见官方文档: https://matplotlib.org/api/_as_gen/matplotlib.lines.Line2D.html 属性描述 alpha线条透明度,float 类型,取值范围:[0, 1],默认为 1.0,即不透明 antialiased / aa是否使用抗锯齿渲染,默认为 True color / c线条颜色,支持英文颜色名称及其简写、十六进制颜色码等,更多颜色示例参见官网 Color Demo fillstyle点的填充样式,'full'、'left'、'right'、'bottom'、'top'、'none' label图例,具体参数参见: 《Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性》 linestyle / ls连接的线条样式:'-' or 'solid', '--' or 'dashed', '-.' or 'dashdot' ':' or 'dotted', 'none' or ' ' or '' linewidth / lw连接的线条宽度,float 类型,默认 0.8 marker标记样式,具体样式参见表二 markeredgecolor / mecmarker 标记的边缘颜色 markeredgewidth / mewmarker 标记的边缘宽度 markerfacecolor / mfcmarker 标记的颜色 markerfacecoloralt / mfcaltmarker 标记的备用颜色 markersize / msmarker 标记的大小 表二:marker 标记的样式,官方文档: https://matplotlib.org/api/markers_api.html 标记描述 "."点 ","像素点 "o"圆圈 "v"倒三角 "^"正三角 "<"左三角 ">"右三角 "1"倒三叉星 "2"正三叉星(类似奔驰车标形状) "3"左三叉星 "4"右三叉星 "8"八边形 "s"正方形 "p"五边形 "P"填充的加号(粗加号) "+"加号 "*"星形 "h"六边形(底部是角) "H"六边形(底部是边) "x"x 号 "X"填充的 x 号(粗 x 号) "D"粗菱形(对角线相等) "d"细菱形(对角线不等) `""` "_"水平线 0水平线靠左 1水平线靠右 2垂直线靠上 3垂直线靠下 4左三角(比 "<" 更细) 5右三角(比 ">" 更细) 6正三角(比 "^" 更细) 7倒三角(比 "v" 更细) 8左三角(比 "<" 更细,靠左显示) 9右三角(比 ">" 更细,靠右显示) 10正三角(比 "^" 更细,靠上显示) 11倒三角(比 "v" 更细,靠下显示) "None" / " " / ""无样式 '$...$'支持 LaTeX 数学公式,表达式用美元符号包围起来 【3x00】绘制极坐标 import numpy as npimport matplotlib.pyplot as plt# 设置中文显示plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']# 设置画布大小plt.figure(figsize=(8.0, 6.0))# 设置三个数据,theta 为点位置的弧度参数,r 为点的半径坐标theta1 = np.array([1.25*np.pi, np.pi/2, 0])theta2 = np.array([-np.pi/6, -np.pi/2, 0, np.pi/2, np.pi])theta3 = np.arange(0., 2*np.pi, 0.5)r1 = np.array([4, 2, 3])r2 = np.array([5, 2, 4, 5, 3])r3 = np.random.randint(0, 5, 13)# 绘制第一个极坐标图,点的标记样式为细菱形,大小为8,点之间的连接线条样式为:plt.polar(theta1, r1, marker='d', ms=8, ls=':', label='数据一')# 填充第一个极坐标图,填充颜色为蓝色,透明度0.3plt.fill(theta1, r1, color='b', alpha=0.3)# 绘制第二个极坐标图,marker、linestyle、color 三个参数可以组合以字符串形式传入plt.polar(theta2, r2, '*-g', ms=10, label='数据二')# 绘制第三个极坐标图,设置 linestyle 为 none,即点与点之间不相连plt.polar(theta3, r3, marker='o', ls='none', ms=8, color='r', label='数据三')plt.title('matplotlib.pyplot.polar 用法示例', pad=25, fontsize=15)plt.legend(bbox_to_anchor=(1.3, 1))plt.show() 示例中 figure、title、legend 等其他方法的解释可参见我的系列文章: 《Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件》 《Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性》 《Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性》 绘制结果如下图: 【4x00】绘制雷达图 雷达图是以从同一点开始的轴上表示的三个或更多个定量变量的二维图表的形式显示多变量数据的图形方法。轴的相对位置和角度通常是无信息的。 雷达图也称为网络图,蜘蛛图,星图,蜘蛛网图,不规则多边形,极坐标图或 Kiviat 图。它相当于平行坐标图,轴径向排列。 在前面的示例中,使用了 matplotlib.pyplot.fill() 方法对三个极坐标点围成的图形进行了填充,这就有点儿接近于雷达图了,仔细观察前面的示例,在填充时第一个点和最后一个点之间没有连线,即没有闭合,而更精确的雷达图应该是闭合的,且外围应该是文字描述而不是度数。 在绘制雷达图之前需要提前了解一些函数。这些函数可以帮助我们实现闭合、自定义文字标签等。 【4x01】理解 numpy.concatenate() numpy.concatenate() 方法用于沿现有轴连接一系列数组,我们可以利用此方法来实现闭合操作。 基本语法:numpy.concatenate((a1, a2, ...)[, axis=0, out=None]) 参数描述 a1, a2, …要连接的数组,必须拥有相同的维度 axis沿指定轴连接数组,可选项,如果 axis 为 None,则数组在使用前被展平,默认值为 0 out用于接收连接后的数组,可选项 用法示例: import numpy as npa = np.array([1, 2, 3, 4])b = np.array(['a', 'b', 'c', 'd'])print(np.concatenate((a, b))) 输出结果如下: ['1' '2' '3' '4' 'a' 'b' 'c' 'd'] 如果要实现数组的闭合,则可以传入原数组和一个新数组,其中新数组中的元素为原数组中的第一个元素,示例如下: import numpy as npa = np.array([1, 2, 3, 4])print(np.concatenate((a, [a[0]]))) 输出结果如下: [1 2 3 4 1] 【4x02】理解 pyplot.thetagrids() matplotlib.pyplot.thetagrids() 方法用于获取并设置当前极区图上的极轴。 基本语法:matplotlib.pyplot.thetagrids(angles, labels=None, fmt=None, **kwargs) 参数描述 angles网格线的角度,浮点数、度数组成的元组 labels每个极轴要使用的文本标签,字符串组成的元组 fmt格式化 angles 参数,如 '%1.2f' 保留两位小数,注意,将使用以弧度为单位的角度 **kwargs其他关键字参数,参见官方文档 应用举例: import matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']plt.polar()angles = range(0, 360, 45)labels = ('东', '东北', '北', '西北', '西', '西南', '南', '东南')plt.thetagrids(angles, labels)plt.title('matplotlib.pyplot.thetagrids() 用法示例', pad=15)plt.show() 【4x03】绘制雷达图 numpy.concatenate() 方法能够解决闭合问题,matplotlib.pyplot.thetagrids() 能够解决自定义极轴和极轴的文本标记问题,因此就可以绘制一个标准的雷达图了。示例如下: import numpy as npimport matplotlib.pyplot as plt# 设置中文显示、画布大小plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']plt.figure(figsize=(8.0, 6.0))# 分割圆并执行闭合操作(0-2π之间返回间隔均匀的6个弧度:π/3、2π/3、π、4π/3、5π/3、2π)theta = np.linspace(0, 2*np.pi, 6, endpoint=False)theta = np.concatenate((theta, [theta[0]]))# 设置两组数据并执行闭合操作data1 = np.array([9, 4, 3, 5, 2, 8])data2 = np.array([3, 6, 9, 6, 3, 2])data1 = np.concatenate((data1, [data1[0]]))data2 = np.concatenate((data2, [data2[0]]))# 绘制并填充两组数据plt.polar(theta, data1, 'bo-', label='小王')plt.polar(theta, data2, 'ro:', label='小张')plt.fill(theta, data1, color='b', alpha=0.3)plt.fill(theta, data2, color='r', alpha=0.3)# 将六个弧度(π/3、2π/3、π、4π/3、5π/3、2π)转换成角度,并分别设置标签labels = np.array(['Python', 'Golang', 'Java', 'C++', 'PHP', 'JavaScript'])plt.thetagrids(theta * 180/np.pi, labels)# 设置刻度范围、标题、图例plt.ylim(0, 10)plt.title('编程语言掌握程度')plt.legend(bbox_to_anchor=(1.3, 1))plt.show() 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106162412未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【5x00】高级用法:绘制极坐标散点图 matplotlib.pyplot.polar() 方法可以实现极坐标散点图,但仅用这一个函数的话实现的样式效果并不多,以下介绍另外三种绘制极坐标散点图的方法: matplotlib.pyplot.polar() 和 matplotlib.pyplot.scatter() 结合,前者绘制极坐标图,后者在极坐标图上绘制散点图; matplotlib.pyplot.subplot() 和 matplotlib.pyplot.scatter() 结合,前者添加子图,其中指定 projection='polar' 即为极坐标图, 后者在极坐标图上绘制散点图; matplotlib.pyplot.axes() 与 matplotlib.pyplot.scatter() 结合,前者设置绘图区参数,其中指定 projection='polar' 或 polar=True 即为极坐标图, 后者在极坐标图上绘制散点图。 【5x01】方法一:pyplot.scatter() 与 pyplot.polar() 以下用到的 matplotlib.pyplot.scatter() 函数,各参数含义以及支持的其他参数可以参见前文: 《Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性》 《Python 数据分析三剑客之 Matplotlib(五):散点图的绘制》 import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']N = 50r = 2 * np.random.rand(N)theta = 2 * np.pi * np.random.rand(N)size = 200 * r ** 2colors = N * np.random.rand(N)plt.polar()plt.scatter(theta, r, s=size, c=colors, alpha=0.8)plt.title('极坐标散点图示例一', pad=15)plt.show() 【5x02】方法二:pyplot.scatter() 与 pyplot.subplot() matplotlib.pyplot.subplot() 方法用于添加子图,如果想要子图为极坐标图,则需要指定 projection 参数为 polar,有关此函数的具体介绍可参见官方文档。其他函数的参数解释可参考前文: 《Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性》 《Python 数据分析三剑客之 Matplotlib(五):散点图的绘制》 import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']N = 50r = 2 * np.random.rand(N)theta = 2 * np.pi * np.random.rand(N)size = 200 * r ** 2colors = N * np.random.rand(N)# 一行一列第一个子图plt.subplot(111, projection='polar')plt.scatter(theta, r, s=size, c=colors, alpha=0.8)plt.title('极坐标散点图示例二', pad=15)plt.show() 【5x03】方法三:pyplot.scatter() 与 pyplot.axes() axes 为 Matplotlib 图像中的绘图区,matplotlib.pyplot.axes() 方法可以对绘图区进行设置,同样的也可以设置 projection 参数为 polar 来实现极坐标图,设置 polar=True 也行。示例中其他函数的参数解释可参考前文: 《Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件》 《Python 数据分析三剑客之 Matplotlib(五):散点图的绘制》 import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']N = 50r = 2 * np.random.rand(N)theta = 2 * np.pi * np.random.rand(N)size = 200 * r ** 2colors = N * np.random.rand(N)# plt.axes(polar=True)plt.axes(projection='polar')plt.scatter(theta, r, s=size, c=colors, alpha=0.8)plt.title('极坐标散点图示例三', pad=15)plt.show() 【6x00】高级用法:绘制极坐标柱状图 和极坐标散点图的绘制类似,matplotlib.pyplot.polar() 方法可以实现极坐标图,但仅用这一个函数的话实现的样式效果并不多,以下介绍另外三种绘制极坐标柱状图的方法: matplotlib.pyplot.polar() 和 matplotlib.pyplot.bar() 结合,前者绘制极坐标图,后者在极坐标图上绘制柱状图; matplotlib.pyplot.subplot() 和 matplotlib.pyplot.bar() 结合,前者添加子图,其中指定 projection='polar' 即为极坐标图, 后者在极坐标图上绘制柱状图; matplotlib.pyplot.axes() 与 matplotlib.pyplot.bar() 结合,前者设置绘图区参数,其中指定 projection='polar' 或 polar=True 即为极坐标图, 后者在极坐标图上绘制柱状图。 【6x01】方法一:pyplot.bar() 与 pyplot.polar() 以下用到的 matplotlib.pyplot.bar() 函数,各参数含义以及支持的其他参数可以参见前文: 《Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性》 《Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制》 import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']r = np.random.rand(8)theta = np.arange(0, 2 * np.pi, 2 * np.pi / 8)colors = np.array(['#4bb2c5', '#c5b47f', '#EAA228', '#579575', '#839557', '#958c12', '#953579', '#4b5de4'])plt.polar()plt.bar(theta, r, color=colors, alpha=0.8)plt.title('极坐标柱状图示例一', pad=15)plt.show() 【6x02】方法二:pyplot.bar() 与 pyplot.subplot() matplotlib.pyplot.subplot() 方法用于添加子图,如果想要子图为极坐标图,则需要指定 projection 参数为 polar,有关此函数的具体介绍可参见官方文档。其他函数的参数解释可参考前文: 《Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性》 《Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制》 import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']r = np.random.rand(8)theta = np.arange(0, 2 * np.pi, 2 * np.pi / 8)colors = np.array(['#4bb2c5', '#c5b47f', '#EAA228', '#579575', '#839557', '#958c12', '#953579', '#4b5de4'])plt.subplot(111, projection='polar')plt.bar(theta, r, color=colors, alpha=0.8)plt.title('极坐标柱状图示例二', pad=15)plt.show() 【6x03】方法三:pyplot.bar() 与 pyplot.axes() axes 为 Matplotlib 图像中的绘图区,matplotlib.pyplot.axes() 方法可以对绘图区进行设置,同样的也可以设置 projection 参数为 polar 来实现极坐标图,设置 polar=True 也行。示例中其他函数的参数解释可参考前文: 《Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件》 《Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制》 import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']r = np.random.rand(8)theta = np.arange(0, 2 * np.pi, 2 * np.pi / 8)colors = np.array(['#4bb2c5', '#c5b47f', '#EAA228', '#579575', '#839557', '#958c12', '#953579', '#4b5de4'])# plt.axes(polar=True)plt.axes(projection='polar')plt.bar(theta, r, color=colors, alpha=0.8)plt.title('极坐标柱状图示例三', pad=15)plt.show() 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106162412未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【1x00】等高线概念 【2x00】理解 numpy.meshgrid() 【3x00】绘制方法 matplotlib.pyplot.contour() 【4x00】填充方法 matplotlib.pyplot.contourf() 【5x00】标记方法 matplotlib.pyplot.clabel() 【6x00】Colormap 取值 【7x00】简单示例 【8x00】添加标记 【9x00】轮廓线颜色和样式 【10x00】颜色填充 Matplotlib 系列文章: Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件 Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性 Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性 Python 数据分析三剑客之 Matplotlib(四):线性图的绘制 Python 数据分析三剑客之 Matplotlib(五):散点图的绘制 Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制 Python 数据分析三剑客之 Matplotlib(七):饼状图的绘制 Python 数据分析三剑客之 Matplotlib(八):等高线 / 等值线图的绘制 Python 数据分析三剑客之 Matplotlib(九):极区图 / 极坐标图 / 雷达图的绘制 Python 数据分析三剑客之 Matplotlib(十):3D 图的绘制 Python 数据分析三剑客之 Matplotlib(十一):最热门最常用的 50 个图表【译文】 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106066852未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【1x00】等高线概念 参考百度百科,等高线概念总结如下:等高线指的是地形图上高程相等的相邻各点所连成的闭合曲线。把地面上海拔高度相同的点连成的闭合曲线,并垂直投影到一个水平面上,并按比例缩绘在图纸上,就得到等高线。等高线也可以看作是不同海拔高度的水平面与实际地面的交线,所以等高线是闭合曲线。在等高线上标注的数字为该等高线的海拔。 位于同一等高线上的地面点,海拔高度相同。但海拔高度相同的点不一定位于同一条等高线上; 在同一幅图内,除了陡崖以外,不同高程的等高线不能相交; 在图廓内相邻等高线的高差一般是相同的,因此地面坡度与等高线之间的等高线平距成反比,等高线平距愈小,等高线排列越密,说明地面坡度越大;等高线平距愈大,等高线排列越稀,则说明地面坡度愈小; 等高线是一条闭合的曲线,如果不能在同一幅内闭合,则必在相邻或者其他图幅内闭合。 等高线经过山脊或山谷时改变方向,因此,山脊线或者山谷线应垂直于等高线转折点处的切线,即等高线与山脊线或者山谷线正交。 在 Matplotlib 等高线的绘制中,需要传递三个基本参数:某个点的 x、y 轴坐标以及其高度。 【2x00】理解 numpy.meshgrid() numpy.meshgrid() 方法用于生成网格点坐标矩阵。 import numpy as npa = np.array([1, 2, 3])b = np.array([7, 8, 9])res = np.meshgrid(a, b)print(res) 输出结果: [array([[1, 2, 3], [1, 2, 3], [1, 2, 3]]), array([[7, 7, 7], [8, 8, 8], [9, 9, 9]])] 给定两个数组,a[1, 2, 3] 和 b[7, 8, 9],a 作为 x 轴数据,b 作为 y 轴数据,那么一共可以绘制出 9 个点: (1,7)、(1,8)、(1,9)、(2,7)、(2,8)、(2,9)、(3,7)、(3,8)、(3,9),而 numpy.meshgrid() 方法就是起这样的作用,返回的两个二维数组,横坐标矩阵 a 中的每个元素,与纵坐标矩阵 b 中对应位置元素,共同构成一个点的完整坐标。 因为在 matplotlib.pyplot.contour() 等高线绘制函数中接收的是二维坐标信息,所以在绘制等高线图之前要将原数据经过 numpy.meshgrid() 方法处理,也可以自己构建类似于上述的二维数组。 【3x00】绘制方法 matplotlib.pyplot.contour() matplotlib.pyplot.contour() 方法可用于绘制等高线图。 基本语法:matplotlib.pyplot.contour(\*args, data=None, \*\*kwargs) 通用格式:matplotlib.pyplot.contour([X, Y,] Z, [levels], **kwargs) 基本参数: 参数描述 X, Y数组形式的点的 x 和 y 轴坐标,两者都必须是二维的,形状与 Z 相同 Z绘制轮廓的高度值,二维数组,每个元素是其对应点的高度 levels确定等高线的数目和位置,如果是整数 N,则使用 N 个数据间隔,即绘制 N+1 条等高线 如果是数组形式,则绘制指定的等高线。值必须按递增顺序排列 其他参数: 参数描述 colors等高线的颜色,颜色字符串或颜色序列 cmap等高线的颜色,字符串或者 Colormap 通常包含一系列的渐变色或其他颜色组合,取值参见【6x00】Colormap 取值 alpha透明度,介于0(透明)和1(不透明)之间 origin通过指定 Z[0,0] 的位置来确定 Z 的方向和确切位置,仅当未指定 X, Y 时才有意义 None:Z[0,0] 位于左下角的 X=0, Y=0 处 'lower':Z [0, 0] 位于左下角的 X = 0.5, Y = 0.5 处 'upper':Z[0,0] 位于左上角的 X=N+0.5, Y=0.5 处 'image':使用 rcParams[“image.origin”] = 'upper'的值 antialiased是否启用抗锯齿渲染,默认 True linewidths等高线的线宽,如果是数字,则所有等高线都将使用此线宽 如果是序列,则将按指定的顺序以升序打印线宽 默认为 rcParams[“lines.linewidth”] = 1.5 linestyles等高线的样式,如果线条颜色为单色,则负等高线默认为虚线 '-' or 'solid', '--' or 'dashed', '-.' or 'dashdot' ':' or 'dotted', 'none' or ' ' or '' 【4x00】填充方法 matplotlib.pyplot.contourf() matplotlib.pyplot.contourf() 方法与 matplotlib.pyplot.contour() 的区别在于:contourf() 会对等高线间的区域进行颜色填充(filled contours)。除此之外两者的函数签名和返回值都相同。 基本语法:matplotlib.pyplot.contourf(\*args, data=None, \*\*kwargs) 通用格式:matplotlib.pyplot.contour([X, Y,] Z, [levels], **kwargs) 基本参数: 参数描述 X, Y数组形式的点的 x 和 y 轴坐标,两者都必须是二维的,形状与 Z 相同 Z绘制轮廓的高度值,二维数组,每个元素是其对应点的高度 levels确定等高线的数目和位置,如果是整数 N,则使用 N 个数据间隔,即绘制 N+1 条等高线 如果是数组形式,则绘制指定的等高线。值必须按递增顺序排列 其他参数: 参数描述 colors等高线的填充颜色,颜色字符串或颜色序列 cmap等高线的填充颜色,字符串或者 Colormap 通常包含一系列的渐变色或其他颜色组合,取值参见【6x00】Colormap 取值 alpha透明度,介于0(透明)和1(不透明)之间 origin通过指定 Z[0,0] 的位置来确定 Z 的方向和确切位置,仅当未指定 X, Y 时才有意义 None:Z[0,0] 位于左下角的 X=0, Y=0 处 'lower':Z [0, 0] 位于左下角的 X = 0.5, Y = 0.5 处 'upper':Z[0,0] 位于左上角的 X=N+0.5, Y=0.5 处 'image':使用 rcParams[“image.origin”] = 'upper'的值 antialiased是否启用抗锯齿渲染,默认 True linewidths等高线的线宽,如果是数字,则所有等高线都将使用此线宽 如果是序列,则将按指定的顺序以升序打印线宽 默认为 rcParams[“lines.linewidth”] = 1.5 linestyles等高线的样式,如果线条颜色为单色,则负等高线默认为虚线 '-' or 'solid', '--' or 'dashed', '-.' or 'dashdot' ':' or 'dotted', 'none' or ' ' or '' 【5x00】标记方法 matplotlib.pyplot.clabel() matplotlib.pyplot.clabel(CS, \*args, \*\*kwargs) 方法可用于标记等高线图。 参数描述 CSContourSet(等高线集)对象,即 pyplot.contour() 返回的对象 levels需要标记的等高线集,数组类型,如果未指定则默认标记所有等高线 fontsize标记的字体大小,可选项: 'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large' colors标记的颜色,颜色字符串或颜色序列 inline是否在标签位置移除轮廓显示,bool 类型,默认 True inline_spacing标签位置移除轮廓的宽度,float 类型,默认为 5 fmt标签的格式字符串。str 或 dict 类型,默认值为 %1.3f rightside_up是否将标签旋转始终与水平面成正负90度,bool 类型,默认 True use_clabeltext默认为 False,如果为 True,则使用 ClabelText 类(而不是 Text)创建标签 ClabelText 在绘图期间重新计算文本的旋转角度,如果轴的角度发生变化,则可以使用此功能 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106066852未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【6x00】Colormap 取值 matplotlib.pyplot.contour() 和 matplotlib.pyplot.contourf() 中 cmap 参数用于设置等高线的颜色,取值通常为 Colormap 中的值,通常包含一系列的渐变色或其他颜色组合。具体参加下图。 官方文档:https://matplotlib.org/tutorials/colors/colormaps.html 【7x00】简单示例 import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']x = np.arange(-2.0, 2.0, 0.01)y = np.arange(-2.0, 2.0, 0.01)m, n = np.meshgrid(x, y) # 生成网格点坐标矩阵# 指定一个函数用于计算每个点的高度,也可以直接使用二维数组储存每个点的高度def f(a, b): return (1 - b ** 5 + a ** 5) * np.exp(-a ** 2 - b ** 2)# 绘制等高线图,8 个数据间隔,颜色为黑色plt.contour(m, n, f(m, n), 8, colors='k')plt.title('等高线图简单示例')plt.xlabel('x axis label')plt.ylabel('y axis label')plt.show() 【8x00】添加标记 matplotlib.pyplot.clabel() 方法用于给等高线添加标记。 import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']x = np.arange(-2.0, 2.0, 0.01)y = np.arange(-2.0, 2.0, 0.01)m, n = np.meshgrid(x, y) # 生成网格点坐标矩阵# 指定一个函数用于计算每个点的高度,也可以直接使用二维数组储存每个点的高度def f(a, b): return (1 - b ** 5 + a ** 5) * np.exp(-a ** 2 - b ** 2)# 绘制等高线图,8 个数据间隔,颜色为黑色C = plt.contour(m, n, f(m, n), 8, colors='k')# 添加标记,标记处不显示轮廓线,颜色为黑红绿蓝四种,保留两位小数plt.clabel(C, inline=True, colors=['k', 'r', 'g', 'b'], fmt='%1.2f')plt.title('等高线图添加标记示例')plt.xlabel('x axis label')plt.ylabel('y axis label')plt.show() 【9x00】轮廓线颜色和样式 matplotlib.pyplot.contour() 方法中,colors 参数即可为等高线轮廓设置颜色,可以是单色,也可以是一个颜色列表,linestyles 参数可以设置轮廓线样式,注意,如果线条颜色为单色,则负等高线(高度值为负)默认为虚线。 import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']x = np.arange(-2.0, 2.0, 0.01)y = np.arange(-2.0, 2.0, 0.01)m, n = np.meshgrid(x, y) # 生成网格点坐标矩阵# 指定一个函数用于计算每个点的高度,也可以直接使用二维数组储存每个点的高度def f(a, b): return (1 - b ** 5 + a ** 5) * np.exp(-a ** 2 - b ** 2)colors = ['k', 'r', 'g', 'b']# 绘制等高线图,8 个数据间隔,颜色为黑色,线条样式为 --C = plt.contour(m, n, f(m, n), 8, colors=colors, linestyles='--')# 添加标记,标记处不显示轮廓线,颜色为黑红绿蓝四种,保留两位小数plt.clabel(C, inline=True, colors=colors, fmt='%1.2f')plt.title('等高线图设置颜色/样式示例')plt.xlabel('x axis label')plt.ylabel('y axis label')plt.show() 如果想启用渐变色,则可以设置 cmap,取值参见【6x00】Colormap 取值,colorbar() 方法可以显示颜色对照条。 import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']x = np.arange(-2.0, 2.0, 0.01)y = np.arange(-2.0, 2.0, 0.01)m, n = np.meshgrid(x, y) # 生成网格点坐标矩阵# 指定一个函数用于计算每个点的高度,也可以直接使用二维数组储存每个点的高度def f(a, b): return (1 - b ** 5 + a ** 5) * np.exp(-a ** 2 - b ** 2)# 绘制等高线图,8 个数据间隔,颜色为 plasmaC = plt.contour(m, n, f(m, n), 8, cmap='plasma')# 添加标记,标记处不显示轮廓线,颜色为黑色,保留两位小数plt.clabel(C, inline=True, colors='k', fmt='%1.2f')# 显示颜色条plt.colorbar()plt.title('等高线图设置渐变色示例')plt.xlabel('x axis label')plt.ylabel('y axis label')plt.show() 【10x00】颜色填充 matplotlib.pyplot.contourf() 方法用于对等高线之间的地方进行颜色填充。 import numpy as npimport matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']x = np.arange(-2.0, 2.0, 0.01)y = np.arange(-2.0, 2.0, 0.01)m, n = np.meshgrid(x, y) # 生成网格点坐标矩阵# 指定一个函数用于计算每个点的高度,也可以直接使用二维数组储存每个点的高度def f(a, b): return (1 - b ** 5 + a ** 5) * np.exp(-a ** 2 - b ** 2)# 绘制等高线图,8 个数据间隔,颜色为 plasmaplt.contourf(m, n, f(m, n), 8, cmap='plasma')C = plt.contour(m, n, f(m, n), 8, cmap='plasma')# 添加标记,标记处不显示轮廓线,颜色为黑色,保留两位小数plt.clabel(C, inline=True, colors='k', fmt='%1.2f')# 显示颜色条plt.colorbar()plt.title('等高线图颜色填充示例')plt.xlabel('x axis label')plt.ylabel('y axis label')plt.show() 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106066852未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
文章目录 【1x00】方法描述 【2x00】简单示例 【3x00】按角度调整扇形标签 【4x00】显示图例 【5x00】突出显示扇形块 【6x00】显示各扇区所占百分比 【7x00】旋转饼状图 【8x00】自定义每个扇形和文字属性 Matplotlib 系列文章: Python 数据分析三剑客之 Matplotlib(一):初识 Matplotlib 与其 matplotibrc 配置文件 Python 数据分析三剑客之 Matplotlib(二):文本描述 / 中文支持 / 画布 / 网格等基本图像属性 Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性 Python 数据分析三剑客之 Matplotlib(四):线性图的绘制 Python 数据分析三剑客之 Matplotlib(五):散点图的绘制 Python 数据分析三剑客之 Matplotlib(六):直方图 / 柱状图 / 条形图的绘制 Python 数据分析三剑客之 Matplotlib(七):饼状图的绘制 Python 数据分析三剑客之 Matplotlib(八):等高线 / 等值线图的绘制 Python 数据分析三剑客之 Matplotlib(九):极区图 / 极坐标图 / 雷达图的绘制 Python 数据分析三剑客之 Matplotlib(十):3D 图的绘制 Python 数据分析三剑客之 Matplotlib(十一):最热门最常用的 50 个图表【译文】 专栏: NumPy 专栏:https://itrhx.blog.csdn.net/category_9780393.html Pandas 专栏:https://itrhx.blog.csdn.net/category_9780397.html Matplotlib 专栏:https://itrhx.blog.csdn.net/category_9780418.html 推荐学习资料与网站: NumPy 官方中文网:https://www.numpy.org.cn/ Pandas 官方中文网:https://www.pypandas.cn/ Matplotlib 官方中文网:https://www.matplotlib.org.cn/ NumPy、Matplotlib、Pandas 速查表:https://github.com/TRHX/Python-quick-reference-table 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106025845未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【1x00】方法描述 matplotlib.pyplot.pie() 方法用于绘制饼状图。 基本语法: matplotlib.pyplot.pie( x[, explode=None, labels=None, colors=None, autopct=None, pctdistance=0.6, shadow=False, labeldistance=1.1, startangle=None, radius=None, counterclock=True, wedgeprops=None, textprops=None, center=(0, 0), frame=False, rotatelabels=False, \*, data=None] ) 参数描述 x每个扇形块的大小,数组形式,大小单位是比例 explode指定对应扇形块脱离饼图的半径大小,数组形式,其中元素个数应该是 len(x) labels每个扇形块上的文本标签,列表形式 labeldistance每个扇形块上的文本标签与扇形中心的距离,float 类型,默认 1.1 colors每个扇形块对应的颜色,数组形式 autopct用于计算每个扇形块所占比例,字符串或者函数类型 例如:autopct='%1.1f%%' 表示浮点数,保留一位小数,并添加百分比符号 pctdistance每个扇形块的中心与 autopct 生成的文本之间的距离,float 类型,默认 0.6 shadow是否为扇形添加阴影效果 startangle将饼图按照逆时针旋转指定的角度,float 类型 radius饼图的半径,如果是 None,则将被设置为 1,float 类型 counterclock是否按照逆时针对扇形图进行排列,bool 类型,默认 True wedgeprops传递给绘制每个扇形图对象的参数,字典形式,参数值参见 Wedge 例如:wedgeprops = {'linewidth': 3} 设置扇形边框线宽度为 3 textprops传递给文本对象的参数,字典形式 例如:textprops={'color': 'r', 'fontsize': 15} 设置文字为红色,大小为15 center饼图圆心在画布上是坐标,默认 (0, 0) frame是否显示 x, y 坐标轴外框,默认 False rotatelabels是否按照角度进行调整每块饼的 label 文本标签,默认 False 【2x00】简单示例 import matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']x = [10, 30, 45, 15]labels = ['Java', 'Golang', 'Python', 'C++']colors = ['red', 'yellow', 'blue', 'green']# 指定4个扇区所占比例以及扇区的颜色,扇区文本标签距离扇区中心1.1plt.pie(x, labels=labels, colors=colors, labeldistance=1.1)plt.title('饼状图简单示例')plt.show() 【3x00】按角度调整扇形标签 rotatelabels 属性可以设置是否按照角度调整每块饼的 label(标签)显示方式。 import matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']x = [10, 30, 45, 15]labels = ['Java', 'Go', 'Python', 'C++']colors = ['red', 'yellow', 'blue', 'green']# 指定4个扇区所占比例以及扇区的颜色,扇区文本标签距离扇区中心1.1,按角度调整 labelsplt.pie(x, labels=labels, colors=colors, labeldistance=1.1, rotatelabels=True)plt.title('饼状图按角度调整 labels 示例')plt.show() 【4x00】显示图例 与前面文章中绘制线性图、散点图、条形图一样,调用 matplotlib.pyplot.legend() 方法可绘制图例,该方法的参数解释参见前文《Python 数据分析三剑客之 Matplotlib(三):图例 / LaTeX / 刻度 / 子图 / 补丁等基本图像属性》 import matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']x = [10, 30, 45, 15]labels = ['Java', 'Go', 'Python', 'C++']colors = ['red', 'yellow', 'blue', 'green']plt.pie(x, labels=labels, colors=colors, labeldistance=1.1)plt.title('饼状图显示图例示例')plt.legend(bbox_to_anchor=(1, 1))plt.show() 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106025845未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃! 【5x00】突出显示扇形块 explode 参数可以实现突出显示某一块扇区,接收数组形式的参数,这个数组中的元素个数应该是 len(x),即和扇区块的数量相同。 import matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']x = [10, 30, 45, 15]labels = ['Java', 'Golang', 'Python', 'C++']colors = ['red', 'yellow', 'blue', 'green']# 指定第一个扇区块脱离饼图的半径大小为0.3,其它扇区不脱离plt.pie(x, labels=labels, colors=colors, labeldistance=1.1, explode=[0.3, 0, 0, 0])plt.title('饼状图突出显示扇形块示例')plt.legend(bbox_to_anchor=(1, 1))plt.show() 【6x00】显示各扇区所占百分比 autopct 参数可用于计算每个扇形块所占比例,接收字符串或者函数类型,例如:autopct='%1.1f%%' 表示浮点数,保留一位小数,并添加百分比符号。pctdistance 参数用于调整每个扇形块的中心与 autopct 生成的文本之间的距离,float 类型,默认 0.6。 import matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']x = [10, 30, 45, 15]labels = ['Java', 'Golang', 'Python', 'C++']colors = ['red', 'yellow', 'blue', 'green']plt.pie( x, # 每个扇形块所占比例 labels=labels, # 扇形块文本标签 colors=colors, # 扇形块颜色 labeldistance=1.1, # 扇形块标签距离中心的距离 explode=[0.3, 0, 0, 0], # 第一个扇形块突出显示 autopct='%1.1f%%', # 显示百分比,保留一位小数 pctdistance=0.5 # 百分比文本距离饼状图中心的距离)plt.title('饼状图显示各扇区所占百分比示例')plt.legend(bbox_to_anchor=(1, 1)) # 显示图例plt.show() 【7x00】旋转饼状图 startangle 参数可以选择饼状图,改变饼状图放置的角度。注意是按照逆时针旋转。 import matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']x = [10, 30, 45, 15]labels = ['Java', 'Golang', 'Python', 'C++']colors = ['red', 'yellow', 'blue', 'green']plt.pie( x, # 每个扇形块所占比例 labels=labels, # 扇形块文本标签 colors=colors, # 扇形块颜色 labeldistance=1.1, # 扇形块标签距离中心的距离 explode=[0.3, 0, 0, 0], # 第一个扇形块突出显示 autopct='%1.1f%%', # 显示百分比,保留一位小数 pctdistance=0.5, # 百分比文本距离饼状图中心的距离 startangle=-90 # 逆时针旋转-90°,即顺时针旋转90°)plt.title('饼状图旋转角度示例')plt.legend(bbox_to_anchor=(1, 1)) # 显示图例plt.show() 【8x00】自定义每个扇形和文字属性 wedgeprops 参数以字典形式为每个扇形添加自定义属性,例如:wedgeprops = {'linewidth': 3} 设置扇形边框线宽度为 3,更多其他参数值参见 Wedge; textprops 参数同样以字典形式为文本对象添加自定义属性,例如:textprops={'color': 'r', 'fontsize': 15} 设置文字为红色,大小为15,更多其他参数值参见 Text。 import matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']x = [10, 30, 45, 15]labels = ['Java', 'Golang', 'Python', 'C++']colors = ['red', 'yellow', 'blue', 'green']plt.pie( x, # 每个扇形块所占比例 labels=labels, # 扇形块文本标签 colors=colors, # 扇形块颜色 labeldistance=1.1, # 扇形块标签距离中心的距离 explode=[0.3, 0, 0, 0], # 第一个扇形块突出显示 autopct='%1.1f%%', # 显示百分比,保留一位小数 pctdistance=0.6, # 百分比文本距离饼状图中心的距离 shadow=True, # 显示阴影效果 wedgeprops={ # 为每个扇形添加属性 'width': 0.7, # 扇形宽度0.7 'edgecolor': '#98F5FF', # 扇形边缘线颜色 'linewidth': 3 # 扇形边缘线宽度 }, textprops={ # 为文字添加属性 'fontsize': 13, # 文字大小 'fontweight': 'bold', # 文字粗细 'color': 'k' # 文字颜色,黑色 })plt.title('饼状图自定义每个扇形和文字属性示例', fontweight='bold')plt.legend(bbox_to_anchor=(1, 1), borderpad=0.6) # 显示图例plt.show() 这里是一段物理防爬虫文本,请读者忽略。本文原创首发于 CSDN,作者 ITBOB。博客首页:https://itrhx.blog.csdn.net/本文链接:https://itrhx.blog.csdn.net/article/details/106025845未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!