pandasql调用ISNUMERIC报错 非数值行更新Flag列实现咨询
问题说明
需实现DataFrame行级数值校验:逐行判断P1列取值是否为数值,非数值行的Flag列标记为Error,数值行Flag留空。
测试用初始数据:
import pandas as pd data = {'P1': [0, 'ABC', 1.1]} originaldf = pd.DataFrame(data)
预期输出:
| P1 | Flag |
|---|---|
| 0 | |
| ABC | Error |
| 1.1 |
之前方案失效的核心原因
- 调用
ISNUMERIC报错:pandasql底层基于SQLite实现,SQLite无内置该TSQL函数,无法直接调用。 LIKE '%[A-Za-z]%'匹配无结果:SQLite的LIKE语法不支持[]形式的字符范围匹配,该语法仅适用于SQL Server等特定数据库。iterrows()遍历不生效:一是用==和通配符字符串做全等判断,不会触发模糊匹配逻辑;二是iterrows返回的行对象是副本,直接修改不会同步到原DataFrame。另外原有SQL中ISNUMERIC(P1) < 0的判断逻辑本身错误,常规ISNUMERIC匹配成功返回1、失败返回0,不存在小于0的返回值。
实现方案
方案1:原生Pandas实现(优先选择,性能最好)
直接利用pandas内置的类型转换能力做判断,无需依赖SQL或遍历:
import pandas as pd import numpy as np data = {'P1': [0, 'ABC', 1.1]} originaldf = pd.DataFrame(data) originaldf['Flag'] = np.where( # 尝试将P1转为数值,转换失败的值会被置为NaN pd.to_numeric(originaldf['P1'], errors='coerce').isna(), 'Error', '' )
执行后输出完全符合预期。
方案2:pandasql环境实现
如果必须使用sqldf编写SQL逻辑,可以先向SQLite引擎注册自定义数值判断函数,再在SQL中调用:
import pandas as pd import pandasql as ps data = {'P1': [0, 'ABC', 1.1]} originaldf = pd.DataFrame(data) # 定义数值判断函数 def is_numeric(val): try: float(val) return 1 except (ValueError, TypeError): return 0 # 注册自定义函数到SQLite conn = ps.SQLiteConnection() conn.conn.create_function("isnumeric", 1, is_numeric) # 执行查询 newdf = ps.sqldf(''' SELECT *, CASE WHEN isnumeric(P1) = 0 THEN 'Error' ELSE '' END AS Flag FROM originaldf ''', conn=conn)
方案3:修正逐行遍历逻辑(不推荐,大数据量下性能极差,仅做写法纠错)
若坚持使用iterrows遍历,需要通过loc做值回写,且不能用通配符字符串做全等判断:
originaldf['Flag'] = '' for idx, row in originaldf.iterrows(): try: float(row['P1']) except ValueError: originaldf.loc[idx, 'Flag'] = 'Error'
内容的提问来源于stack exchange,提问作者smitty_werben_jagerm
相关产品推荐
相关产品推荐

