如何在未知列名的Pandas DataFrame中用f-string模板创建新列
解决Pandas动态模板生成新列的向量化方案
核心问题
需要基于未知列名和动态模板生成新列,但pd.eval不支持f-string语法,迭代行或普通apply又不够优雅高效。
最优方案:将f-string模板转换为pd.eval兼容表达式
pd.eval支持列名与字符串的向量化拼接,我们可以把用户提供的f-string模板转换为pd.eval能识别的表达式,实现高效的向量化操作。
步骤1:编写模板转换函数
这个函数会自动将f-string格式的模板转换成pd.eval支持的语法:
import re def fstring_to_eval_expr(template): # 移除f前缀和首尾引号,提取模板核心内容 content = template.strip().lstrip('f').strip('"').strip("'") # 分割模板中的列引用和固定字符串部分 parts = re.split(r'(\{[^}]+\})', content) expr_parts = [] for part in parts: if part.startswith('{') and part.endswith('}'): # 处理列引用,比如{col2}转为col2 col_name = part.strip('{}') expr_parts.append(col_name) else: # 处理固定字符串,用单引号包裹 if part: expr_parts.append(repr(part)) # 用+拼接所有部分,生成eval可执行的表达式 return ' + '.join(expr_parts)
步骤2:生成新列
以示例DataFrame为例:
import pandas as pd # 示例DataFrame df = pd.DataFrame({ 'col1': ['abc', 'ghi'], 'col2': ['def', 'jkl'] }) # 用户提供的f-string模板 template = 'f"{col2}_x"' # 转换模板为eval表达式 eval_expr = fstring_to_eval_expr(template) # eval_expr结果:'col2 + "_x"' # 向量化生成新列 df['new_col'] = df.eval(eval_expr)
执行后得到的结果:
col1 col2 new_col 0 abc def def_x 1 ghi jkl jkl_x
支持复杂模板
如果模板包含多列拼接或字符串方法,转换函数也能处理:
- 多列拼接模板:
template = 'f"{col1}-{col2}_suffix"'
转换后表达式:col1 + "-" + col2 + "_suffix" - 带字符串方法的模板:修改转换函数支持方法调用:
使用模板def fstring_to_eval_expr(template): content = template.strip().lstrip('f').strip('"').strip("'") pattern = re.compile(r'\{([^}]+)\}') def replace_match(match): inner = match.group(1) # 处理列的字符串方法,比如col1.upper()转为col1.str.upper() if '.' in inner: col, method = inner.split('.', 1) return f"{col}.str.{method}" return inner replaced = pattern.sub(replace_match, content) parts = re.split(r'([a-zA-Z0-9_.]+)', replaced) expr_parts = [] for part in parts: if part and not re.match(r'[a-zA-Z0-9_.]+', part): expr_parts.append(repr(part)) elif part: expr_parts.append(part) return ' + '.join(expr_parts)template = 'f"{col1.upper()}_{col2}"',会生成表达式col1.str.upper() + "_" + col2,最终得到ABC_def、GHI_jkl的结果。
备选方案:小数据集用apply
如果数据集很小,或者模板逻辑过于复杂(比如包含条件判断),可以直接用apply:
df['new_col'] = df.apply(lambda row: template.strip().lstrip('f').format(**row), axis=1)
注意:这个方法是逐行处理,大数据集下效率远低于向量化的eval方案。
内容的提问来源于stack exchange,提问作者j0hn
相关产品推荐
相关产品推荐

