pandas百分比对象列转数值失效及matplotlib绘图报float不可迭代错误
问题根因定位
1. 数值类型转换失效的原因
pd.update()方法只做按索引匹配的原地值覆盖,不会修改原列的dtype结构:原列是object类型时,哪怕覆盖进去的是数值,object列本身支持存储任意类型,列的标识依然会显示为object,这是你用df.info()检查类型没有变化的核心原因。- 原有转换逻辑存在偏差:你在转换后直接除以100得到的是小数形式的float值,和代码里
downcast='integer'要求的int类型目标本身冲突,小数无法被存为整数类型。 - 未排除首列的处理隐患:
apply会对全表所有列执行逻辑,首列Household的文本值会被pd.to_numeric强制识别为非数值,触发errors='coerce'把首列全部替换为NaN,污染原始数据。
2. 绘图报TypeError: 'float' object is not iterable的原因
- 直接触发报错的问题:
zip的第三个参数传入的是df_total[n]——你代码里的df_total是sum(axis=0)(按列求和)得到的Series,按列名索引后拿到的是单个float标量值,而zip要求所有入参都是可迭代对象,标量float无法被迭代,直接触发报错。 - 衍生逻辑错误:堆叠水平条形图需要计算的是每一行(单个Household)的总消费值,你用
sum(axis=0)是按列汇总所有Household的某类消费总和,后续df_rel计算时会因为索引不匹配(行索引和列名索引对不上)全部返回NaN,哪怕不报错生成的图也是错误的。
修复方案
第一步:修正数据转换逻辑
直接对非首列做赋值处理,pandas会自动根据传入的数值调整列的dtype,替代原有update的写法,同时手动排除首列避免污染数据。
如果需要保留百分比整数值(比如23代表23%),用以下代码:
# 定义需要转换的数值列(除首列外的所有列) num_cols = df.columns[1:] # 逐列去%、转整数类型 df[num_cols] = df[num_cols].apply( lambda col: pd.to_numeric(col.str.rstrip('%'), downcast='integer', errors='coerce') )
如果需要转换为小数形式的float值(比如0.23代表23%),在转换后加除以100的逻辑即可:
df[num_cols] = df[num_cols].apply( lambda col: pd.to_numeric(col.str.rstrip('%'), errors='coerce') / 100 )
处理完成后用df.info()检查,对应列会自动显示为int/float类型,不再是object。
第二步:修正绘图逻辑
首先调整总和计算的维度,再修正循环里的可迭代对象参数:
# 先绘制基础堆叠条形图 df.plot( x = 'Household', kind = 'barh', stacked = True, title = 'Cluster 1021 HH Consumption', mark_right = True ) # 修正:按行求和,得到每个Household的总消费值 df_total = df[num_cols].sum(axis=1) # 计算每个消费项在对应Household总消费中的占比 df_rel = df[num_cols].div(df_total, axis=0) * 100 # 修正循环逻辑:第三个迭代对象直接传按行求和的df_total,不再取单个值 for n in df_rel: for i, (cs, ab, pc, tot) in enumerate(zip( df[num_cols].cumsum(axis=1)[n], df_rel[n], df_total )): plt.text(tot, i, f'{tot:.1f}', va='center') plt.text(cs - ab/2, i, f'{pc:.1f}%', va='center', ha='center') plt.show()
内容的提问来源于stack exchange,提问作者kwispychickyjoy
相关产品推荐
相关产品推荐

