遍历Pandas DataFrame遇KeyError:11,求Numpy数组构建X的方案
我正在对一份包含公寓面积与租金的数据集进行线性回归建模,模型形式为:
$\hat{y}=xT\theta$,其中$xT=(x_1,x_2,...,x_N)$,$\hat{y}^T=(\hat{y}_1,\hat{y}2,...,\hat{y}N)$
在本场景中,$x_i^T=(1, v{i1})$,$v{i1}$为第i套公寓的面积,因此$\hat{y}i=x_i^T\theta=\theta_0 + \theta_1×v{i1}$
我们定义模型的经验风险$E=\sum_1n||x_iT\theta−y_i||²$,目标是找到最小化E的$\theta$:$\hat{\theta}=\text{argmin}_\theta E$
课程中使用np.matrix构建特征矩阵X的代码如下:
import numpy as np import pandas as pd import matplotlib.pyplot as plt house_data = pd.read_csv('house.csv') X = np.matrix([np.ones(house_data.shape[0]), house_data['surface'].values]).T y = np.matrix(house_data['loyer']).T theta = np.linalg.inv(X.T.dot(X)).dot(X.T).dot(y) print(theta)
我尝试用np.array替代np.matrix构建X,编写了循环代码,但前11次迭代正常,之后出现KeyError:11。我的完整代码如下:
import numpy as np import matplotlib.pyplot as plt import pandas as pd house_data = pd.read_csv('house.csv') house_data = house_data[house_data['loyer']<10000] x = house_data['surface'] y = house_data['loyer'] X = [] for i in range(len(x)): A = [1,x[i]] X.append(A)
现咨询:KeyError:11的原因是什么?如何用np.array正确构建等价的特征矩阵X?
KeyError:11的原因
过滤数据house_data = house_data[house_data['loyer']<10000]后,数据集的行索引不再是连续的0-based序列(原索引为11的行被过滤移除)。但循环时用range(len(x))生成连续整数作为索引,当i=11时,尝试通过x[i]访问Series元素,而此时Series的索引中不存在11,因此抛出KeyError。
核心问题:过滤后的Series保留了原数据集的索引,循环使用的连续位置序号与实际索引值不匹配,导致索引访问失败。
用np.array正确构建特征矩阵X的方法
方法1:无循环直接拼接(推荐)
利用numpy的数组拼接函数直接构造带截距项的特征矩阵,无需循环,效率更高且避免索引问题:
import numpy as np import pandas as pd house_data = pd.read_csv('house.csv') house_data = house_data[house_data['loyer'] < 10000] # 构造全1数组与面积列拼接 # 方式1:用hstack ones = np.ones((house_data.shape[0], 1)) surface_col = house_data['surface'].values.reshape(-1, 1) X = np.hstack([ones, surface_col]) # 方式2:用column_stack更简洁 X = np.column_stack((np.ones(len(house_data)), house_data['surface'])) # 构造目标变量y的数组 y = house_data['loyer'].values.reshape(-1, 1) # 计算最优theta theta = np.linalg.inv(X.T @ X) @ X.T @ y print(theta)
方法2:保留循环,修改索引访问方式
通过iloc按位置访问Series元素,而非按索引值访问,适配过滤后的非连续索引:
import numpy as np import pandas as pd house_data = pd.read_csv('house.csv') house_data = house_data[house_data['loyer'] < 10000] x = house_data['surface'] y = house_data['loyer'] X = [] for i in range(len(x)): # 用iloc[i]按位置取值,不受索引值影响 A = [1, x.iloc[i]] X.append(A) # 将列表转换为numpy数组 X = np.array(X)
内容的提问来源于stack exchange,提问作者TB01

