关于Python中DataFrame批量处理str时的bug:
把df数据从小数转化成百分数形式时,写出的一个bug,记录一下
当时觉得百思不得其解,现在想想,觉得:啊,我真是个...欸
问题描述
读取excel中的数据,返回值为DataFrame,对DataFrame中某一行进行操作,将小数转化为百分数
我写的代码是这样的:
# 读数据
df = pd.read_excel('data.xlsx')
# 小数转化为百分数形式,先 *100, 保留两位小数,然后转成 str, 加一个 %
df['rate'] = str(round(df['rate'] * 100, 2)) + "%"
# 存数据
df.to_csv('data_res.csv', index=False)
结果它返回是这样的:
# data.excel:
index price rate
0 12 100 0.0012
1 43 150 0.0934
2 54 200 0.0003
3 32 324 0.0043
4 56 546 0.0234
# 返回结果
index price rate
0 12 100 0 0.12\n1 9.34\n2 0.03\n3 0.43\n4 ...
1 43 150 0 0.12\n1 9.34\n2 0.03\n3 0.43\n4 ...
2 54 200 0 0.12\n1 9.34\n2 0.03\n3 0.43\n4 ...
3 32 324 0 0.12\n1 9.34\n2 0.03\n3 0.43\n4 ...
4 56 546 0 0.12\n1 9.34\n2 0.03\n3 0.43\n4 ...
反正看到结果的时候,我是挺震惊的。然后还因为存为CSV的文件过大,打开的时候把excel给卡死了一回,内心又稍微崩溃了几分钟
原因分析:
问题出在str()上,直接看代码吧
# 小数转化为百分数形式,先 *100, 保留两位小数,然后转成 str, 加一个 %
df['rate'] = str(round(df['rate'] * 100, 2)) + "%"
这行代码,我想的是:df的每一行批量操作,先每行*100,再每行转str,每行str再加个百分号
但是Python不这么想,它想的是:先每行 *100,然后全部的行转成str, 赋值给df[‘rate’]的每一行
也就是说,我希望的是类似这样的操作:
df['rate'] = df['rate'] * 100 # 每行按照相同逻辑批量操作
Python执行的是类似这样的操作:
df['rate'] = "反正就是一个str" # 每行赋值相同
解决方案:
法1: Lambda表达式批量操作
法2: str() 转为astype(str)
上代码:
# 1. Lambda表达式批量操作 因为本来就是对单行进行批量操作,所以str()里面是一行的数据,没问题
df['rate'] = df.apply(lambda x: str(round(x['rate'] * 100, 2)) + "%", axis=1)
# 2. str() 转为astype(str)
# astype(str) 是 pandas 中的方法,专门用于将 DataFrame 或 Series 中的列数据转换为字符串类型
# 这里是转换整个 DataFrame
df['rate'] = round(df['rate'] * 100, 2).astype(str) + "%"
这回结果就正常了
index price rate
0 12 100 0.12%
1 43 150 9.34%
2 54 200 0.03%
3 32 324 0.43%
4 56 546 2.34%
总结
对于写的这个bug,对于这个bug害我加班半小时,我的内心感到非常的平静和简单。
高频次地写Python快一个月了,有时觉得我和Python很熟了,但还是会偶发这种匪夷所思的问题(当然,这完全是我的错
有时候我会有一种:和Python很熟但偶尔会被反咬一口的感觉
哈哈哈(抹眼泪
总之这个bug更类似一个阅读理解的逻辑问题,我没有想清楚str()的用法,想当然就用了,结果当然是错的。但是这个bug, 在踩过坑之前,我是不会想的到和主动避免的。
只能说我还有很大的进步空间,嗯。