如何高效移除Pandas DataFrame中包含非数值的行?
高效清理含非数值基因表达数据的DataFrame行
我手上有个存储患者基因表达数据的DataFrame,结构大概是这样:
Patient_ID | gene1 | gene2 | ... | gene10000 p1 0.142 0.233 ... bla p2 0.243 0.243 ... -0.364 ... p4000 1.423 bla ... -1.222
里面混了不少非数值的噪声值,我需要删掉所有包含非数值的行。之前用下面的代码实现,但跑起来慢得离谱:
cols = df.columns[1:] df[cols] = df[cols].apply(pd.to_numeric, errors='coerce') df = df.dropna()
附测试数据复现代码(修正了原代码中行数不匹配的问题):
import numpy as np import pandas as pd arr = np.random.random_sample((3000,10000)) df = pd.DataFrame(arr, columns=['gene' + str(i) for i in range(10000)]) df = pd.concat([pd.DataFrame(['p' + str(i) for i in range(3000)], columns=['Patient_ID']),df],axis = 1) df.loc[2, 'gene0'] = 'bla' df.loc[4, 'gene9998'] = 'bla'
为什么原代码这么慢?
原代码里的apply(pd.to_numeric)是逐列循环处理,面对10000列的大数据量,循环次数直接拉满,效率自然低。
更高效的实现方案
方案1:堆叠转换(大幅减少循环次数)
把所有基因列堆叠成单个Series,一次性完成数值转换,再还原回原结构。这种方式只需要一次转换操作,而不是10000次:
cols = df.columns[1:] # 堆叠→批量转换→还原 df[cols] = df[cols].stack().apply(pd.to_numeric, errors='coerce').unstack() df_clean = df.dropna()
方案2:逐行检测过滤(避免全量转换)
如果不需要保留转换后的数值,只是想过滤掉不合格的行,可以直接逐行检查所有基因列是否都是数值,不用全量转换整个DataFrame,能省不少内存和时间:
cols = df.columns[1:] def is_numeric(val): try: float(val) return True except (ValueError, TypeError): return False # 生成有效行的掩码 valid_rows = df[cols].apply(lambda row: all(is_numeric(x) for x in row), axis=1) df_clean = df[valid_rows].copy()
方案3:字典推导式逐列转换(比apply更高效)
用字典推导式手动循环列执行pd.to_numeric,比apply的内部循环在大数据量下表现更好:
cols = df.columns[1:] df[cols] = pd.DataFrame({col: pd.to_numeric(df[col], errors='coerce') for col in cols}) df_clean = df.dropna()
内容的提问来源于stack exchange,提问作者sagi
相关产品推荐
相关产品推荐

