百万行DataFrame缺失值填充优化求助:解决低效循环与loc报错
优化方案及问题解析
原代码核心问题
- 重复计算品牌集合:每次循环都调用
find_Android_brand和find_iOS_brand,这两个函数会反复遍历整个DataFrame获取唯一品牌,属于完全冗余的操作。 - 逐行循环效率极低:Pandas的设计核心是矢量化操作,逐行处理百万级数据会导致性能呈指数级下降。
- 链式索引风险:
df['device_os'][i]这种链式赋值不仅效率低下,还可能触发SettingWithCopyWarning,导致意外的赋值失败。
优化后的代码
import pandas as pd def Android_iOs_device_os_change(df): # 一次性生成Android和iOS的品牌集合(集合的in操作远快于列表) android_brands = set(df.loc[df['device_os'] == 'Android', 'device_brand'].unique()) android_brands.remove('(not set)') ios_brands = set(df.loc[df['device_os'] == 'iOS', 'device_brand'].unique()) ios_brands.remove('(not set)') # 筛选需要处理的行:device_os为空且device_brand不为空 mask = df['device_os'].isnull() & df['device_brand'].notnull() # 先默认填充为'(not set)' df.loc[mask, 'device_os'] = '(not set)' # 批量填充Android品牌对应的os android_mask = mask & df['device_brand'].isin(android_brands) df.loc[android_mask, 'device_os'] = 'Android' # 批量填充iOS品牌对应的os ios_mask = mask & df['device_brand'].isin(ios_brands) df.loc[ios_mask, 'device_os'] = 'iOS' return df
优化点说明
- 预计算品牌集合:只在函数开头计算一次Android和iOS的品牌集合,避免重复遍历DataFrame;集合的
in操作时间复杂度为O(1),远快于列表的O(n)。 - 矢量化批量操作:用
loc结合布尔掩码实现批量赋值,所有操作都是Pandas底层优化的矢量化运算,处理百万级数据仅需几秒到几十秒。 - 避免链式索引:全程使用
df.loc[掩码, 列名]的方式赋值,既安全又高效,不会触发赋值警告。
关于你遇到的'Series' object has no attribute 'device_os'报错
这个错误通常是因为你在操作时意外将DataFrame转换成了Series。比如错误地写了df[mask].loc[:, 'device_os'],此时df[mask]如果是一个Series(比如掩码筛选后只剩一列),就会找不到device_os属性。正确的做法是直接在原DataFrame上用df.loc[mask, 'device_os']操作,不要提前切片出子DataFrame/Series。
内容的提问来源于stack exchange,提问作者Necrotoxxx
相关产品推荐
相关产品推荐

