Pandas如何删除含缺失值或取值不在0-1区间的DataFrame列
解决方案
要实现按规则过滤列的需求,不用写循环或自定义apply函数,用pandas内置向量化方法就能高效完成,数据量越大性能优势越明显。
你需要保留同时满足以下两个条件的列:
- 列中不存在缺失值
- 列中所有取值都落在[0,1]闭区间内
核心实现
你原有代码里的organize_columns和get_data函数可以直接复用,删掉无效的自定义校验函数,替换prepare_data里的处理逻辑即可:
import pandas as pd import numpy as np def prepare_data(data_abs_path, cols_abs_path): df_crime = pd.DataFrame( data=get_data(data_file_abs_path), columns=organize_columns(columns_file_abs_path) ) df_crime = df_crime.iloc[:, 5:] # 替换原始数据里的缺失占位符?为标准NaN df_crime = df_crime.replace('?', np.nan) # 统一转为浮点类型才能做数值比较 df_crime = df_crime.astype(float) # 逐列判断是否符合保留要求 # 1. 列内无缺失值 col_has_no_na = ~df_crime.isna().any() # 2. 列内不存在小于0或大于1的越界值 col_all_in_range = ~((df_crime < 0) | (df_crime > 1)).any() # 只保留同时满足两个条件的列 df_crime = df_crime.loc[:, col_has_no_na & col_all_in_range] return df_crime # 以下两个函数保持原逻辑即可,补充文件关闭操作避免句柄泄漏 def organize_columns(cols_abs_path): crime_file = open(cols_abs_path, "r") list_columns = [] string_crime = crime_file.read().split('\n') for i in range(len(string_crime)): if len(string_crime[i]) > 10: if string_crime[i][0:10] == "@attribute": att_line_splitted = string_crime[i].split(' ') if len(att_line_splitted) >= 2: list_columns += [str(att_line_splitted[1])] crime_file.close() return list_columns def get_data(data_file_abs_path1): return np.loadtxt(data_file_abs_path1, dtype=str, delimiter=',') if __name__ == '__main__': file_path = "/home/daniln/Documents/studies/BigData/ex3_home" columns_file_abs_path = file_path + "/communities.names" data_file_abs_path = file_path + "/communities.data" df_crime1 = prepare_data(data_file_abs_path, columns_file_abs_path)
原有代码的问题说明
你最初想的「替换非法值为NaN再调用dropna删列」的思路本身是可行的,只是写法不符合pandas语法规则:
- pandas不支持
0 > df_crime > 1这种连续比较写法,必须拆成两个独立判断,用位运算符|(或)、&(且)连接,且每个判断条件要单独加括号 df.loc只接受行、列两个维度的索引参数,你之前传了三个参数会直接报错- 自定义的
verify_valid_cols_values、delete_invalid_values_cols函数用了列表推导但没有返回值,也没有原地修改DataFrame,运行后不会产生任何实际效果
如果要沿用你最初的替换+删列思路,可以用mask方法实现非法值替换,代码如下:
# 将所有越界值替换为NaN df_crime = df_crime.mask((df_crime < 0) | (df_crime > 1), np.nan) # 直接删除存在NaN的列即可 df_crime = df_crime.dropna(axis=1)
示例DataFrame参考

内容的提问来源于stack exchange,提问作者dani_l_n
相关产品推荐
相关产品推荐

