You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python从零实现KNN算法遇类型错误:字符串无法减法运算求助

解决KNN实现中的TypeError及数据处理问题

看起来你已经找对了方向——数据类型确实是核心问题!咱们一步步拆解解决:

1. 报错根源:字符串类型无法做数值运算

你的错误TypeError: unsupported operand type(s) for -: 'str' and 'str'非常明确:用来计算距离的特征数据是字符串/字节类型,没法执行减法、平方这些数值运算。你怀疑要转成float是完全正确的,不过还要注意ARFF数据加载后的特殊处理。

2. 先处理ARFF数据的类型问题

用scipy.io.arff.loadarff加载数据后,字符串类型的字段会被解析成bytes格式(比如b'1.23'),需要先解码再转换为数值类型。你可以批量处理训练集和测试集:

from scipy.io import arff
import pandas as pd
import numpy as np
import math

# 加载并处理训练集
data_train = arff.loadarff('train.arff')
train = pd.DataFrame(data_train[0])

# 批量转换字节/字符串为数值类型
for col in train.columns:
    if train[col].dtype == 'object':
        # 先解码字节为普通字符串
        train[col] = train[col].str.decode('utf-8')
        # 尝试转为float(标签列或分类特征会报错,跳过即可)
        try:
            train[col] = train[col].astype(float)
        except ValueError:
            pass

# 同样处理测试集
data_test = arff.loadarff('test1.arff')
test = pd.DataFrame(data_test[0])
for col in test.columns:
    if test[col].dtype == 'object':
        test[col] = test[col].str.decode('utf-8')
        try:
            test[col] = test[col].astype(float)
        except ValueError:
            pass

3. 修正train_test_split的误用

你现在的用法完全错了!train_test_split是用来把单个数据集拆分成训练集和验证集,而不是把两个独立的数据集(train和test)传进去。正确的做法是:

  • 先从你的训练集里拆分出特征(X)和标签(y)
  • 再拆分训练集和验证集;如果已经有单独的测试集,直接用测试集即可
from sklearn.model_selection import train_test_split  # 注意:sklearn.cross_validation已废弃,改用model_selection

# 假设你的数据集最后一列是标签,替换成你实际的标签列名
label_col = 'your_label_column_name'

# 拆分训练集的特征和标签
X_train_full = train.drop(label_col, axis=1)
y_train_full = train[label_col]

# 拆分训练集和验证集(可选,如果你需要用一部分训练数据做验证)
X_train, X_val, y_train, y_val = train_test_split(X_train_full, y_train_full, test_size=0.1, random_state=42)

# 处理测试集的特征和标签
X_test = test.drop(label_col, axis=1)
y_test = test[label_col]

4. 修正代码里的两个小bug

  • distance函数的笔误:你写的是return dis,但变量名是dist,这会导致未定义错误
  • 遍历DataFrame的错误:直接for testpoint in X_test会遍历列名,而不是每行数据,需要用.values获取每行的数值数组

修正后的函数:

def distance(testpoint, trainpoint): 
    # 计算测试点与训练点之间的距离
    dist = np.sqrt(np.sum(np.power(testpoint-trainpoint, 2)))
    return dist  # 修正笔误:返回dist而不是dis

def getNeighbors(X_train, y_train, X_test, k): 
    k_neighbors_with_labels = [] 
    for testpoint in X_test.values:  # 用.values获取每行的数值数组
        distances_label = [] 
        for (trainpoint,y_train_label) in zip(X_train.values, y_train): 
            distances_label.append((distance(testpoint, trainpoint), y_train_label))
        # 排序后取前k个最近邻
        k_neighbors_with_labels.append(sorted(distances_label)[0:k]) 
    return k_neighbors_with_labels

# 调用函数(如果用验证集就传X_val、y_val,用测试集就传X_test、y_test)
ne = getNeighbors(X_train, y_train, X_val, k = 3)
print(ne)

最后检查

运行前可以先打印X_train.dtypes和X_test.dtypes,确认所有特征列都是float64或者int64类型,这样就能正常执行数值运算了。

内容的提问来源于stack exchange,提问作者Meg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:47:37