pandas库
是Python中一个非常强大的数据处理库,提供了高效的数据分析方法和数据结构。它特别适用于处理具有关系型数据或带标签数据的情况,同时在时间序列分析方面也有着出色的表现。
pandas库广泛应用于数据挖掘和分析、金融和经济分析、科学和工程计算等领域。使用pandas库可以轻松地对数据进行筛选、排序、过滤、清理和变换等操作,并可以进行统计和汇总等分析,从而提高数据处理的效率和精度。pandas库还提供了许多常用的函数和方法,例如数据筛选和排序、数据合并和连接等。
Series和DataFrame
pandas库中最常用的数据类型是Series和DataFrame。Series是一维数组,拥有数据与索引;而DataFrame则是一个类似于表格的二维数据结构,其中储存了多个Series。例如:
>>> import pandas as pd
>>> df = pd.DataFrame({
'Title': ['流浪地球 2', '奥本海默', '俄罗斯方块', '银河护卫队 3', '我爱你!', '电锯惊魂 10', '灌篮高手', '梦的背后', '漫长的季节', '1923 第一季', '黑暗荣耀 第二季', '重启人生', '画江湖之不良人 6', '地球脉动 第三季'],
'Award': ['评分最高华语电影', '评分最高外语电影', '年度冷门佳片', '评分最高喜剧片', '评分最高爱情片', '评分最高恐怖片', '评分最高动画片', '评分最高纪录片', '评分最高华语剧集', '评分最高英美新剧', '评分最高韩国剧集', '评分最高日本剧集', '评分最高动画剧集', '评分最高纪录剧集'],
'Score': [9.5, 8.8, 8.0, 8.4, 7.9, 7.4, 8.9, 9.0, 9.4, 9.3, 9.0, 9.3, 9.4, 9.8]}
)
>>> df
Title Award Score
0 流浪地球 2 评分最高华语电影 9.5
1 奥本海默 评分最高外语电影 8.8
2 俄罗斯方块 年度冷门佳片 8.0
3 银河护卫队 3 评分最高喜剧片 8.4
4 我爱你! 评分最高爱情片 7.9
5 电锯惊魂 10 评分最高恐怖片 7.4
6 灌篮高手 评分最高动画片 8.9
7 梦的背后 评分最高纪录片 9.0
8 漫长的季节 评分最高华语剧集 9.4
9 1923 第一季 评分最高英美新剧 9.3
10 黑暗荣耀 第二季 评分最高韩国剧集 9.0
11 重启人生 评分最高日本剧集 9.3
12 画江湖之不良人 6 评分最高动画剧集 9.4
13 地球脉动 第三季 评分最高纪录剧集 9.8
nlargest和nsmallest
本篇就简单说说pandas数据筛选和排序中的nlargest / nsmallest两个函数的用法:
DataFrame.nlargest(n, columns, keep='first')
Series.nlargest(n, keep='first')
DataFrame.nsmallest(n, columns, keep='first')
Series.nsmallest(n, keep='first')
n是一个整数,表示要返回的行数或值数。
columns是一个标签或标签列表,表示要按照哪些列进行排序。只适用于DataFrame,不适用于Series。
keep是一个字符串,表示当有相同值的时候,如何处理。可以取以下三个值之一:
'first':保留第一个出现的行或值。
'last':保留最后一个出现的行或值。
'all':保留所有出现的行或值。
nlargest函数会返回一个新的DataFrame或Series,包含原数据中最大的n个值,按照降序排列。如果指定了多个列,那么会按照列的顺序依次进行排序。如果原数据中的值不是数值类型,那么会抛出TypeError异常。nsmallest函数则按照升序排列,另外如使用参数 keep='all',会导致返回的结果数会超过第一个参数n的值。
用法示例
>>> df.nlargest(3, 'Score', keep='first')
Title Award Score
13 地球脉动 第三季 评分最高纪录剧集 9.8
0 流浪地球 2 评分最高华语电影 9.5
8 漫长的季节 评分最高华语剧集 9.4
>>> df.nlargest(3, 'Score', keep='last')
Title Award Score
13 地球脉动 第三季 评分最高纪录剧集 9.8
0 流浪地球 2 评分最高华语电影 9.5
12 画江湖之不良人 6 评分最高动画剧集 9.4
>>> df.nlargest(3, 'Score')
Title Award Score
13 地球脉动 第三季 评分最高纪录剧集 9.8
0 流浪地球 2 评分最高华语电影 9.5
8 漫长的季节 评分最高华语剧集 9.4
>>> df.nlargest(3, 'Score', keep='all')
Title Award Score
13 地球脉动 第三季 评分最高纪录剧集 9.8
0 流浪地球 2 评分最高华语电影 9.5
8 漫长的季节 评分最高华语剧集 9.4
12 画江湖之不良人 6 评分最高动画剧集 9.4
>>> df.nsmallest(3, 'Score')
Title Award Score
5 电锯惊魂 10 评分最高恐怖片 7.4
4 我爱你! 评分最高爱情片 7.9
2 俄罗斯方块 年度冷门佳片 8.0
代替方法
df.sort_values()加切片也能实现nlargest和nsmallest的基本功能:
>>> df.sort_values('Score')[-3:][::-1]
Title Award Score
13 地球脉动 第三季 评分最高纪录剧集 9.8
0 流浪地球 2 评分最高华语电影 9.5
12 画江湖之不良人 6 评分最高动画剧集 9.4
>>> df.sort_values('Score')[:3]
Title Award Score
5 电锯惊魂 10 评分最高恐怖片 7.4
4 我爱你! 评分最高爱情片 7.9
2 俄罗斯方块 年度冷门佳片 8.0
手动实现
假如我们不使用pandas,只用python基础数据类型dict()来实现这些功能:
>>> dic = {
'Title': ['流浪地球 2', '奥本海默', '俄罗斯方块', '银河护卫队 3', '我爱你!', '电锯惊魂 10', '灌篮高手', '梦的背后', '漫长的季节', '1923 第一季', '黑暗荣耀 第二季', '重启人生', '画江湖之不良人 6', '地球脉动 第三季'],
'Award': ['评分最高华语电影', '评分最高外语电影', '年度冷门佳片', '评分最高喜剧片', '评分最高爱情片', '评分最高恐怖片', '评分最高动画片', '评分最高纪录片', '评分最高华语剧集', '评分最高英美新剧', '评分最高韩国剧集', '评分最高日本剧集', '评分最高动画剧集', '评分最高纪录剧集'],
'Score': [9.5, 8.8, 8.0, 8.4, 7.9, 7.4, 8.9, 9.0, 9.4, 9.3, 9.0, 9.3, 9.4, 9.8]}
>>> dic['Title']
['流浪地球 2', '奥本海默', '俄罗斯方块', '银河护卫队 3', '我爱你!', '电锯惊魂 10', '灌篮高手', '梦的背后', '漫长的季节', '1923 第一季', '黑暗荣耀 第二季', '重启人生', '画江湖之不良人 6', '地球脉动 第三季']
>>> dic['Score']
[9.5, 8.8, 8.0, 8.4, 7.9, 7.4, 8.9, 9.0, 9.4, 9.3, 9.0, 9.3, 9.4, 9.8]
使用内置函数sorted, zip一行代码就能实现:
>>> sorted(zip(dic['Title'],dic['Award'],dic['Score']),key=lambda x:x[-1])[-3:][::-1]
[('地球脉动 第三季', '评分最高纪录剧集', 9.8), ('流浪地球 2', '评分最高华语电影', 9.5), ('画江湖之不良人 6', '评分最高动画剧集', 9.4)]
>>> sorted(zip(dic['Title'],dic['Award'],dic['Score']),key=lambda x:x[-1])[:3]
[('电锯惊魂 10', '评分最高恐怖片', 7.4), ('我爱你!', '评分最高爱情片', 7.9), ('俄罗斯方块', '年度冷门佳片', 8.0)]
如果也想实现参数keep=last和all,那就稍微复杂些,你可以试试如何实现?
模拟代码
class DataFrame: def __init__(self, dic): self.dic = dic def nlargest(self, n, Column, keep='first'): if n<=0: return [] if Column not in self.dic: raise KeyError(f'{Column}') if not all([isinstance(i,int) or isinstance(i,float) for i in self.dic[Column]]): raise TypeError(f"Column '{Column}' has dtype object, cannot use method 'nlargest' with this dtype") lst = [self.dic[i] for i in self.dic.keys()] idx = list(self.dic.keys()).index(Column) tmp = sorted(zip(*lst) ,key=lambda x:x[idx],reverse=True) res = tmp[:n] num = tmp[n-1][idx] if keep=='first': pass elif keep=='last': for t in tmp[n:]: if num==t[idx]: res[-1]=t else: break elif keep=='all': for t in tmp[n:]: if num==t[idx]: res.append(t) else: break else: raise ValueError('keep must be either "first", "last" or "all"') return res dic = { 'Title': ['流浪地球 2', '奥本海默', '俄罗斯方块', '银河护卫队 3', '我爱你!', '电锯惊魂 10', '灌篮高手', '梦的背后', '漫长的季节', '1923 第一季', '黑暗荣耀 第二季', '重启人生', '画江湖之不良人 6', '地球脉动 第三季'], 'Award': ['评分最高华语电影', '评分最高外语电影', '年度冷门佳片', '评分最高喜剧片', '评分最高爱情片', '评分最高恐怖片', '评分最高动画片', '评分最高纪录片', '评分最高华语剧集', '评分最高英美新剧', '评分最高韩国剧集', '评分最高日本剧集', '评分最高动画剧集', '评分最高纪录剧集'], 'Score': [9.5, 8.8, 8.0, 8.4, 7.9, 7.4, 9.0, 9.0, 9.4, 9.3, 9.0, 9.3, 9.4, 9.8], } df = DataFrame(dic) kp = 'first', 'last', 'all' print('3largest:') for k in kp: print(k+':') for n in df.nlargest(3, 'Score', keep=k): print(n) print('7largest:') for k in kp: print(k+':') for n in df.nlargest(7, 'Score', keep=k): print(n)
运行结果:
3largest:
first:
('地球脉动 第三季', '评分最高纪录剧集', 9.8)
('流浪地球 2', '评分最高华语电影', 9.5)
('漫长的季节', '评分最高华语剧集', 9.4)
last:
('地球脉动 第三季', '评分最高纪录剧集', 9.8)
('流浪地球 2', '评分最高华语电影', 9.5)
('画江湖之不良人 6', '评分最高动画剧集', 9.4)
all:
('地球脉动 第三季', '评分最高纪录剧集', 9.8)
('流浪地球 2', '评分最高华语电影', 9.5)
('漫长的季节', '评分最高华语剧集', 9.4)
('画江湖之不良人 6', '评分最高动画剧集', 9.4)
7largest:
first:
('地球脉动 第三季', '评分最高纪录剧集', 9.8)
('流浪地球 2', '评分最高华语电影', 9.5)
('漫长的季节', '评分最高华语剧集', 9.4)
('画江湖之不良人 6', '评分最高动画剧集', 9.4)
('1923 第一季', '评分最高英美新剧', 9.3)
('重启人生', '评分最高日本剧集', 9.3)
('灌篮高手', '评分最高动画片', 9.0)
last:
('地球脉动 第三季', '评分最高纪录剧集', 9.8)
('流浪地球 2', '评分最高华语电影', 9.5)
('漫长的季节', '评分最高华语剧集', 9.4)
('画江湖之不良人 6', '评分最高动画剧集', 9.4)
('1923 第一季', '评分最高英美新剧', 9.3)
('重启人生', '评分最高日本剧集', 9.3)
('黑暗荣耀 第二季', '评分最高韩国剧集', 9.0)
all:
('地球脉动 第三季', '评分最高纪录剧集', 9.8)
('流浪地球 2', '评分最高华语电影', 9.5)
('漫长的季节', '评分最高华语剧集', 9.4)
('画江湖之不良人 6', '评分最高动画剧集', 9.4)
('1923 第一季', '评分最高英美新剧', 9.3)
('重启人生', '评分最高日本剧集', 9.3)
('灌篮高手', '评分最高动画片', 9.0)
('梦的背后', '评分最高纪录片', 9.0)
('黑暗荣耀 第二季', '评分最高韩国剧集', 9.0)
加强升级
nlargest和nsmallest只差一个排序参数, 修改一下就得到通用方法__sort__(),使用reverse参数来调用nlargest和nsmallest;另外DataFrame类新增__repr__()方法,便于打印时调用。
class DataFrame: def __init__(self, dic): self.__dic = dic self.__lst = [self.__dic[_] for _ in self.__dic.keys()] if any([len(self)-len(_) for _ in self.__lst]): raise ValueError("All arrays must be of the same length") def __repr__(self): res = [] for z in zip(*self.__lst): res.append(', '.join(map(lambda x:x.join(["'"]*2) if isinstance(x,str) else str(x) ,z))) return '\n'.join(res) def __len__(self): return len(self.__lst[0]) def __sort__(self, n, column, keep, reverse=True): if n<=0: return [] if n>len(self): n = len(self) if column not in self.__dic: raise KeyError(f'{column}') function = __import__('sys')._getframe(1).f_code.co_name column_type = f"Column '{column}' has dtype object, cannot use method '{function}' with this dtype" if not all([isinstance(_,int) or isinstance(_,float) for _ in self.__dic[column]]): raise TypeError(column_type) idx = list(self.__dic.keys()).index(column) tmp = sorted(zip(*self.__lst), key=lambda x:x[idx], reverse=reverse) lst = tmp[:n] num = lst[-1][idx] match keep: case 'first': pass case 'last': for t in tmp[n:]: if num==t[idx]: lst[-1]=t else: break case 'all': for t in tmp[n:]: if num==t[idx]: lst.append(t) else: break case _: raise ValueError('keep must be either "first", "last" or "all"') res = dict() for row in lst: for col,key in enumerate(self.__dic.keys()): tmp = res.get(key,[]) tmp.append(row[col]) res[key] = tmp return DataFrame(res) def nlargest(self, n, column, keep='first'): return self.__sort__(n, column, keep) def nsmallest(self, n, column, keep='first'): return self.__sort__(n, column, keep, reverse=False) dic = { 'Title': ['流浪地球 2', '奥本海默', '俄罗斯方块', '银河护卫队 3', '我爱你!', '电锯惊魂 10', '灌篮高手', '梦的背后', '漫长的季节', '1923 第一季', '黑暗荣耀 第二季', '重启人生', '画江湖之不良人 6', '地球脉动 第三季'], 'Award': ['评分最高华语电影', '评分最高外语电影', '年度冷门佳片', '评分最高喜剧片', '评分最高爱情片', '评分最高恐怖片', '评分最高动画片', '评分最高纪录片', '评分最高华语剧集', '评分最高英美新剧', '评分最高韩国剧集', '评分最高日本剧集', '评分最高动画剧集', '评分最高纪录剧集'], 'Score': [9.5, 8.8, 8.2, 8.2, 8.2, 7.8, 9.0, 9.0, 9.4, 9.3, 9.0, 9.3, 9.4, 9.8], } df = DataFrame(dic) print('DataFrame:') print(df) kp = 'first', 'last', 'all' for m in (3,7): print(f"df.nlargest({m},'Score'):") for k in kp: print(f'keep={k}:') print(df.nlargest(m, 'Score', keep=k)) print("df.nsmallest(2,'Score')") for k in kp: print(f'keep={k}:') print(df.nsmallest(2, 'Score', keep=k)) # 改变字典的键值顺序 dic = { 'Score': [9.5, 8.8, 8.2, 8.2, 8.2, 7.8, 9.0, 9.0, 9.4, 9.3, 9.0, 9.3, 9.4, 9.8], 'Title': ['流浪地球 2', '奥本海默', '俄罗斯方块', '银河护卫队 3', '我爱你!', '电锯惊魂 10', '灌篮高手', '梦的背后', '漫长的季节', '1923 第一季', '黑暗荣耀 第二季', '重启人生', '画江湖之不良人 6', '地球脉动 第三季'], 'Award': ['评分最高华语电影', '评分最高外语电影', '年度冷门佳片', '评分最高喜剧片', '评分最高爱情片', '评分最高恐怖片', '评分最高动画片', '评分最高纪录片', '评分最高华语剧集', '评分最高英美新剧', '评分最高韩国剧集', '评分最高日本剧集', '评分最高动画剧集', '评分最高纪录剧集'], } df = DataFrame(dic) print(df) for m in (3,7): print(f"df.nlargest({m},'Score'):") for k in kp: print(f'keep={k}:') print(df.nlargest(m, 'Score', keep=k)) print("df.nsmallest(2,'Score')") for k in kp: print(f'keep={k}:') print(df.nsmallest(2, 'Score', keep=k))
注:如果Python版本低于 3.10 ,上述代码中match-case需要改回if-elif-else结构。
运行结果:
DataFrame:
'流浪地球 2', '评分最高华语电影', 9.5
'奥本海默', '评分最高外语电影', 8.8
'俄罗斯方块', '年度冷门佳片', 8.2
'银河护卫队 3', '评分最高喜剧片', 8.2
'我爱你!', '评分最高爱情片', 8.2
'电锯惊魂 10', '评分最高恐怖片', 7.8
'灌篮高手', '评分最高动画片', 9.0
'梦的背后', '评分最高纪录片', 9.0
'漫长的季节', '评分最高华语剧集', 9.4
'1923 第一季', '评分最高英美新剧', 9.3
'黑暗荣耀 第二季', '评分最高韩国剧集', 9.0
'重启人生', '评分最高日本剧集', 9.3
'画江湖之不良人 6', '评分最高动画剧集', 9.4
'地球脉动 第三季', '评分最高纪录剧集', 9.8
df.nlargest(3,'Score'):
keep=first:
'地球脉动 第三季', '评分最高纪录剧集', 9.8
'流浪地球 2', '评分最高华语电影', 9.5
'漫长的季节', '评分最高华语剧集', 9.4
keep=last:
'地球脉动 第三季', '评分最高纪录剧集', 9.8
'流浪地球 2', '评分最高华语电影', 9.5
'画江湖之不良人 6', '评分最高动画剧集', 9.4
keep=all:
'地球脉动 第三季', '评分最高纪录剧集', 9.8
'流浪地球 2', '评分最高华语电影', 9.5
'漫长的季节', '评分最高华语剧集', 9.4
'画江湖之不良人 6', '评分最高动画剧集', 9.4
df.nlargest(7,'Score'):
keep=first:
'地球脉动 第三季', '评分最高纪录剧集', 9.8
'流浪地球 2', '评分最高华语电影', 9.5
'漫长的季节', '评分最高华语剧集', 9.4
'画江湖之不良人 6', '评分最高动画剧集', 9.4
'1923 第一季', '评分最高英美新剧', 9.3
'重启人生', '评分最高日本剧集', 9.3
'灌篮高手', '评分最高动画片', 9.0
keep=last:
'地球脉动 第三季', '评分最高纪录剧集', 9.8
'流浪地球 2', '评分最高华语电影', 9.5
'漫长的季节', '评分最高华语剧集', 9.4
'画江湖之不良人 6', '评分最高动画剧集', 9.4
'1923 第一季', '评分最高英美新剧', 9.3
'重启人生', '评分最高日本剧集', 9.3
'黑暗荣耀 第二季', '评分最高韩国剧集', 9.0
keep=all:
'地球脉动 第三季', '评分最高纪录剧集', 9.8
'流浪地球 2', '评分最高华语电影', 9.5
'漫长的季节', '评分最高华语剧集', 9.4
'画江湖之不良人 6', '评分最高动画剧集', 9.4
'1923 第一季', '评分最高英美新剧', 9.3
'重启人生', '评分最高日本剧集', 9.3
'灌篮高手', '评分最高动画片', 9.0
'梦的背后', '评分最高纪录片', 9.0
'黑暗荣耀 第二季', '评分最高韩国剧集', 9.0
df.nsmallest(2,'Score')
keep=first:
'电锯惊魂 10', '评分最高恐怖片', 7.8
'俄罗斯方块', '年度冷门佳片', 8.2
keep=last:
'电锯惊魂 10', '评分最高恐怖片', 7.8
'我爱你!', '评分最高爱情片', 8.2
keep=all:
'电锯惊魂 10', '评分最高恐怖片', 7.8
'俄罗斯方块', '年度冷门佳片', 8.2
'银河护卫队 3', '评分最高喜剧片', 8.2
'我爱你!', '评分最高爱情片', 8.2
9.5, '流浪地球 2', '评分最高华语电影'
8.8, '奥本海默', '评分最高外语电影'
8.2, '俄罗斯方块', '年度冷门佳片'
8.2, '银河护卫队 3', '评分最高喜剧片'
8.2, '我爱你!', '评分最高爱情片'
7.8, '电锯惊魂 10', '评分最高恐怖片'
9.0, '灌篮高手', '评分最高动画片'
9.0, '梦的背后', '评分最高纪录片'
9.4, '漫长的季节', '评分最高华语剧集'
9.3, '1923 第一季', '评分最高英美新剧'
9.0, '黑暗荣耀 第二季', '评分最高韩国剧集'
9.3, '重启人生', '评分最高日本剧集'
9.4, '画江湖之不良人 6', '评分最高动画剧集'
9.8, '地球脉动 第三季', '评分最高纪录剧集'
df.nlargest(3,'Score'):
keep=first:
9.8, '地球脉动 第三季', '评分最高纪录剧集'
9.5, '流浪地球 2', '评分最高华语电影'
9.4, '漫长的季节', '评分最高华语剧集'
keep=last:
9.8, '地球脉动 第三季', '评分最高纪录剧集'
9.5, '流浪地球 2', '评分最高华语电影'
9.4, '画江湖之不良人 6', '评分最高动画剧集'
keep=all:
9.8, '地球脉动 第三季', '评分最高纪录剧集'
9.5, '流浪地球 2', '评分最高华语电影'
9.4, '漫长的季节', '评分最高华语剧集'
9.4, '画江湖之不良人 6', '评分最高动画剧集'
df.nlargest(7,'Score'):
keep=first:
9.8, '地球脉动 第三季', '评分最高纪录剧集'
9.5, '流浪地球 2', '评分最高华语电影'
9.4, '漫长的季节', '评分最高华语剧集'
9.4, '画江湖之不良人 6', '评分最高动画剧集'
9.3, '1923 第一季', '评分最高英美新剧'
9.3, '重启人生', '评分最高日本剧集'
9.0, '灌篮高手', '评分最高动画片'
keep=last:
9.8, '地球脉动 第三季', '评分最高纪录剧集'
9.5, '流浪地球 2', '评分最高华语电影'
9.4, '漫长的季节', '评分最高华语剧集'
9.4, '画江湖之不良人 6', '评分最高动画剧集'
9.3, '1923 第一季', '评分最高英美新剧'
9.3, '重启人生', '评分最高日本剧集'
9.0, '黑暗荣耀 第二季', '评分最高韩国剧集'
keep=all:
9.8, '地球脉动 第三季', '评分最高纪录剧集'
9.5, '流浪地球 2', '评分最高华语电影'
9.4, '漫长的季节', '评分最高华语剧集'
9.4, '画江湖之不良人 6', '评分最高动画剧集'
9.3, '1923 第一季', '评分最高英美新剧'
9.3, '重启人生', '评分最高日本剧集'
9.0, '灌篮高手', '评分最高动画片'
9.0, '梦的背后', '评分最高纪录片'
9.0, '黑暗荣耀 第二季', '评分最高韩国剧集'
df.nsmallest(2,'Score')
keep=first:
7.8, '电锯惊魂 10', '评分最高恐怖片'
8.2, '俄罗斯方块', '年度冷门佳片'
keep=last:
7.8, '电锯惊魂 10', '评分最高恐怖片'
8.2, '我爱你!', '评分最高爱情片'
keep=all:
7.8, '电锯惊魂 10', '评分最高恐怖片'
8.2, '俄罗斯方块', '年度冷门佳片'
8.2, '银河护卫队 3', '评分最高喜剧片'
8.2, '我爱你!', '评分最高爱情片'
【小技巧】
在被调用函数中可用以下代码获取调用函数名:
sys._getframe(1).f_code.co_name
示例:
import sys def my_function(): frame = sys._getframe(1) function = frame.f_code.co_name print(f"Called from {function}") def function1(): my_function() def function2(): my_function() function1() function2()
Out:
Called from function1
Called from function2
完