Python数据分析遇KeyError:指定索引项不在DataFrame列中求解决
KeyError错误分析与修复方案
错误原因
- 无效的Series操作:代码中
summary - summary[base_cols]是无意义的减法运算,没有对summary做任何筛选或修改,导致summary保留了所有重复索引项。后续合并时,这些索引被转为列名,而base_cols是索引值,自然找不到对应的列,触发KeyError。 - 拼写错误:
pandas.concat(summaries, asix=1).T里的asix是笔误,正确应为axis=1。这个错误会导致合并方向完全错误,把本应按列合并的操作变成按行合并,最终数据结构完全不符合预期。 - 参数传递错误:调用
read_season_info("soup")时传了字符串soup,而非解析后的BeautifulSoup对象,这会导致获取赛季信息失败,引发额外错误。
修复步骤
- 替换无效操作:把
summary - summary[base_cols]改为按索引筛选并赋值:
这一步确保summary = summary[base_cols]summary只保留我们需要的、去重后的统计项。 - 修正拼写错误:将
asix=1改为axis=1:summary = pandas.concat(summaries, axis=1).T - 修复参数传递:把
read_season_info("soup")改为传递实际的soup对象:full_game["season"] = read_season_info(soup)
修正后的完整代码
from bs4 import BeautifulSoup import pandas import os SEASONS = list(range(2016, 2017)) DATA_DIR = "data" STANDINGS_DIR = os.path.join(DATA_DIR, "standings") SCORES_DIR = os.path.join(DATA_DIR, "scores") box_scores = os.listdir(SCORES_DIR) box_scores = [os.path.join(SCORES_DIR, f) for f in box_scores if f.endswith(".html")] def parse_html(box_score): with open(box_score) as f: html = f.read() soup = BeautifulSoup(html) [s.decompose() for s in soup.select("tr.over_header")] [s.decompose() for s in soup.select("tr.thead")] return soup def read_line_score(soup): line_score = pandas.read_html(str(soup), attrs = {"id": "line_score"})[0] cols = list(line_score.columns) cols[0] = "team" cols[-1] = "total" line_score.columns = cols line_score = line_score[["team", "total"]] return line_score def read_stats(soup, team, stat): df = pandas.read_html(str(soup), attrs={"id": f"box-{team}-game-{stat}"}, index_col=0)[0] df = df.apply(pandas.to_numeric, errors="coerce") return df def read_season_info(soup): nav = soup.select("#bottom_nav_container")[0] hrefs = [a["href"] for a in nav.find_all("a")] season = os.path.basename(hrefs[1]).split("_")[0] return season base_cols = None games = [] for box_score in box_scores: soup = parse_html(box_score) line_score = read_line_score(soup) teams = list(line_score["team"]) summaries = [] for team in teams: basic = read_stats(soup, team, "basic") advanced = read_stats(soup, team, "advanced") totals = pandas.concat([basic.iloc[-1:], advanced.iloc[-1:]]) totals.index = totals.index.str.lower() maxes = pandas.concat([basic.iloc[:-1,:].max(), advanced.iloc[:-1,:].max()]) maxes.index = maxes.index.str.lower() + "_max" summary = pandas.concat([totals, maxes]) if base_cols is None: base_cols = list(summary.index.drop_duplicates(keep="first")) base_cols = [b for b in base_cols if "bpm" not in b] # 修复:替换无效减法为索引筛选 summary = summary[base_cols] summaries.append(summary) # 修复:修正axis拼写错误 summary = pandas.concat(summaries, axis=1).T game = pandas.concat([summary, line_score], axis=1) game["home"] = [0, 1] game_opp = game.iloc[::-1].reset_index() game_opp.columns += "_opp" full_game = pandas.concat([game, game_opp], axis=1) # 修复:传递正确的soup对象 full_game["season"] = read_season_info(soup) full_game["date"] = os.path.basename(box_score)[:8] full_game["date"] = pandas.to_datetime(full_game["date"], format="%Y%m%d") full_game["won"] = full_game["total"] > full_game["total_opp"] games.append(full_game) if len(games) % 100 == 0: print(f"{len(games)} / {len(box_scores)}")
内容的提问来源于stack exchange,提问作者pynewbpy44
相关产品推荐
相关产品推荐

