バイオインフォマティクスデータの距離計算の方法

バイオインフォマティクスの分野では、遺伝子発現データ、DNA/タンパク質配列、腸内マイクロバイオームの組成データなど、さまざまな種類のデータを解析する際に「データ間の距離」を計算することが非常に重要となります。

本記事では、バイオインフォマティクス分野で利用される主要な距離計算手法について、Pythonによる実装例とともに解説します。

ユークリッド距離

距離といえば、真っ先に思い浮かぶのがユークリッド距離。ユークリッド距離は、最も基本的で直感的な距離計算方法です。各次元の値の差の2乗和の平方根を計算することで、連続値データ間の「直線距離」を求めます。
主にマイクロアレイによる遺伝子発現データやRNA-seqのFPKM値など、連続値データのクラスタリングや次元削減に利用されます。

import numpy as np
from scipy.spatial.distance import euclidean

# 例:2つの遺伝子発現プロファイル
vector1 = np.array([5.1, 3.5, 1.4, 0.2])
vector2 = np.array([4.9, 3.0, 1.4, 0.2])

distance = euclidean(vector1, vector2)
print("Euclidean Distance:", distance)

# 出力
# Euclidean Distance: 0.5385164807134502

マンハッタン距離

マンハッタン距離(またはL1ノルム)は、各次元における絶対差の和を計算します。
ユークリッド距離よりもロバストな場合があり、変動が大きい遺伝子発現データやスパースなデータに対して有用です。

from scipy.spatial.distance import cityblock

# 例:2つの遺伝子発現プロファイル
vector1 = np.array([5.1, 3.5, 1.4, 0.2])
vector2 = np.array([4.9, 3.0, 1.4, 0.2])

distance = cityblock(vector1, vector2)
print("Manhattan Distance:", distance)

# 出力
# Manhattan Distance: 0.6999999999999993

先ほどの、ユークリッド距離と値が異なることがわかります。

コサイン距離/類似度

コサイン距離は、ベクトル間の角度(方向性)に注目する指標です。
特徴量のスケールが大きく異なる場合や、テキストデータ、配列の埋め込み(embedding)ベクトルの類似度評価に適しています。

from sklearn.metrics.pairwise import cosine_distances

# 例:2つの遺伝子発現プロファイル
vector1 = np.array([5.1, 3.5, 1.4, 0.2])
vector2 = np.array([4.9, 3.0, 1.4, 0.2])

# 2つのベクトルを2次元配列に整形
vectors = np.array([vector1, vector2])
cosine_distance = cosine_distances(vectors)
print("Cosine Distance matrix:\n", cosine_distance)

# 出力
# Cosine Distance matrix:
# [[0. 0.00142084]
#  [0.00142084 0. ]]

タンパク質やDNA配列から得られた特徴ベクトルの類似度評価や、RNA-seqデータのパターン比較などで使用されます。

ジャッカード距離/指数

ジャッカード距離は、二値データや集合データの類似性を評価する手法です。
例えば、遺伝子の発現の有無、またはマイクロバイオームのOTUの存在・非存在(presence/absence)の比較に活用されます。

from sklearn.metrics import jaccard_score

# 例:2つのバイナリベクトル(例:特定遺伝子の発現有無情報)
binary1 = np.array([1, 0, 1, 1, 0])
binary2 = np.array([1, 1, 1, 0, 0])

jaccard = jaccard_score(binary1, binary2)
print("Jaccard Similarity:", jaccard)
print("Jaccard Distance:", 1 - jaccard) # 出力 # Jaccard Similarity: 0.5 # Jaccard Distance: 0.5

腸内マイクロバイオームのOTU出現パターンを、存在/非存在データとしてクラスタリングする場合などに利用されます。

ハミング距離

ハミング距離は、同じ長さの配列間で各位置が一致するかどうかを数え、異なる文字の数(または割合)を計算します。
DNAやタンパク質配列間の変異(SNPなど)の検出に適しています。

from scipy.spatial.distance import hamming

seq1 = "ACGTACGT"
seq2 = "ACGTTCGT"

# ハミング距離は割合として返されるので、実際の不一致数は長さ×distanceで求める
distance_ratio = hamming(list(seq1), list(seq2))
distance_count = distance_ratio * len(seq1)
print("Hamming Distance ratio:", distance_ratio)
print("Hamming Distance (count):", distance_count)

# 出力
# Hamming Distance ratio: 0.125
# Hamming Distance (count): 1.0

DNA配列やタンパク質配列の間の相違点を調べることで、進化的距離や変異解析に利用されます。

レーベンシュタイン距離/編集距離

編集距離は、1つの配列をもう1つの配列に変換する際に必要な挿入、削除、置換の最小操作数を計算します。
特に、DNAやタンパク質配列間の全体的な類似性評価に有効です。

まず、python-Levenshteinパッケージをインストールします。

pip install python-Levenshtein

python実装例

importLevenshtein

seq1="ACGTACGT"
seq2="ACGTTCGT"
distance=Levenshtein.distance(seq1, seq2)
print("Levenshtein Distance:", distance)

# 出力
# Levenshtein Distance: 1

UniFrac距離

UniFracは、微生物群集(マイクロバイオーム)の解析に特化した距離評価手法です。
系統樹に基づいて、サンプル間で共有する系統枝の長さを比較するため、「unweighted UniFrac」では存在/非存在情報を、「weighted UniFrac」では各OTUの相対豊富性も考慮します。
Pythonでは、scikit-bioパッケージがUniFrac距離の計算をサポートしています。まずはパッケージのインストールします。
pip install scikit-bio
python実装例
import numpy as np
from skbio import TreeNode
from skbio.diversity import beta_diversity

# サンプルOTUテーブル(行:サンプル、列:OTU)
# ここでは3サンプル×3 OTU のシンプルな例です
otu_table = np.array([
    [10, 0, 20],
    [ 0, 15, 5],
    [20, 5, 0]
])

# サンプルIDおよびOTU(taxa)IDリスト
sample_ids = ['S1', 'S2', 'S3']
taxa = ['OTU1', 'OTU2', 'OTU3']

# Newick形式の系統樹
# 例: OTU1とOTU2が近縁、OTU3がそれらから分岐する場合
tree_newick = "((OTU1:0.1,OTU2:0.2):0.3,OTU3:0.4);"
tree = TreeNode.read([tree_newick])

# beta_diversity関数を用いて、"unweighted_unifrac" 距離行列を計算
unifrac_dm = beta_diversity(
    metric="unweighted_unifrac", # "weighted_unifrac" に変更可能
    counts=otu_table,
    ids=sample_ids,
    tree=tree,
    taxa=taxa # ここでOTUリストを渡す
)

print("Unweighted UniFrac Distance Matrix:")
print(unifrac_dm)

# 出力
# Unweighted UniFrac Distance Matrix:
# 3x3 distance matrix
# IDs:
# 'S1', 'S2', 'S3'
# Data:
# [[0. 0.3 0.6]
# [0.3 0. 0.5]
# [0.6 0.5 0. ]]
腸内マイクロバイオームの16S rRNAシーケンスデータからOTUテーブルを構築し、サンプル間の群集構造やEnterotype解析で広く利用されています。

Bray-Curtis距離

Bray–Curtis距離は、主に生態学で使用される指標で、2つのサンプル間の群集構成の違いを評価します。各カテゴリ(例:OTU、種、または機能群)の豊富性の差の絶対値の和を、2つのサンプルでの総豊富性の和で割ることで求められます。腸内マイクロバイオームの解析において、サンプル間の組成(相対的な存在比率)の違いを評価するのに広く利用されます。

Bray–Curtis距離は以下のように定義されます。

 

dBC(x,y)=i=1nxiyii=1n(xi+yi)

ここで、xおよびyはそれぞれのサンプルの各カテゴリの豊富性を表すベクトルです。

import numpy as np
from scipy.spatial.distance import braycurtis

# 例:2つのサンプルのOTU相対豊富性データ
sample1 = np.array([0.1, 0.3, 0.6])
sample2 = np.array([0.2, 0.2, 0.6])

distance = braycurtis(sample1, sample2)
print("Bray–Curtis Distance:", distance)

# 出力
# Bray–Curtis Distance: 0.09999999999999999

アンチソン距離

アイチソン距離は、構成データ(全体で100%に正規化されたデータ)の解析に適しており、Centered Log-Ratio(CLR)変換後のユークリッド距離として定義されます。
マイクロバイオームデータのように、各サンプルの値が相対値の場合に用いられることが多いです。
scikit-bioをインストール
pip install scikit-bio
python実装例
import numpy as np
from skbio.stats.composition import clr
from scipy.spatial.distance import euclidean

# 例:腸内マイクロバイオームサンプルのOTU構成(各サンプルは確率分布)
sample1 = np.array([0.2, 0.3, 0.5])
sample2 = np.array([0.1, 0.4, 0.5])

# CLR変換(実際にゼロが含まれる場合は擬似カウントを加えること)
sample1_clr = clr(sample1)
sample2_clr = clr(sample2)

aitchison_distance = euclidean(sample1_clr, sample2_clr)
print("Aitchison Distance:", aitchison_distance)

# 出力
# Aitchison Distance: 0.7130310914894464

RMSD (Root Mean Square Deviation)

RMSDは、2つの対応する点集合(例:タンパク質の立体構造や複数の分子コンフォメーション)の間の相違(ずれ)を定量化する指標です。各点間の偏差の2乗の平均の平方根として計算され、構造の類似性や動的変化の評価によく利用されます。生体高分子の比較解析(例:分子動力学シミュレーション、構造アライメント)などで頻繁に使用されます。
import numpy as np

def compute_rmsd(P, Q):
    """
    P, Q: 各サンプル点を行に持つNumpy配列
    例:P.shape = (N, 3), Q.shape = (N, 3)
    """
    assert P.shape == Q.shape, "入力の形状が一致していません。"
    diff = P - Q
    rmsd = np.sqrt(np.mean(np.square(diff)))
    return rmsd

# 例:タンパク質の2つの構造(各構造はN個の3次元座標)
P = np.array([[1.0, 2.0, 3.0],
              [2.0, 3.0, 4.0],
              [3.0, 4.0, 5.0]])
Q = np.array([[1.1, 1.9, 3.1],
             [1.9, 3.1, 3.9],
             [3.2, 3.8, 5.1]])

rmsd_value = compute_rmsd(P, Q)
print("RMSD:", rmsd_value)

# 出力
# RMSD: 0.12909944487358063
RMSDは下記のような場面で使用されます。
  • タンパク質構造の比較:PDBデータベースから取得した同一タンパク質の異なるコンフォメーション間の構造ズレの評価

  • 分子動力学シミュレーション:シミュレーション中に得られる複数の構造状態間での平均的な構造変動の評価

まとめ

本記事では、バイオインフォマティクス分野で利用される主要な距離計算手法と、Pythonによる実装例、そして具体的なデータ事例について解説しました。

  • ユークリッド距離, マンハッタン距離, コサイン距離 などの手法は、主に連続データ(例:遺伝子発現データ、埋め込みベクトル)で用いられます。

  • ジャッカード距離ハミング距離 は、存在/非存在や文字列間の違いを計算する際に適しており、DNAやタンパク質配列の比較に利用されます。

  • レーベンシュタイン距離 は編集距離として、配列全体の変換回数(挿入、削除、置換)を計算するため、配列類似性評価に役立ちます。

  • マイクロバイオーム解析では、UniFrac(weighted/unweighted)Bray-Curtis距離アンチソン距離 がよく用いられ、これらはそれぞれ系統情報や構成的データの特性を考慮した距離計算手法です。

  • タンパク質の構造解析では、構造間のずれを定量化する指標として、RMSDが用いられます。

各手法は、データの前処理(正規化、CLR変換、擬似カウントの追加など)を適切に行った上で、対象データの性質に合わせて選択する必要があります。これにより、クラスタリングや次元削減、解析の結果が生物学的な解釈に基づく信頼性の高いものとなります。

ぜひ、様々なデータで距離を計算してみてください。