课程资料《pandas数据处理与分析》、github地址、讲解视频、习题参考答案 、pandas官网
传送门:
一、补充习题
Ex1:NumPy的向量化运算
- 给定一个正整数列表,请找出缺失的最小正整数。
arr = np.array([2,3,4])
get_miss(arr)
1
arr = np.array([6,3,5,1,2])
get_miss(arr)
4
arr = np.array([5,2,1,3,4])
get_miss(arr)
6
# 思路:排序后diff做差,找到差值为2的索引对应的元素减一就是,多个值取最小。
def get_miss(n):
s=pd.Series(n).sort_values()
if s[0]!=1:
return 1
elif s.diff().dropna().sum()==len(s)-1:
return len(s)+1
else:
miss_index=s.diff()[s.diff().values==2].index
return (n[miss_index]-1).min()
- 设计一个生成二维NumPy数组的函数get_res(),其输入为正整数n,返回的数组构造方式如下:第1行填入1个1,第2行在上一行填入位置的下一列连续填入2个2,第3行在第二行最后一个填入位置的下一列连续填入3个3,…,第n行在第n-1行最后一个填入位置的下一列连续填入n个n。
n = 4
get_res(n)
array([[1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[0., 2., 2., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 3., 3., 3., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 4., 4., 4., 4.]])
本来想生成没有0的list[[i]*i for i in range(1,n+1,1)
求索引来知道每个数前后填多少0,但是还得展平、求索引,太麻烦。还是老老实实计算前后填充0的个数好了:
# 生成numpy格式只求求sum,懒得写循环求和
def sum_list(n):
return np.array([i for i in range(1,n+1,1)]).sum() if n!=0 else 0
def get_res(n):
ls=[]
le=sum_list(n)
for i in range(1,n+1,1):
lt=[0]*sum_list(i-1)+[i]*i+[0]*(le-sum_list(i-1)-i)
ls.append(lt)
return np.array(ls)
get_res(5)
array([[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5]])
- 点 A 初始位置在数轴原点处,现进行n步简单随机游走,即每一步以等概率向左或向右移动长度为1的距离,记该点最终的位置为
S
n
S_n
Sn ,则可以证明:
my_list = [-1,1]
def test(n):
ls=np.random.choice(my_list, 100, p=[0.5,0.5]) # choice函数随机取样
return int(np.fabs(ls.sum())) # ls的和就是最终点的位置,返回位置s_n的绝对值
def ponits(n):
lg_1000=[]
for j in range(1000): # 运行1000次试验
ls_100=[]
for i in range(100): # 循环100次取均值求E|s_n|
sn=test(n)
ls_100.append(sn)
esn=np.array(ls_100).mean() # 100次sn均值
result=esn/np.sqrt(n)-np.sqrt(2/np.pi)
lg_1000.append(result)
return np.array(lg_1000)
anwser=ponits(5000)
anwser.mean(),np.quantile(anwser,0.05),np.quantile(anwser,0.95) # 为啥结果不是接近0呢
(-0.685692170472683, -0.6997381395741726, -0.6717367110391853)
- 在二维平面上有n个点,每个点具有k维特征,点的坐标数据记录在node_xy中,点的特征数据记录在node_fea中。现要计算所有点的相关矩阵S,点a和点b的相关系数定义如下:
n, k = 1000, 10
node_xy = np.random.rand(n, 2)
node_fea = np.random.rand(n, k)
get_S(node_xy, node_fea)
- 计算 σ a b \sigma _{ab} σab:
def sigma(a,b):
return a@b/(np.linalg.norm(a)*np.linalg.norm(b))
- 计算
λ
a
b
\lambda _{ab}
λab
计算出每个点和其它点的距离表格,后面再查表,不知道是不是快一点。
# 计算两点欧氏距离用np.linalg.norm(a-b)
# 计算出每个点和其它点的距离表格
ls,le=[],len(node_xy)
for i in range(le):
for j in range(0,le):
if i!=j:
ls.append(np.linalg.norm(node_xy[i]-node_xy[j]))
else:
continue
df_all=pd.DataFrame(np.array(ls).reshape(le,-1))
new_cloumns=['点'+str(i) for i in range(1,le,1)]
df.columns=new_cloumns
df
点1 点2 点3 点4
0 0.891908 0.259182 0.528596 0.302012
1 0.891908 0.632727 0.602179 0.939268
2 0.259182 0.632727 0.374223 0.396821
3 0.528596 0.602179 0.374223 0.399266
4 0.302012 0.939268 0.396821 0.399266
但是貌似计算量还是一样的,而且排名、查表写起来很麻烦,直接莽吧。就是知道了还有排名函数rank。
算了,还是不会做,放弃了
Ex2:统计学生的成绩情况
在data/supplement/ex2目录下存放了某校高三第一学期的学生成绩情况,包含16次周测成绩、期中考试成绩和期末考试成绩,科目一栏的成绩表示学生选课的成绩。所有的表中,相同的行表示的是同一位同学。请完成以下练习:
df = pd.read_csv('data/supplement/ex2/第1次周测成绩.csv')
df.head()
Out[5]:
班级 姓名 选科 语文 数学 英语 科目
0 1 吴刚 地理 93 95 82 69
1 1 卢楠 物理 108 77 90 94
2 1 唐秀兰 历史 88 72 95 85
3 1 张刚 化学 85 88 102 76
4 1 姜洋 历史 104 99 84 86
-
该校高三年级中是否存在姓名相同的学生?
-
在第一次周测中,请求出每个班级选修物理或化学同学的语数英总分的平均值。哪个班级最高?
-
学生在该学期的总评计算方式是各次考试总分的加权平均值,其中周测成绩权重为50%(每次测验权重相等,即3.125%),期中权重为20%,期末权重为30%。请结合nlargest函数找出年级中总评前十的同学。
-
请统计1班到8班文理科(物化生为理科,政史地为文科)期末考试总分前5的学生,结果格式如下,括号内的为选科分数:
pd.DataFrame(
{
"1班(文)": ["王大锤:历史(102)"]+["..."]* 4,
"1班(理)": ["..."]* 5,
"2班(文)": ["..."]* 5,
"...": ["..."]* 5,
"8班(理)": ["..."]* 5,
}
) # 王大锤:历史(102)只是举个例子,表示结果字符串需要按照这个格式来写
Out[6]:
1班(文) 1班(理) 2班(文) ... 8班(理)
0 王大锤:历史(102) ... ... ... ...
1 ... ... ... ... ...
2 ... ... ... ... ...
3 ... ... ... ... ...
4 ... ... ... ... ...
- 学生成绩的稳定性可以用每次考试在全年级相同选科学生中的总分排名标准差来度量,请计算每个班级的各科学生成绩稳定性的均值,结果格式如下:
pd.DataFrame(
np.random.rand(11, 6),
index=pd.Index(range(1, 12), name="班级"),
columns=pd.Index(
["物理", "化学", "生物", "历史", "地理", "政治"],
name="选科",
)
)
Out[7]:
选科 物理 化学 生物 历史 地理 政治
班级
1 0.461479 0.780529 0.118274 0.639921 0.143353 0.944669
2 0.521848 0.414662 0.264556 0.774234 0.456150 0.568434
3 0.018790 0.617635 0.612096 0.616934 0.943748 0.681820
4 0.359508 0.437032 0.697631 0.060225 0.666767 0.670638
5 0.210383 0.128926 0.315428 0.363711 0.570197 0.438602
6 0.988374 0.102045 0.208877 0.161310 0.653108 0.253292
7 0.466311 0.244426 0.158970 0.110375 0.656330 0.138183
8 0.196582 0.368725 0.820993 0.097101 0.837945 0.096098
9 0.976459 0.468651 0.976761 0.604846 0.739264 0.039188
10 0.282807 0.120197 0.296140 0.118728 0.317983 0.414263
11 0.064147 0.692472 0.566601 0.265389 0.523248 0.093941
- 该校高三年级中是否存在姓名相同的学生?
#df['姓名'].value_counts().sort_values() # 最大值还是1,没有重名
len(df.drop_duplicates(subset=['姓名'] ))==len(df) # 为True没有重名
- 在第一次周测中,请求出每个班级选修物理或化学同学的语数英总分的平均值。哪个班级最高?
df.loc[df['选科'].isin(['物理','化学'])].groupby(df['班级'])[['语文','数学','英语']].\
mean().sum(1).sort_values(ascending=False).head()/3
班级
2 93.939394
1 91.575758
6 90.964912
7 90.272727
9 90.023810
dtype: float64
- 学生在该学期的总评计算方式是各次考试总分的加权平均值,其中周测成绩权重为50%(每次测验权重相等,即3.125%),期中权重为20%,期末权重为30%。请结合nlargest函数找出年级中总评前十的同学。
import os
data_dir='./data/supplement/ex2'
df_16=pd.DataFrame(columns=['班级', '姓名', '选科', '语文', '数学', '英语', '科目'])
for file_name in os.listdir(data_dir):
if file_name=='期中考试成绩.csv':
df_mid=pd.read_csv(os.path.join(data_dir,file_name)).set_index('姓名').sort_index()
elif file_name=='期末考试成绩.csv':
df_end=pd.read_csv(os.path.join(data_dir,file_name)).set_index('姓名').sort_index()
else:
df_week=pd.read_csv(os.path.join(data_dir,file_name))
df_16=pd.concat([df_16,df_week],axis=0)
# 16次周测验的总成绩平均值
score_week=df_16.groupby(df['姓名'])[['语文','数学','英语','科目']].sum().sum(1).sort_index()/16
姓名
丁帅 387.5000
丁斌 404.8750
丁燕 387.4375
万云 395.8750
万志强 399.7500
...
龙晨 390.3750
龙秀荣 393.5625
龙鑫 404.1875
龙雪梅 393.1250
龚建华 391.1250
Length: 896, dtype: float64
score=df_mid[['语文','数学','英语','科目']].sum(1)*0.2+\
df_end[['语文','数学','英语','科目']].sum(1)*0.3+score_week*0.5
score.sort_values(ascending=False).index[:10]
Index(['王想', '黄萍', '黄文', '黎玉', '王淑英', '慕阳', '杨凤兰', '张欢', '吕雪', '孙桂珍'], dtype='object', name='姓名')
- 请统计1班到8班文理科(物化生为理科,政史地为文科)期末考试总分前5的学生,结果格式如下,括号内的为选科分数
df8=df_end.loc[df_end['班级']<9].reset_index() # 选出前8个班的同学
# 根据班级、姓名、文理科分组,计算总分
df8=df8.groupby([df8['班级'],df8['选科'].isin\
(['物理','化学','生物']),df8['姓名']])[['语文','数学','英语','科目']].sum(1).sum(1)
df8=pd.DataFrame(df8,columns=['总分']).reset_index()
df8
班级 选科 姓名 总分
0 1 False 任兰英 351
1 1 False 余峰 367
2 1 False 刘丽 390
3 1 False 刘婷婷 414
4 1 False 刘桂荣 394
... ... ... ... ...
676 8 True 陈玲 351
677 8 True 高莉 381
678 8 True 黄利 382
679 8 True 黄斌 423
680 8 True 黎想 430
# 定义组内排序函数
def sort(s):
return s.sort_values(['总分'],ascending=False)[:5]
# 根据班级、文理科分组排序取前5名
df_top5=df8.groupby([df8['班级'],df8['选科']])[['姓名','总分']].agg(sort).reset_index()
del df_top5['level_2'] # 重设索引时多了一列之前的索引,将其去掉
df_top5.head()
班级 选科 姓名 总分
0 1 False 秦利 435
1 1 False 王雷 415
2 1 False 刘婷婷 414
3 1 False 唐秀兰 411
4 1 False 龙晨 401
df_top5=df_top5.merge(df_end,on=['姓名','班级'],how='left') # 合并之前的表拿到选科和选科成绩
# 更改格式方便后面合并列
df_top5['班级']=df_top5['班级'].apply(lambda x : str(x)+'班')
df_top5['选科_x']=df_top5['选科_x'].apply(lambda x: '(理)' if x else '(文)')
df_top5['科目']=df_top5['科目'].apply(lambda x :'('+str(x)+')')
df_top5.eval('班级=班级+选科_x',inplace=True)
df_top5.eval('科目=选科_y+科目',inplace=True)
df_top5=df_top5[['班级','姓名','科目']]
df_top5['姓名']=df_top5['姓名'].apply(lambda x : str(x)+':')
df_top5.eval('姓名=姓名+科目',inplace=True)
del df_top5['科目']
df_top5 # 到这一步改不了横表了,不会做啊
班级 姓名
0 1班(文) 秦利:地理(116)
1 1班(文) 王雷:地理(116)
2 1班(文) 刘婷婷:地理(115)
3 1班(文) 唐秀兰:历史(115)
4 1班(文) 龙晨:地理(106)
... ... ...
75 8班(理) 王想:物理(115)
76 8班(理) 刘娜:化学(102)
77 8班(理) 黎想:化学(118)
78 8班(理) 严琳:化学(125)
79 8班(理) 张桂香:物理(124)
- 学生成绩的稳定性可以用每次考试在全年级相同选科学生中的总分排名标准差来度量,请计算每个班级的各科学生成绩稳定性的均值。
# 之前的df_mid和df_end索引都是姓名,连接时要重置索引
df_all=pd.concat([df_16,df_mid.reset_index(),df_end.reset_index()],axis=0).reset_index()
df_all.eval('总分=语文+数学+英语+科目',inplace=True)
# 将index设置为考试的次数,比如第一次、第二次......第18次
# 列表ls是1到18重复896次后展平
ls=np.array([[i]*896 for i in range(1,19,1)]).flatten()
df_all.loc[df_all.index,'index']=ls
df_all # index为第几次考试
index 班级 姓名 选科 语文 数学 英语 科目 总分
0 1 1 吴刚 地理 102 84 106 104 396
1 1 1 卢楠 物理 78 88 87 79 332
2 1 1 唐秀兰 历史 106 86 111 112 415
3 1 1 张刚 化学 97 77 80 113 367
4 1 1 姜洋 历史 101 89 93 105 388
def sort(s):
return s.sort_values(['总分'],ascending=False)
# 每次考试各个选科根据总分排序
df_all=df_all.groupby([df_all['index'],df_all['选科']])[['班级','姓名','总分']].agg(sort).reset_index()
size=df_all.groupby([df_all['index'],df_all['选科']])['level_2'].size() # 得到每个组别的元素个数,也就是每组排序长度
sort_index=np.array([[i for i in range(1,j+1,1)] for j in size.values]).flatten() # 不定长序列无法展平
lg=[]
for i in sort_index:
for j in i:
lg.append(j)
df_all.level_2=lg
df_all=df_all.rename(columns={'level_2':'排名'})
df_all # 得到每次考试每个学科排名情况
index 选科 排名 班级 姓名 总分
0 1 化学 1 3 杨桂荣 447
1 1 化学 2 8 狄琳 443
2 1 化学 3 11 夏刚 441
3 1 化学 4 4 吴淑兰 437
4 1 化学 5 6 韩柳 436
... ... ... ... ... ... ...
16123 18 生物 162 6 沈涛 332
16124 18 生物 163 4 王浩 331
16125 18 生物 164 5 萧秀云 323
16126 18 生物 165 6 沈欣 317
16127 18 生物 166 2 谷静 303
result=df_all.groupby([df_all['选科'],df_all['姓名']])[['班级','排名']].std() # 计算排名标准差
result['班级']=df_mid.sort_values(['选科','姓名']).reset_index()['班级'] # 结果加入班级字段
anwser=result.groupby([result['班级'],result['选科']])['排名'].mean() # 对班级选科分组求std
anwser=pd.DataFrame(anwser)
anwser.unstack(1) # 转换格式
Ex3:统计商品的审核情况
在data/supplement/ex3中存放了两个有关商品审核的信息表,“商品信息.csv”中记录了每个商品的ID号,唯一的识别码以及商品所属的类别,“申请与审核记录.csv”中记录了每个商品的审核信息。已知商品的审核流程如下:由申请人发起商品审核的申请,然后由审核人审核,审核的结果包括通过与不通过两种情况,若商品不通过审核则可以由另一位申请人再次发起申请,直到商品的审核通过。
df_info = pd.read_csv('data/supplement/ex3/商品信息.csv')
df_info.head()
Out[9]:
ID号 识别码 类别
0 ID 000001 CRtXJUK T1
1 ID 000002 RGSxifC Q1
2 ID 000003 AboduTp S1
3 ID 000004 zlpUeMl S2
4 ID 000005 IVQqhIK S3
df_record = pd.read_csv('data/supplement/ex3/申请与审核记录.csv')
df_record.head()
Out[11]:
ID号 申请人 申请时间 审核人 审核时间 结果
0 ID 000001 \#+3((52\{ 2020-04-19 ~1=6\*183| 2020-05-03 未通过
1 ID 000001 8@75[1|2\* 2020-05-10 15![3\({59 2020-07-17 未通过
2 ID 000001 }!7)(#^0*7 2020-07-28 3`}04}%@75 2020-08-23 通过
3 ID 000002 |*{20#9|}5 2020-01-05 ={`8]03*4+ 2020-03-09 未通过
4 ID 000002 4~6%)455`[ 2020-03-14 =$-36[)|8] 2020-04-21 未通过
- 有多少商品最终通过审核?
- 各类别商品的通过率分别为多少?
- 对于类别为“T1”且最终状态为通过的商品,平均审核次数为多少?
- 是否存在商品在上一次审核未完成时就提交了下一次审核申请?
- 请对所有审核通过的商品统计第一位申请人和最后一位审核人的信息,返回格式如下:
pd.DataFrame(
{
"ID号": ["ID 000001"]+["..."]*3,
"类别":["T1"]+["..."]*3,
"申请人":["\#+3((52\{"]+["..."]*3,
"审核人":["3`}04}%@75"]+["..."]*3
},
index=[1,2,3,"..."]
)
Out[12]:
ID号 类别 申请人 审核人
1 ID 000001 T1 \#+3((52\{ 3`}04}%@75
2 ... ... ... ...
3 ... ... ... ...
... ... ... ... ...
- 有多少商品最终通过审核?
df_record['结果'].value_counts() # 10848
未通过 136652
通过 10848
Name: 结果, dtype: int64
或者是:
# 计算结果为通过和ID的唯一组合数,更严谨的写法,防止一个ID通过两次
len(df_record[df_record.结果=='通过'].groupby(['ID号','结果']). groups)
- 各类别商品的通过率分别为多少?
df_record合并加入类别和识别码字段
df=df_record.merge(df_info,on='ID号',how='left')
df.groupby(['类别','结果'])['结果'].count() # 计算每个类别是否通过的个数
类别 结果
Q1 未通过 19153
通过 1494
Q2 未通过 20010
通过 1613
S1 未通过 19552
通过 1538
S2 未通过 19162
通过 1548
S3 未通过 19529
通过 1582
T1 未通过 19324
通过 1509
T2 未通过 19922
通过 1564
Name: 结果, dtype: int64
# to_frame()将Series转为DataFrame结构,将类别从转到列,这样就好计算了
# 再去除列的外层索引,index名丢失,重命名为'结果'。
res=df.groupby(['类别','结果'])['结果'].count().\
to_frame().unstack(0).droplevel(0,axis=1).rename_axis('结果')
res
类别 Q1 Q2 S1 S2 S3 T1 T2
结果
未通过 19153 20010 19552 19162 19529 19324 19922
通过 1494 1613 1538 1548 1582 1509 1564
res[res.index=='通过'].values/res.sum().values # 这样无法转为百分数,还得改
array([[0.07235918, 0.07459649, 0.07292556, 0.0747465 , 0.07493724,
0.07243316, 0.07279159]])
res=(res[res.index=='通过']/res.sum()).stack(0).apply(lambda x: format(x, '.2%')) .to_frame()
res.columns=['通过率']
res.reset_index()
结果 类别 通过率
0 通过 Q1 7.24%
1 通过 Q2 7.46%
2 通过 S1 7.29%
3 通过 S2 7.47%
4 通过 S3 7.49%
5 通过 T1 7.24%
6 通过 T2 7.28%
- 对于类别为“T1”且最终状态为通过的商品,平均审核次数为多少?
# 获取所以T1类里面通过审核的商品ID
ids=df.loc[(df.类别=='T1')&(df.结果=='通过'),'ID号']
df[df['ID号'].isin(ids)].groupby('ID号')['结果'].count().mean()
5.547382372432074
- 是否存在商品在上一次审核未完成时就提交了下一次审核申请?
df.申请时间=pd.to_datetime(df.申请时间) # 转为时间序列
df.审核时间=pd.to_datetime(df.审核时间)
# 申请时间上移一位
df.申请时间[:-1]=df.申请时间[1:]
df.eval('时间差=审核时间-申请时间',inplace=True)
# 获取每件商品在表格在切换的位置,这个位置计算的时间差是两种商品的时间差,不应该计入
df['index']=df.index
del_ids=df.groupby(df['ID号'])['index'].max().values
del_ids,len(del_ids)
array([ 2, 7, 10, ..., 147488, 147493, 147499], dtype=int64)
# 计算非切换位置时间差是否大于0的真假矩阵的唯一值统计
anwser=df.loc[~df['index'].isin(del_ids)]['时间差'].dt.days<0
anwser.value_counts() # 所以是有3182件商品没审核就提交的
True 117486
False 3182
Name: 时间差, dtype: int64
# 看看没有过滤切换位置的情况
(df['时间差'].dt.days<0).value_counts()
True 117524
False 29976
Name: 时间差, dtype: int64
下面试着找到这3182件商品,没有找到,醉了
n1=df.loc[(df['时间差'].dt.days>0)].index.values # 所有时间差大于0的商品的索引
n2=df.loc[~df['index'].isin(del_ids)]['index'].values # 不是切换位置的索引
inter=np.intersect1d(n1,n2) # numpy求二者的交集
array([], dtype=int64) # 没有交集.......
最后我试了无数遍,发现漏了时间差=0的情况,即当天审核完当天提交。所以一开始上面判断条件应该用>0。怪不得我后面想找这3182件死活找不出来。
(df.loc[~df['index'].isin(del_ids)]['时间差'].dt.days==0).value_counts()
True 117486
False 3182
Name: 时间差, dtype: int64
(df.loc[~df['index'].isin(del_ids)]['时间差'].dt.days>0).value_counts()
False 120668
Name: 时间差, dtype: int64
- 请对所有审核通过的商品统计第一位申请人和最后一位审核人的信息,返回指定格式
id_pass=df.loc[(df.结果=='通过'),'ID号'] # 审核通过的商品ID号
df['index']=df.index.values # 加入一列为其index方便筛选
统计每件商品申请时间是否按顺序排列
td=df.groupby('ID号')['申请时间'].diff(1) # 根据ID号将各个商品分开统计申请时间,用diff做差
(td.dt.days<0).value_counts() # 统计是否有差小于0,也就是申请时间是否都是按顺序来的
False 147500
Name: 申请时间, dtype: int64
每件商品的申请时间都是按顺序来的,所以index最小的对应的就是第一个申请的人
app_ids=df[df['ID号'].isin(id_pass)].groupby('ID号')['index'].min().values
df1=df.loc[df['index'].isin(app_ids),['ID号','申请人']]
df1
ID号 申请人
0 ID 000001 \#+3((52\{
17 ID 000005 =_@@9(2|#|
27 ID 000008 3~2#9`*~#8
56 ID 000013 78!#-24|)&
85 ID 000019 +_0!]*8!]$
... ... ...
147420 ID 026819 \%\=4$9@+-
147442 ID 026823 }{**\(7&&(
147449 ID 026824 +5&%{#*`_`
147470 ID 026828 \##{~+^9!3
147480 ID 026830 @`=(2@03^0
统计每件商品审核时间是否按顺序排列
td2=df.groupby('ID号')['审核时间'].diff(1) # 根据ID号将各个商品分开统计申请时间,用diff做差
(td2.dt.days<0).value_counts() # 统计是否有差小于0,也就是申请时间是否都是按顺序来的
False 147500
Name: 审核时间, dtype: int64
每件商品的审核时间都是按顺序来的,所以index最大的对应的就是最后一个审核的人。因为按常理来说肯定是先申请后审核,而且通过之后不再申请。
Reviewer_ids=df[df['ID号'].isin(id_pass)].groupby('ID号')['index'].max().values
df2=df.loc[df['index'].isin(Reviewer_ids),['ID号','审核人']]
df2
ID号 审核人
2 ID 000001 3`}04}%@75
19 ID 000005 ^7#10{&3^6
30 ID 000008 *}-5[$$]87
61 ID 000013 )`]({`6-52
88 ID 000019 {---]\43!@
... ... ...
147422 ID 026819 @5~@$=#3[]
147448 ID 026823 53~(\4|7(=
147455 ID 026824 012&*&$]}
147472 ID 026828 @`^=@!{0#@
147488 ID 026830 [_7\=*\(#8
df1.merge(df2,on='ID号',how='left')
df_all=df1.merge(df2,on='ID号',how='left')
df_all['类别']=df[df['ID号'].isin(id_pass)]['类别']
df_all.iloc[:,[0,3,1,2]] # 新增类别列在最后,用iloc拿到ID后面
ID号 类别 申请人 审核人
0 ID 000001 T1 \#+3((52\{ 3`}04}%@75
1 ID 000005 T1 =_@@9(2|#| ^7#10{&3^6
2 ID 000008 T1 3~2#9`*~#8 *}-5[$$]87
3 ID 000013 NaN 78!#-24|)& )`]({`6-52
4 ID 000019 NaN +_0!]*8!]$ {---]\43!@
... ... ... ... ...
10843 ID 026819 NaN \%\=4$9@+- @5~@$=#3[]
10844 ID 026823 NaN }{**\(7&&( 53~(\4|7(=
10845 ID 026824 NaN +5&%{#*`_` 012&*&$]}
10846 ID 026828 NaN \##{~+^9!3 @`^=@!{0#@
10847 ID 026830 NaN @`=(2@03^0 [_7\=*\(#8