在含时间戳层级的多索引列中使用pd.eval函数失败的问题
解决多索引列含datetime层级时的pd.eval访问问题
问题核心在于:多索引列的第一层级是datetime对象,无法通过.属性访问的方式在pd.eval中引用这类列——因为datetime(2020,5,17)这类表达式不是合法的Python标识符,不能作为DataFrame的属性名。
解决方案1:修改pd.eval查询字符串为索引访问格式
将列的点访问格式转换为df.loc[:, (datetime对象, 层级2, 层级3)]的索引访问格式,让pd.eval能正确解析多索引列。
修改后的完整代码:
import pandas as pd from datetime import datetime cols = pd.MultiIndex.from_tuples([(datetime(2020, 5, 17), "A1", "A"), (datetime(2020, 5, 17), "B1", "B")]) data = [[5, 10], [2, 15], [6, 14]] df = pd.DataFrame(data, columns=cols) # 定义函数,将点格式的列字符串转换为loc索引访问格式 def format_multi_col(s): parts = s.split('.') dt_expr, level2, level3 = parts[0], parts[1], parts[2] return f"df.loc[:, ({dt_expr}, '{level2}', '{level3}')]" lst = [5, '*', 'datetime(2020, 5, 17).A1.A'] # 生成合法的pd.eval查询语句 query = ''.join([format_multi_col(x) if (isinstance(x, str) and '.' in x) else str(x) for x in lst]) # 定义新列的第一层级key(需与实际需求匹配) key = datetime(2020, 5, 17) # 执行计算并赋值新列 df[(key, 'N1', 'N')] = pd.eval(query) print(df)
解决方案2:直接处理元素计算(避免pd.eval)
如果不需要使用pd.eval,可直接解析lst中的元素,用Python原生运算符完成计算,更安全直观:
import pandas as pd from datetime import datetime from operator import mul cols = pd.MultiIndex.from_tuples([(datetime(2020, 5, 17), "A1", "A"), (datetime(2020, 5, 17), "B1", "B")]) data = [[5, 10], [2, 15], [6, 14]] df = pd.DataFrame(data, columns=cols) lst = [5, '*', 'datetime(2020, 5, 17).A1.A'] # 映射运算符 op_map = {'*': mul} # 处理lst中的每个元素 processed = [] for item in lst: if isinstance(item, str) and '.' in item: # 拆分多索引列信息 dt_str, l2, l3 = item.split('.') # 解析datetime对象 dt = eval(dt_str) # 获取对应的列 processed.append(df[(dt, l2, l3)]) else: processed.append(item) # 执行计算 result = op_map[processed[1]](processed[0], processed[2]) key = datetime(2020, 5, 17) df[(key, 'N1', 'N')] = result print(df)
两种方案都能解决datetime层级多索引列的访问问题:方案2避免了pd.eval的潜在安全风险,适合简单计算场景;方案1保留了pd.eval的使用,适合复杂表达式场景。
内容的提问来源于stack exchange,提问作者Thanasis
相关产品推荐
相关产品推荐

