为何函数内拼接DataFrame列名生成的字符串列表会报错?
问题:函数内列表推导报错,函数外执行正常的原因?
我遇到一个无法解释的问题:在函数内外执行列表拼接时结果不同。具体来说,我尝试在函数内基于DataFrame列名拼接字符串列表会报错,但在函数外执行却完全正常。示例如下:
【示例】假设我要编写一个函数,返回DataFrame某列的多个滞后值,并基于原列名为滞后变量分配新名称,代码如下:
import pandas as pd import numpy as np rng = np.random.default_rng(22222222) df = pd.DataFrame({'X':rng.random(10)}) print(df)
输出:
X 0 0.279384 1 0.838032 2 0.298536 3 0.056188 4 0.532023 5 0.560038 6 0.127512 7 0.322774 8 0.813949 9 0.245242
编写函数:
def lagger(column, lags): #Takes as input a DataFrame column in the form df[colname] lags = [column.shift(i) for i in range(1, lags+1)] df = pd.concat(lags, axis=1) #a DataFrame with a column for each lag. names = [f"{column.name}_L{i}" for i in range(1,lags+1)] #generate new names df.rename(names, axis='columns', inplace=True) return df
测试函数时出现如下错误:
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[27], line 1 ----> 1 lagger(df['X'], 3) Cell In[25], line 6 2 lags = [column.shift(i) for i in range(1, lags+1)] 4 df = pd.concat(lags, axis=1) #a DataFrame with a column for each lag. ----> 6 names = [f"{column.name}_L{i}" for i in range(1,lags+1)] #generate new names 8 df.rename(names, axis='columns', inplace=True) 10 return df TypeError: can only concatenate list (not "int") to list
但在函数外执行类似的列表推导式却能正常运行:
[f"{df['X'].name}_L{i}" for i in range(1,4)]
输出:
['X_L1', 'X_L2', 'X_L3']
我已了解生成多个滞后值的实现方法,现仅询问:为何函数内执行[f"{column.name}_L{i}" for i in range(1,lags+1)]会失败,而函数外执行[f"{df['X'].name}_L{i}" for i in range(1,4)]却正常?
解答
核心原因是你在函数内部覆盖了参数lags的变量类型:
- 函数定义时,
lags是传入的整数参数(比如调用时的3) - 但函数第一行代码
lags = [column.shift(i) for i in range(1, lags+1)]把lags从整数改成了列表对象 - 后续执行
range(1,lags+1)时,lags已经是列表,尝试用列表加整数(lags+1)就会触发TypeError——这就是报错的直接原因
而函数外的代码中,你用的是明确的整数4,range(1,4)是合法操作,所以不会报错。
如果要修复这个问题,只需要把第一行的变量名改成不与参数重名的名称,比如lag_columns:
def lagger(column, lags): lag_columns = [column.shift(i) for i in range(1, lags+1)] # 重命名变量,避免覆盖参数 df = pd.concat(lag_columns, axis=1) names = [f"{column.name}_L{i}" for i in range(1,lags+1)] df.rename(names, axis='columns', inplace=True) return df
内容的提问来源于stack exchange,提问作者thagomizer
相关产品推荐
相关产品推荐

