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

基于Scanpy的AnnData对象obs索引匹配标签赋值及报错修复

问题:AnnData对象obs与anno索引匹配赋值时触发KeyError并实现需求

原代码

import pandas as pd
import numpy as np
import os
import scanpy as sc

for subdir, dirs, files in os.walk(directory_path):
    for file in files:
        if file.endswith("_ccRCC.h5"):
            file_path = os.path.join(subdir, file)
            id = file.split("_")[0]
            dfs[id] = sc.read_10x_h5(file_path, genome="GRCh38", backup_url=None)    
            dfs[id].var_names_make_unique()
            results_file[id] = id + ".h5ad"


for i in dfs:
    ids = anno.index.str.extract(r'([^_]*)$')[0].tolist()
    if any(j in dfs[i].obs.index.map(str).tolist() for j in ids):
        for k in ids:
            dfs[i].obs = dfs[i].obs.join(anno.set_index(k)).dropna()

报错信息

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Input In [124], in <cell line: 1>()
      3 if any(j in dfs[i].obs.index.map(str).tolist() for j in ids):
      4     for k in ids:
----> 5         dfs[i].obs = dfs[i].obs.join(anno.set_index(k)).dropna()

File ~/.local/lib/python3.9/site-packages/pandas/core/frame.py:5859, in DataFrame.set_index(self, keys, drop, append, inplace, verify_integrity)
   5856                 missing.append(col)
   5858 if missing:
-> 5859     raise KeyError(f"None of {missing} are in the columns")
   5861 if inplace:
   5862     frame = self

KeyError: "None of ['AAACCTGCAAGTAGTA-1'] are in the columns"

输入数据

  • dfs结构
{'GSM4819737': AnnData object with n_obs × n_vars = 1916 × 2252
     obs: 'n_genes', 'n_genes_by_counts', 'total_counts', 'total_counts_mt', 'pct_counts_mt', 'leiden'
     var: 'gene_ids', 'n_cells', 'mt', 'n_cells_by_counts', 'mean_counts', 'pct_dropout_by_counts', 'total_counts', 'highly_variable', 'means', 'dispersions', 'dispersions_norm', 'mean', 'std'
     uns: 'hvg', 'leiden', 'leiden_colors', 'leiden_sizes', 'log1p', 'neighbors', 'paga', 'pca', 'rank_genes_groups', 'umap'
     obsm: 'X_pca', 'X_umap'
     varm: 'PCs'
     obsp: 'connectivities', 'distances',
 'GSM4819735': AnnData object with n_obs × n_vars = 713 × 2619
     obs: 'n_genes', 'n_genes_by_counts', 'total_counts', 'total_counts_mt', 'pct_counts_mt', 'leiden'
     var: 'gene_ids', 'n_cells', 'mt', 'n_cells_by_counts', 'mean_counts', 'pct_dropout_by_counts', 'total_counts', 'highly_variable', 'means', 'dispersions', 'dispersions_norm', 'mean', 'std'
     uns: 'hvg', 'leiden', 'leiden_colors', 'leiden_sizes', 'log1p', 'neighbors', 'paga', 'pca', 'rank_genes_groups', 'umap'
     obsm: 'X_pca', 'X_umap'
     varm: 'PCs'
     obsp: 'connectivities', 'distances'}
  • dfs["GSM4819737"].obs前两行
pd.DataFrame({'n_genes': {'AAACCTGGTAAATGTG-1': 2261, 'AAACCTGCAAGTAGTA-1': 2497},
 'n_genes_by_counts': {'AAACCTGGTAAATGTG-1': 2261, 'AAACCTGCAAGTAGTA-1': 2497},
 'total_counts': {'AAACCTGGTAAATGTG-1': 5744.0, 'AAACCTGCAAGTAGTA-1': 10502.0},
 'total_counts_mt': {'AAACCTGGTAAATGTG-1': 146.0, 'AAACCTGCAAGTAGTA-1': 18.0},
 'pct_counts_mt': {'AAACCTGGTAAATGTG-1': 2.5417826175689697,
  'AAACCTGCAAGTAGTA-1': 0.1713959276676178},
 'leiden': {'AAACCTGGTAAATGTG-1': '2', 'AAACCTGCAAGTAGTA-1': '1'}})
  • anno前两行最后两列
pd.DataFrame({'label': {'SI_18854_AAACCTGCAAGTAGTA-1': '1:Tumor',
  'SI_18854_AAACCTGTCCACTGGG-1': '1:Tumor'},
 'patient': {'SI_18854_AAACCTGCAAGTAGTA-1': 'SS_2005',
  'SI_18854_AAACCTGTCCACTGGG-1': 'SS_2005'}})

期望输出

pd.DataFrame({'n_genes': {'AAACCTGCAAGTAGTA-1': 2497},
 'n_genes_by_counts': {'AAACCTGCAAGTAGTA-1': 2497},
 'total_counts': {'AAACCTGCAAGTAGTA-1': 10502.0},
 'total_counts_mt': {'AAACCTGCAAGTAGTA-1': 18.0},
 'pct_counts_mt': {'AAACCTGCAAGTAGTA-1': 0.1713959276676178},
 'leiden': {'AAACCTGCAAGTAGTA-1': '1'},
 'label': {'AAACCTGCAAGTAGTA-1': '1:Tumor'}})

解决方案

报错原因

原代码中anno.set_index(k)逻辑错误:k是从anno索引提取的子串(如AAACCTGCAAGTAGTA-1),但anno的列中不存在该名称,因此触发KeyError。

修正代码

import pandas as pd
import numpy as np
import os
import scanpy as sc

# 读取数据部分保持不变
for subdir, dirs, files in os.walk(directory_path):
    for file in files:
        if file.endswith("_ccRCC.h5"):
            file_path = os.path.join(subdir, file)
            id = file.split("_")[0]
            dfs[id] = sc.read_10x_h5(file_path, genome="GRCh38", backup_url=None)    
            dfs[id].var_names_make_unique()
            results_file[id] = id + ".h5ad"

# 预处理anno:提取索引最后一个下划线后的子串作为匹配用的cell_id列
anno['cell_id'] = anno.index.str.split('_').str[-1]

# 遍历每个AnnData对象完成匹配赋值
for sample_id in dfs:
    adata = dfs[sample_id]
    # 将obs的索引转为列,方便后续合并
    adata.obs = adata.obs.reset_index().rename(columns={'index': 'cell_id'})
    # 内连接合并,自动过滤无匹配的行,仅保留需要的label列
    merged_obs = pd.merge(adata.obs, anno[['cell_id', 'label']], on='cell_id', how='inner')
    # 恢复obs的索引结构为cell_id
    merged_obs = merged_obs.set_index('cell_id')
    # 更新AnnData的obs数据
    adata.obs = merged_obs
    # 同步更新AnnData的观测数(可选,替换obs后会自动更新,显式处理更稳妥)
    adata._n_obs = len(merged_obs)

代码说明

  1. 预处理anno:新增cell_id列存储索引最后一个下划线后的子串,作为匹配的键。
  2. 合并匹配:将obs的索引转为列后,用内连接(how='inner')自动过滤无匹配的行,同时关联anno的label列。
  3. 恢复结构:合并完成后重新设置obs的索引为cell_id,保证AnnData的结构符合后续分析要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 08:37:01