使用scikit-learn LabelEncoder编码数据时遇TypeError问题求助
TypeError: unhashable type: 'list'问题 首先看你给出的报错核心信息:
TypeError: unhashable type: 'list'
...
TypeError: argument must be a string or number
这个错误的根源是你的标签数据被存成了列表类型,而sklearn.preprocessing.LabelEncoder只能处理可哈希的单个值(比如字符串、数字),无法处理列表作为输入。
问题出在哪里?
看你读取数据的这段代码:
for i ,line in enumerate(data.split("\n")): content = line.split('",') texts.append(content[0]) labels.append(content[1:]) # 这里是关键错误!
content[1:]会返回一个列表(哪怕该位置只有一个元素),比如一行数据的标签是"spam",split后content[1:]会变成['spam'],而不是单个字符串'spam'。当LabelEncoder尝试处理这些列表时,就会抛出"不可哈希类型"的错误。
一步步修复方案
1. 修正标签读取逻辑
如果你每个样本只有一个标签,应该直接取content[1]而不是content[1:],同时清理掉残留的引号和换行符:
data = open('dataset.csv').read() labels = [] texts = [] for i ,line in enumerate(data.split("\n")): # 跳过空行避免索引错误 if not line.strip(): continue content = line.split('",') # 清理文本开头的引号(比如第一个元素可能是"hello world) texts.append(content[0].strip('"')) # 提取单个标签,清理引号和换行 raw_label = content[1].strip('"\n') labels.append(raw_label)
2. 不要重复训练LabelEncoder
你现在对训练集和验证集分别调用了fit_transform,这会导致编码规则不一致(比如训练集的"positive"可能被编码为0,验证集的"positive"可能因为fit时的顺序变成1)。正确的做法是只在训练集上拟合编码器,再用它转换验证集:
encoder = preprocessing.LabelEncoder() train_y = encoder.fit_transform(train_y) valid_y = encoder.transform(valid_y) # 这里用transform,不要fit_transform
3. 修正特征提取器的列名错误
你的代码里写了count_vect.fit(trainDF['texts']),但DataFrame的列名是text(你定义的trainDF['text'] = texts),这里会抛出KeyError,要改成:
count_vect = CountVectorizer(analyzer='word', token_pattern=r'\w{1,}') count_vect.fit(trainDF['text']) # 是text不是texts xtrain_count = count_vect.transform(train_x) xvalid_count = count_vect.transform(valid_x) tfidf_vect = TfidfVectorizer(analyzer='word', token_pattern=r'\w{1,}', max_features=5000) tfidf_vect.fit(trainDF['text']) # 同样修正列名 xtrain_tfidf = tfidf_vect.transform(train_x) xvalid_tfidf = tfidf_vect.transform(valid_x)
4. 更可靠的CSV读取方式(可选推荐)
手动split读取CSV很容易出错(比如文本里包含逗号的情况),推荐直接用pandas的read_csv方法,它会自动处理引号和分隔符:
# 假设你的CSV第一行是表头:text,label trainDF = pandas.read_csv('dataset.csv', quotechar='"', escapechar='\\') # 直接获取text和label列,不需要手动循环处理 train_x, valid_x, train_y, valid_y = model_selection.train_test_split( trainDF['text'], trainDF['label'], test_size=0.2, random_state=0 )
修正后的完整代码示例
from sklearn import model_selection, preprocessing, linear_model, naive_bayes, metrics, svm from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer from sklearn import decomposition, ensemble import pandas, xgboost, numpy, string # 推荐用pandas读取CSV trainDF = pandas.read_csv('dataset.csv', quotechar='"', escapechar='\\') # 划分训练集和验证集 train_x, valid_x, train_y, valid_y = model_selection.train_test_split( trainDF['text'], trainDF['label'], test_size=0.2, random_state=0 ) # 编码标签 encoder = preprocessing.LabelEncoder() train_y = encoder.fit_transform(train_y) valid_y = encoder.transform(valid_y) # CountVectorizer特征提取 count_vect = CountVectorizer(analyzer='word', token_pattern=r'\w{1,}') count_vect.fit(trainDF['text']) xtrain_count = count_vect.transform(train_x) xvalid_count = count_vect.transform(valid_x) # TF-IDF特征提取 tfidf_vect = TfidfVectorizer(analyzer='word', token_pattern=r'\w{1,}', max_features=5000) tfidf_vect.fit(trainDF['text']) xtrain_tfidf = tfidf_vect.transform(train_x) xvalid_tfidf = tfidf_vect.transform(valid_x) # 训练模型(假设你有train_model函数,注意补充valid_y参数) accuracy = train_model(svm.SVC(), xtrain_tfidf, train_y, xvalid_tfidf, valid_y) print(accuracy)
内容的提问来源于stack exchange,提问作者Arnav Desai

