Physics and Informatics/bioinformatics

bioinformatics: gene symbol, entrez id 변환

Novelism 2023. 12. 25. 09:59

 

 

이전 글 ( https://novelism.tistory.com/381 )에서 언급한 gene symbol과 entrez ID 를 변환하는 코드 예시입니다. 

DB를 배포할 때, 서로 중복될 여지가 있는 gene symbol 말고도 풀네임이나 ID 를 함께 배포하면 좋겠습니다만,

그렇지 못한 경우가 여럿 있습니다.

 

일단 저는 정보를 추출할 때 다음 2개의 파일을 사용합니다. 하나는 HGNC이고, 다른것은 NCBI gene info 입니다. 

HGNC는 당연히 HGNC symbol 이 기준이고, NCBI는 entrez id 가 기준입니다. 

https://ftp.ebi.ac.uk/pub/databases/genenames/hgnc/tsv/hgnc_complete_set.txt

 

https://ftp.ncbi.nlm.nih.gov/gene/DATA/GENE_INFO/Mammalia/Homo_sapiens.gene_info.gz

 

이 둘도 서로 100% 일치하지 않습니다. hgnc 에선 Entrez ID가 발급되었음에도 정보가 없는 경우가 있고, gene  info의 symbol이 HGNC의 symbol과 일치하지 않는 경우도 있습니다. 아마도 HGNC symbol이 시간에 따라 변하다보니 반영이 늦은 것일 수도 있습니다. 또한 모든 유전자에 HGNC symbol이 정해진 것은 아니기에 HGNC에 정보가 없는 것들도 있습니다. 

 

 gene symbol -> entrez id

entrez id -> gene symbol

두개의 딕셔너리를 작성할 것인데, 기본적으로 둘다 1:1이 아닙니다. 

전자에선 하나의 gene symbol이 하나의 유전자만을 지칭하는 것이 아니기에 관련된 유전자 전부를 연결합니다. 

후자에선 하나의 entrez id는 하나의 유전자만을 지칭하기에 (뭐 후에 두개가 동일유전자 였다 같은 일은 있을 수 있습니다.) HGNC같은 대표 gene symbol 만을 선택하는 방법이 있습니다. 

 

 일단 현재 시점의 HGNC의 gene symbol을 우선시하겠습니다.

 그래서 hgnc_complete_set.txt 파일을 먼저 파싱합니다. 

 

최종 생성물은 

gene_entrez_dict 와 gene_symbol_entrez_dict 두개의 python dict 입니다. 

gene_entrez_dict은 entrez_id가 key이고, gene symbol, gene name, 해당 gene symbol이 HGNC symbol 인지 여부를 values에 넣었습니다. 

{'entrez_id': { 'symbol': symbol, 'name': name, 'is_HGNC' : is_hgnc}}

의 2중 딕셔너리 구조입니다. 

 

gene_symbol_entrez_dict 은 gene symbol을 key로 사용하고, entrez_id 를 value로 제공합니다.

import pandas as pd
import numpy as np

hgnc_file = 'hgnc_complete_set.txt'
df_hgnc = pd.read_csv(hgnc_file, sep='\t',low_memory=False)
df_hgnc0 = df_hgnc.set_index('symbol')

gene_symbol_entrez_dict = dict()
gene_entrez_dict = dict()
for i in range(df_hgnc.shape[0]):
    df0 = df_hgnc.iloc[i]
    hgnc_id = df0['hgnc_id']
    name = df0['name']
    hgnc_symbol = df0['symbol']
    entrez_id0 = df0['entrez_id']
    ensembl_gene_id = df0['ensembl_gene_id']
    if not np.isnan(entrez_id0):
        entrez_id = int(entrez_id0)
        gene_entrez_dict[entrez_id] = dict()
        gene_entrez_dict[entrez_id]['symbol'] = hgnc_symbol
        gene_entrez_dict[entrez_id]['name'] = name
        gene_entrez_dict[entrez_id]['is_HGNC'] = True
        gene_symbol_entrez_dict[hgnc_symbol] = [entrez_id]

일단 HGNC symbol과 entrez_id 를 연결했습니다. entrez_id 는 원래 자연수이지만, 값이 없는 경우가 있어서 pandas로 읽을 경우 float, nan 이 됩니다. 


다음엔 현재 시점의 HGNC symbol 이외의, 이전에 사용되던 HGNC symbol이나 기타 gene symbol을 연결하겠습니다. 

'prev_symbol', 'alias_symbol' 열에 등록되어있습니다. symbol 끼리는 '|' 로 구분됩니다. 

for i in range(df_hgnc.shape[0]):
    df0 = df_hgnc.iloc[i]
    hgnc_id = df0['hgnc_id']
    hgnc_symbol = df0['symbol']
    entrez_id0 = df0['entrez_id']
    ensembl_gene_id = df0['ensembl_gene_id']
    alias_symbol = df0['alias_symbol']
    prev_symbol = df0['prev_symbol']
    alias_symbol_set = set()
    prev_symbol_set = set()
    if np.isnan(entrez_id0):
        continue
    entrez_id = int(entrez_id0)
    if alias_symbol is not np.nan:
        alias_symbol_set = set(alias_symbol.split('|'))
    if prev_symbol is not np.nan:
        prev_symbol_set = set(prev_symbol.split('|'))
    a_symbol_set = alias_symbol_set.union(prev_symbol_set)

    if len(a_symbol_set) ==0:
        continue
    for gene_symbol in sorted(a_symbol_set):
        if gene_symbol not in gene_symbol_entrez_dict:
            gene_symbol_entrez_dict[gene_symbol] = list()
        gene_symbol_entrez_dict[gene_symbol].append(entrez_id)

여기까지 진행하면 HGNC에 있는 gene 들은 연결됩니다. 

 

그다음은 gene info입니다. 일단 symbol 부터 연결합니다.

여기선 위에서 연결된 것들은 지나갑니다. 

그리고 tRNA같은 것도 무시합니다. 

gene_info_file = 'Homo_sapiens.gene_info.gz'
df_gene_info = pd.read_csv(gene_info_file, sep='\t',low_memory=False)

for i in range(0,df_gene_info.shape[0]):
    df0 = df_gene_info.iloc[i]
    entrez_id = int(df0['GeneID'])
    symbol = df0['Symbol']
    synonyms0 = df0['Synonyms']
    name = df0['description']
    type_of_gene = df0['type_of_gene']
    if type_of_gene =='tRNA':
        continue

    if entrez_id not in gene_entrez_dict:
        gene_entrez_dict[entrez_id] = dict()

        gene_entrez_dict[entrez_id]['symbol'] = symbol
        gene_entrez_dict[entrez_id]['name'] = name
        gene_entrez_dict[entrez_id]['is_HGNC'] = False

        if symbol not in gene_symbol_entrez_dict:
            gene_symbol_entrez_dict[symbol] = list()
        gene_symbol_entrez_dict[symbol].append(entrez_id)

여기서 is_HGNC는 전부 False 로 했는데, 사실 True 여야 하는 경우도 있습니다. 

HGNC 에서 entrez id가 nan으로 나온 것들이 여기서 잡히면 True여야 합니다. 

 

다음으로 synonyms symbol을 연결합니다. 

for i in range(0,df_gene_info.shape[0]):
    df0 = df_gene_info.iloc[i]
    entrez_id = int(df0['GeneID'])
    symbol = df0['Symbol']
    synonyms0 = df0['Synonyms']
    name = df0['description']
    type_of_gene = df0['type_of_gene']
    if type_of_gene =='tRNA':
        continue

    if synonyms0 == '-':
        continue

    synonyms_list = synonyms0.strip().split('|')
    for gene_symbol in synonyms_list:
        if gene_symbol not in gene_symbol_entrez_dict:
            gene_symbol_entrez_dict[gene_symbol] = list()
        if entrez_id not in gene_symbol_entrez_dict[gene_symbol]:
            gene_symbol_entrez_dict[gene_symbol].append(entrez_id)

 

이렇게 하면 딕셔너리가 완성됩니다.

저는 다음과 같은 형태로 저장했습니다. 

df_entrez = pd.DataFrame(gene_entrez_dict).T
df_entrez.index.name = 'Entrez_id'
df_entrez.to_csv('gene_dict_entrez.tsv', sep='\t')
df_entrez.to_pickle('gene_dict_entrez.pkl')

out_dict_file = 'gene_dict_symbol.tsv'
fp_out = open(out_dict_file, 'w')
for key in sorted(gene_symbol_entrez_dict.keys()):
    val = gene_symbol_entrez_dict[key]

    tmp_list = list()
    for entrez_id in val:
        tmp_list.append(str(entrez_id))
    tt = '|'.join(tmp_list)
    line_out = '%s\t%s\n' % (key,tt)
    fp_out.write(line_out)
fp_out.close()