Traceback (most recent call last): File "C:\Users\lenovo\AppData\Local\Programs\Python\Python312\Lib\site-packages\pandas\core\indexes\base.py", line 3805, in get_loc return self._engine.get_loc(casted_key) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "index.pyx", line 167, in pandas._libs.index.IndexEngine.get_loc File "index.pyx", line 196, in pandas._libs.index.IndexEngine.get_loc File "pandas\\_libs\\hashtable_class_helper.pxi", line 7081, in pandas._libs.hashtable.PyObjectHashTable.get_item File "pandas\\_libs\\hashtable_class_helper.pxi", line 7089, in pandas._libs.hashtable.PyObjectHashTable.get_item KeyError: '文物采样点' The above exception was the direct cause of the following exception: Traceback (most recent call last): File "C:\Users\lenovo\Desktop\数学建模竞赛\暑期培训\2022-cumcm-古代玻璃制品的成分分析与鉴别\解题\Archaeological Glass Classification.py", line 296, in <module> main() File "C:\Users\lenovo\Desktop\数学建模竞赛\暑期培训\2022-cumcm-古代玻璃制品的成分分析与鉴别\解题\Archaeological Glass Classification.py", line 266, in main df_train, df_test, features = load_and_preprocess_data() ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\lenovo\Desktop\数学建模竞赛\暑期培训\2022-cumcm-古代玻璃制品的成分分析与鉴别\解题\Archaeological Glass Classification.py", line 41, in load_and_preprocess_data df_test['文物编号'] = df_test['文物采样点'].apply(extract_id) # 使用相同的提取函数 ~~~~~~~^^^^^^^^^^^^^^ File "C:\Users\lenovo\AppData\Local\Programs\Python\Python312\Lib\site-packages\pandas\core\frame.py", line 4102, in __getitem__ indexer = self.columns.get_loc(key) ^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\lenovo\AppData\Local\Programs\Python\Python312\Lib\site-packages\pandas\core\indexes\base.py", line 3812, in get_loc raise KeyError(key) from err KeyError: '文物采样点
时间: 2025-07-08 13:14:13 浏览: 6
<think>根据错误信息,`KeyError: '文物采样点'`,这意味着在`df_test`中找不到名为'文物采样点'的列。这可能是由于Excel文件中表单3的列名与代码中使用的列名不一致导致的。
我们需要检查Excel文件中表单3的列名。在代码中,我们假设表单3中有一个名为'文物采样点'的列,但实际可能不同。例如,可能是'文物采样点'、'采样点'或其他名称。
解决方案:
1. 打开Excel文件,查看表单3的列名。
2. 修改代码,使用正确的列名。
如果确认表单3的列名确实不是'文物采样点',而是其他名称,比如可能是'文物采样点'(注意空格)或'文物采样点'(注意全半角),那么我们需要在代码中做相应调整。
另外,在读取Excel时,我们使用了`header=0`,即第一行为列名。但是,原始数据的第一行可能是标题,第二行是单位,我们之前已经跳过了标题行(使用`iloc[1:]`),所以列名应该是第一行的内容。
我们可以先打印出读取后的`df_test`的列名,看看实际读取到的列名是什么。
修改`load_and_preprocess_data`函数,在读取表单3后打印列名:
```python
df_test = pd.read_excel('2022-C题-附件-CLR变换后.xlsx', sheet_name='表单3', header=0)
print("表单3的列名:", df_test.columns.tolist())
```
然后根据实际列名修改代码。
但是,为了避免每次运行都要手动检查,我们可以编写一个健壮的方法,尝试匹配可能的列名。
例如,我们可以尝试以下候选列名:
候选列名 = ['文物采样点', '文物采样点 ', '文物采样点(部位)', '采样点', '文物编号']
如果上述方法不可行,我们可以根据位置来选取列(因为表单3的第一列应该就是文物采样点)。
另一种方案:直接使用第一列(索引0)作为文物采样点。
修改代码:
将`df_test['文物采样点']`改为`df_test.iloc[:, 0]`,即第一列。
但是,这样会使得代码可读性降低,而且如果列顺序变化就会出错。
综合考虑,我建议先打印列名,然后根据实际情况调整。
不过,根据题目附件,表单3的列名应该是“文物采样点”,所以可能是读取时出现了空格或不可见字符。
我们可以使用模糊匹配列名,例如:
```python
# 在读取df_test后
# 模糊匹配列名
possible_columns = ['文物采样点', '文物采样点 ', '文物采样点(部位)', '采样点']
for col in possible_columns:
if col in df_test.columns:
df_test.rename(columns={col: '文物采样点'}, inplace=True)
break
else:
# 如果没有匹配到,则使用第一列
df_test.rename(columns={df_test.columns[0]: '文物采样点'}, inplace=True)
```
这样,我们尝试将匹配到的列重命名为统一的'文物采样点',如果都不匹配,则将第一列重命名为'文物采样点'。
下面我们修改`load_and_preprocess_data`函数中的相关部分。
另外,注意在读取表单2时也可能存在同样的问题,所以我们同样处理表单2。
修改后的代码:
在读取表单2和表单3后,都进行列名模糊匹配。
同时,为了确保表单1的列名正确,我们也检查一下。表单1中我们使用了'文物编号'和'表面风化',同样需要确保存在。
由于时间关系,我们只处理表单2和表单3的'文物采样点'列。
修改后的`load_and_preprocess_data`函数(部分):
```python
# 读取表单2:已分类文物化学成分
df_train = pd.read_excel('2022-C题-附件-CLR变换后.xlsx', sheet_name='表单2', header=0)
df_train = df_train.iloc[1:] # 跳过标题行
# 模糊匹配列名,将文物采样点的列名统一为'文物采样点'
possible_columns = ['文物采样点', '文物采样点 ', '文物采样点(部位)', '采样点']
for col in possible_columns:
if col in df_train.columns:
df_train.rename(columns={col: '文物采样点'}, inplace=True)
break
else:
# 如果没有匹配到,则使用第一列
df_train.rename(columns={df_train.columns[0]: '文物采样点'}, inplace=True)
# 同样的方式处理表单3
df_test = pd.read_excel('2022-C题-附件-CLR变换后.xlsx', sheet_name='表单3', header=0)
df_test = df_test.iloc[1:] # 跳过标题行
for col in possible_columns:
if col in df_test.columns:
df_test.rename(columns={col: '文物采样点'}, inplace=True)
break
else:
df_test.rename(columns={df_test.columns[0]: '文物采样点'}, inplace=True)
```
这样,我们统一了列名为'文物采样点',然后就可以使用`df_test['文物采样点']`了。
此外,在提取文物编号的函数中,我们也要注意处理可能出现的异常。
下面给出修改后的完整代码,并添加注释。</think>### 错误分析:`KeyError: '文物采样点'`
这个错误发生在数据预处理阶段,具体在`load_and_preprocess_data()`函数中尝试访问`df_test['文物采样点']`列时。错误表明在表单3(未知文物化学成分)中不存在名为"文物采样点"的列。
### 问题原因:
1. **列名不一致**:
- 表单3(未知文物化学成分)的列名可能与表单2(已分类文物化学成分)不同
- Excel文件中的列名可能包含空格、特殊字符或不同命名方式
2. **数据读取问题**:
- 使用`header=0`参数可能没有正确识别列名
- Excel文件可能有合并单元格或其他格式问题
3. **列位置变化**:
- 表单3中"文物采样点"信息可能位于不同列位置
- 数据格式在表单间不一致
### 解决方案:
#### 方法1:检查并统一列名
```python
def load_and_preprocess_data():
# ...其他代码不变...
# 读取表单3:未知文物化学成分
df_test = pd.read_excel('2022-C题-附件-CLR变换后.xlsx', sheet_name='表单3', header=0)
df_test = df_test.iloc[1:] # 跳过标题行
# 打印列名以进行调试
print("表单3的列名:", df_test.columns.tolist())
# 尝试可能的列名变体
possible_names = ['文物采样点', '文物采样点 ', '采样点', '文物点', '文物采样位置']
sample_point_col = None
for name in possible_names:
if name in df_test.columns:
sample_point_col = name
break
if sample_point_col is None:
# 如果找不到匹配列名,尝试第一列
sample_point_col = df_test.columns[0]
print(f"警告: 未找到'文物采样点'列, 使用第一列 '{sample_point_col}' 代替")
# 使用确定的列名
df_test['文物采样点'] = df_test[sample_point_col]
# ...后续代码...
```
#### 方法2:基于列位置访问
```python
def load_and_preprocess_data():
# ...其他代码不变...
# 读取表单3:未知文物化学成分
df_test = pd.read_excel('2022-C题-附件-CLR变换后.xlsx', sheet_name='表单3', header=0)
df_test = df_test.iloc[1:] # 跳过标题行
# 假设"文物采样点"信息在第一列
df_test['文物采样点'] = df_test.iloc[:, 0]
# ...后续代码...
```
#### 方法3:使用更健壮的列名处理
```python
def load_and_preprocess_data():
# ...其他代码不变...
# 读取表单3:未知文物化学成分
df_test = pd.read_excel('2022-C题-附件-CLR变换后.xlsx', sheet_name='表单3', header=0)
df_test = df_test.iloc[1:] # 跳过标题行
# 标准化列名:去除空格和特殊字符
df_test.columns = [col.strip().replace(' ', '').replace('\n', '') for col in df_test.columns]
# 尝试匹配列名
if '文物采样点' in df_test.columns:
sample_col = '文物采样点'
elif '采样点' in df_test.columns:
sample_col = '采样点'
else:
sample_col = df_test.columns[0] # 使用第一列
df_test['文物采样点'] = df_test[sample_col]
# ...后续代码...
```
### 完整修改后的代码:
```python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import re
from sklearn.ensemble import RandomForestClassifier
from sklearn.decomposition import PCA
from sklearn.preprocessing import LabelEncoder
def load_and_preprocess_data():
"""加载并预处理数据,处理列名不一致问题"""
# 读取表单1:文物基本信息
df_info = pd.read_excel('2022-C题-附件-CLR变换后.xlsx', sheet_name='表单1', header=0)
df_info = df_info.iloc[1:] # 跳过标题行
df_info['文物编号'] = df_info['文物编号'].astype(str).str.strip()
# 读取表单2:已分类文物化学成分
df_train = pd.read_excel('2022-C题-附件-CLR变换后.xlsx', sheet_name='表单2', header=0)
df_train = df_train.iloc[1:] # 跳过标题行
# 标准化表单2列名
df_train.columns = [col.strip().replace(' ', '') for col in df_train.columns]
# 提取文物编号
def extract_id(x):
if pd.isna(x):
return None
if isinstance(x, str):
match = re.search(r'(\d+)', x)
if match:
return match.group(1)
return str(x)
df_train['文物编号'] = df_train['文物采样点'].apply(extract_id)
df_train['文物编号'] = df_train['文物编号'].str.strip()
# 关联表单1获取风化信息
df_train = pd.merge(df_train, df_info[['文物编号', '表面风化']], on='文物编号', how='left')
# 读取表单3:未知文物化学成分
df_test = pd.read_excel('2022-C题-附件-CLR变换后.xlsx', sheet_name='表单3', header=0)
df_test = df_test.iloc[1:] # 跳过标题行
# 标准化表单3列名
df_test.columns = [col.strip().replace(' ', '') for col in df_test.columns]
# 处理可能的列名变体
sample_col_candidates = ['文物采样点', '采样点', '文物点', '文物采样位置']
sample_col = None
for col in sample_col_candidates:
if col in df_test.columns:
sample_col = col
break
if sample_col is None:
# 如果找不到匹配列名,使用第一列
sample_col = df_test.columns[0]
print(f"警告: 未找到标准列名, 使用 '{sample_col}' 作为文物采样点")
df_test['文物采样点'] = df_test[sample_col]
df_test['文物编号'] = df_test['文物采样点'].apply(extract_id)
df_test['文物编号'] = df_test['文物编号'].str.strip()
# 特征列(14种化学成分)
features = [
'二氧化硅(SiO2)', '氧化钠(Na2O)', '氧化钾(K2O)', '氧化钙(CaO)', '氧化镁(MgO)',
'氧化铝(Al2O3)', '氧化铁(Fe2O3)', '氧化铜(CuO)', '氧化铅(PbO)', '氧化钡(BaO)',
'五氧化二磷(P2O5)', '氧化锶(SrO)', '氧化锡(SnO2)', '二氧化硫(SO2)'
]
# 转换数据类型
for col in features:
df_train[col] = pd.to_numeric(df_train[col], errors='coerce')
df_test[col] = pd.to_numeric(df_test[col], errors='coerce')
return df_train, df_test, features
# ... train_and_predict_by_weathering, visualize_results, main 函数保持不变 ...
```
### 关键修改说明:
1. **列名标准化**:
```python
# 去除空格和特殊字符
df_train.columns = [col.strip().replace(' ', '') for col in df_train.columns]
df_test.columns = [col.strip().replace(' ', '') for col in df_test.columns]
```
2. **列名智能匹配**:
```python
# 尝试可能的列名变体
sample_col_candidates = ['文物采样点', '采样点', '文物点', '文物采样位置']
sample_col = None
for col in sample_col_candidates:
if col in df_test.columns:
sample_col = col
break
```
3. **回退机制**:
```python
if sample_col is None:
# 如果找不到匹配列名,使用第一列
sample_col = df_test.columns[0]
print(f"警告: 未找到标准列名, 使用 '{sample_col}' 作为文物采样点")
```
4. **健壮的文物编号提取**:
```python
def extract_id(x):
if pd.isna(x):
return None
if isinstance(x, str):
match = re.search(r'(\d+)', x) # 提取数字部分
if match:
return match.group(1)
return str(x) # 处理非字符串类型
```
### 预防类似错误的建议:
1. **数据探索**:
```python
# 在读取数据后立即检查列名
print("表单2列名:", df_train.columns.tolist())
print("表单3列名:", df_test.columns.tolist())
```
2. **异常处理**:
```python
try:
df_test['文物采样点'] = df_test['文物采样点']
except KeyError:
# 处理列名缺失情况
df_test['文物采样点'] = df_test.iloc[:, 0]
```
3. **配置文件**:
```python
# 使用配置文件管理列名映射
column_mapping = {
'表单2': {'sample_point': '文物采样点', 'id': '文物编号'},
'表单3': {'sample_point': '采样点位置', 'id': '文物ID'}
}
```
阅读全文
相关推荐



















