PyTorch构建神经网络时y_train转张量类型错误的解决方法
解决PyTorch转换y_train为张量时的类型错误
问题根源
- 威斯康星乳腺癌数据集的目标变量(diagnosis)是字符串类型(M=恶性,B=良性),并非你所说的数值型,直接转float32会触发类型错误。
- 单独对
y_train执行dropna(),会导致X_train和y_train样本数量不一致,后续批量训练会出现索引不匹配问题。 - 未编码的字符串目标变量会让
y_train.values成为numpy.object_类型,PyTorch不支持直接转换该类型为张量。
修复步骤
1. 对目标变量做数值编码
将字符串诊断结果转换为0/1数值:
# 替换原y定义部分 y = pd.DataFrame(breast_cancer_wisconsin_diagnostic.data.targets) # 良性B转0,恶性M转1 y['diagnosis'] = y['diagnosis'].map({'B': 0, 'M': 1})
2. 同步处理缺失值
不要单独删除y的缺失样本,拆分数据集前统一处理所有缺失值:
# 合并特征与目标变量后统一删缺失值 df = pd.concat([X, y], axis=1) df = df.dropna() X = df.drop('diagnosis', axis=1) y = df['diagnosis'] # 再执行数据集拆分 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
3. 正确转换为PyTorch张量
此时y_train已为数值型,用to_numpy()转换更稳妥:
y_train_tensor = torch.tensor(y_train.to_numpy(), dtype=torch.float32).view(-1, 1) y_test_tensor = torch.tensor(y_test.to_numpy(), dtype=torch.float32).view(-1, 1)
完整修改后的代码
import pandas as pd import torch import torch.nn as nn import torch.optim as optim from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from ucimlrepo import fetch_ucirepo breast_cancer_wisconsin_diagnostic = fetch_ucirepo(id=17) X = pd.DataFrame(breast_cancer_wisconsin_diagnostic.data.features) y = pd.DataFrame(breast_cancer_wisconsin_diagnostic.data.targets) # 关键修改1:对目标变量做数值编码 y['diagnosis'] = y['diagnosis'].map({'B': 0, 'M': 1}) # 关键修改2:统一处理缺失值 df = pd.concat([X, y], axis=1) df = df.dropna() X = df.drop('diagnosis', axis=1) y = df['diagnosis'] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) scaler = StandardScaler() X_train = scaler.fit_transform(X_train) X_test = scaler.transform(X_test) X_train_tensor = torch.tensor(X_train, dtype=torch.float32) X_test_tensor = torch.tensor(X_test, dtype=torch.float32) # 关键修改3:正确转换张量 y_train_tensor = torch.tensor(y_train.to_numpy(), dtype=torch.float32).view(-1, 1) y_test_tensor = torch.tensor(y_test.to_numpy(), dtype=torch.float32).view(-1, 1) class NeuralNetwork(nn.Module): def __init__(self): super(NeuralNetwork, self).__init__() self.fc1 = nn.Linear(X_train.shape[1], 16) self.fc2 = nn.Linear(16, 8) self.fc3 = nn.Linear(8, 1) self.relu = nn.ReLU() def forward(self, x): x = self.relu(self.fc1(x)) x = self.relu(self.fc2(x)) x = torch.sigmoid(self.fc3(x)) return x model = NeuralNetwork() loss_fn = nn.BCELoss() optimizer = optim.Adam(model.parameters(), lr=0.001) n_epochs = 100 batch_size = 10 for epoch in range(n_epochs): model.train() for i in range(0, len(X_train_tensor), batch_size): X_batch = X_train_tensor[i:i+batch_size] y_batch = y_train_tensor[i:i+batch_size] optimizer.zero_grad() y_pred = model(X_batch) loss = loss_fn(y_pred, y_batch) loss.backward() optimizer.step() print(f'Finished epoch {epoch+1}, latest loss: {loss.item():.4f}') model.eval() with torch.no_grad(): y_test_pred = model(X_test_tensor) y_test_pred_classes = (y_test_pred > 0.5).float() accuracy = (y_test_pred_classes.eq(y_test_tensor).sum().item()) / len(y_test_tensor) print(f'Accuracy on test set: {accuracy * 100:.2f}%')
内容的提问来源于stack exchange,提问作者bahar homayoun
相关产品推荐
相关产品推荐

