如何简化移除DataFrame中值全相同列的代码?可改用for循环或apply吗?
问题描述
假设有如下包含多列值全相同的DataFrame:
df = pd.DataFrame({'State':['Texas','Texas','Texas','Texas'], 'County':['Harris','Harris','Harris','Harris'], 'Building':[1,2,3,4], 'Budget':[7328,3290,8342,4290]})
我想要编写函数扫描该DataFrame并删除值全相同的列,已实现一个可返回被移除列及其唯一值的Series x的drop_monocols函数(代码如下):
def drop_monocols(df): # 接收DataFrame x = dict() n = 0 while n < df.shape[1]: if df.iloc[:,n].nunique()==1: # 找出所有值相同的列 x[df.columns[n]] = df.iloc[0,n] # 将列名和对应唯一值存入字典 df = df.drop(df.columns[n], axis=1) # 删除无用列 else: n +=1 x = pd.Series(x) return x, df # 返回无用列的Series和清理后的DataFrame
作为编程新手,我想了解:
- 是否有更简洁的实现方式?
- 能否用for循环替代while循环?
- 是否可以用.apply方法代替传入df的函数?
解答
1. 更简洁的实现方式
利用pandas的向量化操作可以直接筛选目标列,不用逐列循环,效率和可读性都更高:
def drop_monocols(df): # 筛选出所有唯一值数量为1的列 mono_cols = df.columns[df.nunique() == 1] # 提取这些列的唯一值(取第一行即可) dropped_series = df.loc[0, mono_cols] # 删除目标列得到清理后的DataFrame cleaned_df = df.drop(mono_cols, axis=1) return dropped_series, cleaned_df
df.nunique()会直接返回每一列的唯一值数量,用布尔索引就能一次性筛选出所有单值列,比循环操作高效得多。
2. 用for循环替代while循环
如果偏好for循环,建议先收集所有需要删除的列,再统一处理(避免循环中修改DataFrame列数导致索引混乱):
def drop_monocols(df): dropped_dict = {} # 遍历所有列,收集单值列及其唯一值 for col in df.columns: if df[col].nunique() == 1: dropped_dict[col] = df[col].iloc[0] # 统一删除收集到的列 cleaned_df = df.drop(dropped_dict.keys(), axis=1) return pd.Series(dropped_dict), cleaned_df
这种方式逻辑更清晰,不会像原while循环那样因为删除列导致后续索引错位,降低出错概率。
3. 用.apply方法实现
可以用apply给每一列做单值判断,再基于结果处理:
# 定义判断单值列的辅助函数 def is_single_value_col(col): return col.nunique() == 1 def drop_monocols(df): # 用apply标记每一列是否为单值列 mono_col_mask = df.apply(is_single_value_col) # 筛选出单值列的列名 mono_cols = mono_col_mask[mono_col_mask].index # 提取唯一值并清理DataFrame dropped_series = df.loc[0, mono_cols] cleaned_df = df.drop(mono_cols, axis=1) return dropped_series, cleaned_df
df.apply(is_single_value_col)会对每一列执行判断函数,返回一个布尔Series,后续操作和第一种简洁方式一致,适合需要拆分逻辑的场景。
另外提醒:尽量避免在循环中直接修改原DataFrame的结构(比如原while循环里逐列删除),先收集目标列再统一处理是pandas编程的常规好习惯。
内容的提问来源于stack exchange,提问作者Richard Downhard
相关产品推荐
相关产品推荐

