评委打分例子更优雅的写法

【注:本文所提资源来自GitHub的Joyful-Pandas项目,一个pandas的中文学习项目,可自行前往获取完整资料】

开始正题:

某比赛有1000名选手,300位评委打分,每个选手由三个不同的评委打分,每位评委打10位选手的分。
现在需要将各个评委的编号转到列索引,行索引不变,表格内容为打分分数,缺失值(即选手i没有被评委j打分)用’-'填充。

数据源:
在这里插入图片描述
原作者给出了三种写法:

【方法一】思维量较大,有技巧性,对Pandas依赖较少¶,耗时0.468秒。

t0 = time.perf_counter()
############################################################################################
L, k = [], 1
for i in range(301):
    judge = 'Judge_%d' % i
    result = df[(df.iloc[:, 0::2] == judge).any(1)]
    L_temp = (result.iloc[:, 0::2] == judge).values * result.iloc[:,
                                                                  1::2].values

    L.append(list(zip(result.index.tolist(), list(L_temp.max(axis=1)))))
L.pop(0)

df_result = pd.DataFrame([['-'] * 1000] * 300,
                         index=['Judge_%d' % i for i in range(1, 301)],
                         columns=['%d' % i for i in range(1, 1001)])
for i in L:
    for j in i:
        df_result.at['Judge_%d' % k, '%d' % j[0]] = j[1]
    k += 1
# ############################################################################################
t1 = time.perf_counter()
print('时间为:%.3f' % (t1 - t0))
df_result.T.head()

【方法二】思路简单,但运行时间较长¶,耗时15s。

t0=time.perf_counter()
############################################################################################
judge = np.array([[df.iloc[:,0:2].values],[df.iloc[:,2:4].values],[df.iloc[:,4:6].values]]).reshape(6000)[0::2]
score = np.array([[df.iloc[:,0:2].values],[df.iloc[:,2:4].values],[df.iloc[:,4:6].values]]).reshape(6000)[1::2]
df_result = pd.DataFrame({'judge':judge,'score':score}
                         ,index=np.array([range(1,1001)]*3).reshape(3000)).reset_index()
df_result = pd.crosstab(index=df_result['index'],columns=df_result['judge'],values=df_result['score']
                     ,aggfunc=np.sum).fillna('-').T.reindex(['Judge_%d'%i for i in range(1,301)]).T
############################################################################################
t1=time.perf_counter()
print('时间为:%.3f'%(t1-t0))
df_result.head()

【方法三】基本与方法二类似,但借助pivot函数大幅提高速度¶,耗时0.053s。

t0=time.perf_counter()
############################################################################################
judge = np.array([[df.iloc[:,0:2].values],[df.iloc[:,2:4].values],[df.iloc[:,4:6].values]]).reshape(6000)[0::2]
score = np.array([[df.iloc[:,0:2].values],[df.iloc[:,2:4].values],[df.iloc[:,4:6].values]]).reshape(6000)[1::2]
df_result = pd.DataFrame({'judge':judge,'score':score}
                         ,index=np.array([range(1,1001)]*3).reshape(3000)).reset_index()
df_result = df_result.pivot(index='index',columns='judge'
                    ,values='score').T.reindex(['Judge_%d'%i for i in range(1,301)]).T.fillna('-')
############################################################################################
t1=time.perf_counter()
print('时间为:%.3f'%(t1-t0))
df_result

从上面的方法来说,明显第三种方法更快,各种思路和操作也确实更能锻炼解题能力,但我觉得写法中太多的切片、取值、转换,看着头大,可读性不高。作为一个Pythoner,明显不够优雅,下面是我的写法,比较简洁明了,供大伙参考:

【方法一】耗时0.24秒,简洁的代码省下来很多敲码时间,且更具可读性。

# 构建空白的df, 设定index和columns
ans_one = pd.DataFrame(index=range(1, 1001),
                       columns=["Judge_%d" % i for i in range(1, 301)])
# 按行向量化计算,并对ans_one的相应位置进行对应的赋值
for idx, row in df.iterrows():
    ans_one.loc[idx, row[0]] = row[1]
    ans_one.loc[idx, row[2]] = row[3]
    ans_one.loc[idx, row[4]] = row[5]
# 空值填充
ans_one = ans_one.fillna('-')
ans_one

【方法二】没有上面的方法那么简洁,好在逻辑简单清晰,可读性高,小白一眼看下去也能知道在干嘛,运行速度也更快,只用0.127s。

l1, l2, l3 = df['评委一'].to_list(), df['评委二'].to_list(), df['评委三'].to_list()
# 取唯一值
judge_list = list(set(l1 + l2 + l3))
# 构建字典,作为后续DataFrame的data
judge_dict = {key: [] for key in judge_list}

# 按行向量化计算
for idx, row in df.iterrows():
    judge_dict[row[0]].append(row[1])
    judge_dict[row[2]].append(row[3])
    judge_dict[row[4]].append(row[5])
	# 不在该行中的键的值赋值为'-'
    exclude_key = [row[0], row[2], row[4]]
    for key in judge_dict:
        if key not in exclude_key:
            judge_dict[key].append('-')
            
# 构建结果的DataFrame
ans_two = pd.DataFrame(judge_dict, index=df.index)
# 对列名进行排序
col = sorted(ans_two.columns.to_list(), key=lambda x: int(x.split('_')[1]))
ans_two = ans_two[col]
ans_two

本文结束,Bye~
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值