TL;DR
- 공개 ChEMBL 데이터로 hERG 차단 예측을 직접 재현했습니다. 같은 분자, 같은 코드, 같은 LightGBM인데 무작위 분할은 AUROC 0.835, 연도 기준 시간 분할은 0.565였습니다. 점수 차이는 모델이 아니라 시험 문제에서 나왔습니다.
- 이유는 시험 분자가 학습 분자와 얼마나 닮았느냐입니다. 학습 집합에서 가장 가까운 분자와의 Tanimoto 유사도 중앙값이 무작위 분할 0.794, 시간 분할 0.365였습니다.
- 제출 횟수도 점수를 올립니다. 실력이 0인 제출자가 무작위 예측을 1,000번 내고 최고점을 남기면 공개 점수가 0.500에서 0.552로 오릅니다. 갱신 문턱을 두는 사다리 규칙(Blum and Hardt, ICML 2015)으로 이 부풀림을 줄이는 모습을 시뮬레이션으로 보였습니다.
- 이해관계 고지: 이 글이 다루는 LEADBOARD는 VIDRAFT(FINAL-Bench)가 운영하는 신약 예측 도구 벤치마크입니다. 우리 모델을 재는 보드가 아니라 어떤 도구든 올릴 수 있는 시험대입니다. 아래 수치 중 "재현"이라고 표시한 것은 제가 공개 데이터로 다시 돌린 것이고, "보드"라고 표시한 것은 운영 중인 보드 API와 문서에서 읽은 값입니다.
무작위 분할은 무엇이 문제인가?
신약 후보 물질 예측 논문은 대부분 분자를 무작위로 섞어 학습과 시험으로 나눕니다. 구현이 쉽고 분산이 작기 때문입니다. 그런데 실제로 이 도구를 쓰는 순간은 아직 아무도 재지 않은 분자의 순위를 매길 때입니다. 화학 시리즈는 한 논문 안에서 골격이 같은 분자 수십 개로 나오고, 무작위로 섞으면 그 이웃들이 학습과 시험에 나뉘어 들어갑니다. 모델은 암기한 이웃을 되돌려 주는 것만으로 점수를 얻습니다.
이를 직접 확인하려고 ChEMBL 37의 hERG(CHEMBL240) IC50 측정값을 받아 같은 특성과 같은 모델로 두 가지 분할을 비교했습니다. 전체 코드는 아래 골자입니다.
import requests, numpy as np, pandas as pd, lightgbm as lgb
from rdkit import Chem
from rdkit.Chem import rdFingerprintGenerator
from sklearn.metrics import roc_auc_score
API = "https://www.ebi.ac.uk/chembl/api/data/activity.json"
q = dict(target_chembl_id="CHEMBL240", standard_type="IC50",
standard_relation="=", limit=1000)
# offset 을 1000 씩 올리며 전부 받는다 (공개 API, 인증 불필요)
# 분자마다: pIC50 중앙값, 최초 보고 연도(= 그 분자가 처음 등장한 문헌 연도)
g = df.groupby("molecule_chembl_id").agg(
smiles=("canonical_smiles", "first"),
p=("p", "median"), year=("year", "min")).reset_index()
gen = rdFingerprintGenerator.GetMorganGenerator(radius=2, fpSize=2048)
y = (g.p.values >= 5.0).astype(int) # IC50 10 uM 이하면 차단제
cut = 2022
te_time = np.where(g.year.values > cut)[0]
tr_time = np.where(g.year.values <= cut)[0]
perm = np.random.default_rng(0).permutation(len(g))
te_rand = perm[:len(te_time)] # 시험 크기를 시간 분할과 똑같이 맞춘다
tr_rand = perm[len(te_time):]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
핵심은 시험 크기를 맞추는 것입니다. 무작위 분할의 시험 집합을 시간 분할과 같은 885개로 잘라 두 분할 사이에 다른 것은 "어느 분자가 시험에 들어가느냐" 하나뿐이게 했습니다. 시드 5개로 반복한 결과입니다.
| 분할 | 학습 / 시험 | AUROC (재현, 5회 평균 ± 표준편차) | 학습과 가장 가까운 분자의 Tanimoto 중앙값 |
|---|
| 무작위 | 8,729 / 885 | 0.835 ± 0.008 | 0.794 |
| 시간 (2022년 이후 최초 보고) | 8,729 / 885 | 0.565 ± 0.005 | 0.365 |
무작위 분할과 시간 분할의 hERG AUROC, 재현값과 LEADBOARD 문서값 비교
LEADBOARD 문서는 같은 현상을 hERG 보드에서 무작위 분할 0.818, 시간 분할 0.606으로 적어 두었습니다. 제 재현은 데이터 정제 방식(중앙값 집계, 등호 측정값만 사용, 문턱 pIC50 5.0)이 달라 값이 정확히 같지는 않지만 방향과 크기는 같습니다. 약 0.2 이상이 시험 문제에서 나온 점수입니다.
운영 중인 hERG 보드의 시간 분할 기준은 2022년이고 학습 8,450개, 시험 1,338개입니다. 보드 API의 값으로 보면 학습하지 않은 기준선 세 가지의 AUROC는 상수 예측 0.5, 최근접 이웃 0.566, Morgan 지문과 LightGBM 0.606입니다. 제 재현의 시간 분할 0.565는 이 기준선들과 같은 범위에 있습니다.
시간 분할이면 문제가 끝나는가?
아닙니다. 시간 분할은 더 정직한 질문일 뿐이고, 그 질문 하나가 해마다 다른 시험입니다. 같은 모델로 "해당 연도 이전으로 학습해 그해를 예측"하는 시험을 연도별로 돌려 봤습니다.
연도별 hERG AUROC 재현. 2016년 0.726에서 2025년 0.515까지 폭이 크다
13개 연도의 평균은 0.647이지만 최고 0.726(2016), 최저 0.515(2025)로 폭이 0.21입니다. 시험 크기가 156개(2025, 연중 집계)에서 751개(2018)까지 다르다는 점도 같이 봐야 합니다. 이 보드가 단일 점수만 내지 않고 기준선과 실험 잡음의 크기를 함께 공개하는 이유가 여기에 있습니다.
실험 잡음은 이런 뜻입니다. 같은 화합물을 서로 다른 연구실이 쟀을 때 값이 얼마나 벌어지는가입니다. hERG 보드는 857개 화합물, 5,185개 측정 쌍에서 단일 측정의 표준편차를 약 0.266 로그 단위, 쌍 차이의 중앙값을 0.148, 90분위를 1.34로 계산해 두었습니다. 정답표 자체가 이만큼 흔들리므로 그 아래 오차를 "개선"이라 부르는 것은 의미가 없습니다.
학습하지 않은 기준선이 상수 예측을 못 이기는 보드가 몇 개인가?
운영 중인 보드 API를 전부 받아 집계했습니다(2026-10-21 기준, 보드 46개, 시험 화합물 합계 57,698개).
| 항목 | 값 |
|---|
| 열린 보드 / 계획 | 46 / 96 |
| 분할 등급 | 시간 분할 44개, 골격 분할 2개, 무작위 분할 0개 |
| 정답 등급 | 공개 출처 정제(P1) 35개, 공개 출처 단위 변환 포함(P2) 11개, 비공개 정답(P3)·미래 예측(P4) 0개 |
| 1차 지표 | MAE 44개, 프로파일 상관 1개, AUROC 1개 |
| 기준선 세 종이 모두 상수 예측을 MAE로 못 이긴 보드 | 11개 |
마지막 줄은 직관과 어긋나므로 설명이 필요합니다. 시간 분할에서는 시험 시기의 값 분포가 학습 시기와 달라집니다. 순위를 맞히는 능력(AUROC)은 남아도 값의 크기를 맞히는 능력(MAE)은 상수 평균값보다 나빠질 수 있습니다. hERG가 그 사례입니다. Morgan+LightGBM은 AUROC 0.606으로 순위를 약간 맞히지만 MAE는 상수 예측의 0.589보다 낫지 못합니다.
반대편에는 기준선이 이미 높은 보드가 있습니다.
| 보드 | Morgan+LightGBM AUROC (보드) | 최선 기준선 MAE / 실험 잡음 SD | MAE로 상수 예측을 이기는가 |
|---|
| hERG | 0.606 | 2.21 | 아니오 |
| CYP3A4 | 0.572 | 2.04 | 아니오 |
| EGFR | 0.563 | 3.05 | 아니오 |
| BRD4 | 0.861 | 4.79 | 예 |
| BACE1 | 0.923 | 8.04 | 예 |
| Thrombin | 0.995 | 10.96 | 예 |
"MAE / 실험 잡음 SD"가 1에 가까울수록 기준선이 이미 측정 한계에 닿아 있다는 뜻이고, 클수록 개선 여지가 남아 있다는 뜻입니다. 보드마다 이 숫자가 다르다는 것이 보드를 하나의 합산 점수로 묶지 않는 이유입니다. Thrombin과 BACE1은 기준선 AUROC가 0.9를 넘는 반면, 독성과 대사 쪽 보드(hERG, CYP)는 0.6 근처에서 멈춥니다. 왜 그런지는 이 표만으로 단정할 수 없습니다. 다만 어느 보드가 얼마나 어려운지는 기준선과 잡음 크기를 같이 놓아야 말할 수 있다는 점은 분명합니다.
같은 사람이 여러 번 내면 점수는 얼마나 부풀어 오르는가?
시험 문제를 바꿔도 남는 문제가 제출 횟수입니다. 공개 점수를 돌려주는 보드에서는 매번 조금씩 다른 예측을 내고 최고점을 남기는 것만으로 점수가 올라갑니다. 보드 문서는 사다리 규칙(Blum and Hardt, ICML 2015)을 쓴다고 밝힙니다. 새 점수는 이전 최고점을 실험 잡음보다 크게 넘을 때만 공개하고, 아니면 이전 최고점이 유지됩니다.
이 효과를 직접 보려고 시뮬레이션을 돌렸습니다. 이 시뮬레이션은 illustrative입니다. 실제 보드의 제출 기록이 아니라 가정한 상황입니다. 시험 집합 1,338개(양성 784개, hERG 보드와 같은 크기와 비율)에 실력이 전혀 없는 제출자가 무작위 예측을 k번 냅니다.
n, pos = 1338, 784
y = np.r_[np.ones(pos, int), np.zeros(n - pos, int)]
sd = np.sqrt((n + 1) / (12 * pos * (n - pos))) # 찍기의 AUROC 표준편차, 약 0.016
def run(eta, k):
best = None
for _ in range(k):
s = roc_auc_score(y, rng.random(n)) # 실력 0 제출
if best is None or s > best + eta: # 사다리 규칙: 문턱 eta 보다 크게 넘어야 갱신
best = s
return best
eta=0이면 그냥 최고점 유지입니다. 문턱을 찍기 표준편차(0.016)의 1배, 2배, 3배로 두고 시도마다 반복한 평균입니다(제출 1,000회 조건은 60번 반복).
| 제출 횟수 | 최고점 유지 | 문턱 1 SD | 문턱 2 SD | 문턱 3 SD |
|---|
| 1 | 0.500 | 0.498 | 0.500 | 0.502 |
| 10 | 0.524 | 0.521 | 0.514 | 0.505 |
| 100 | 0.540 | 0.536 | 0.528 | 0.519 |
| 1,000 | 0.552 | 0.548 | 0.539 | 0.533 |
제출 횟수에 따라 실력 0 제출자의 공개 AUROC가 오르는 시뮬레이션. 문턱이 클수록 덜 오른다
두 가지를 읽을 수 있습니다. 첫째, 제출 1,000번만으로 실력 0이 0.552까지 올라갑니다. hERG 보드의 최근접 이웃 기준선(0.566)과 0.014 차이입니다. 보드 점수 하나만 보면 찍기와 모델이 구별되지 않는 구간이 실제로 있습니다. 둘째, 문턱을 키울수록 부풀림이 줄지만 공짜는 아닙니다. 문턱 3 SD(약 0.048)에서는 진짜로 0.03 개선한 모델도 공개 점수에 반영되지 않습니다. 사다리 규칙은 "구별 가능한 개선의 최소 단위"를 보드가 정하는 일이고, 그 단위를 정하는 근거로 보드는 실험 잡음을 씁니다.
이 시뮬레이션은 가장 단순한 공격인 무작위 제출만 다룹니다. 피드백을 이용해 예측을 조금씩 고쳐 가는 적응형 공격은 더 강하고, 사다리 규칙 논문은 그 경우의 오차 상한을 제출 횟수의 로그에 의존하는 형태로 증명했습니다. 이 글의 시뮬레이션은 그 증명을 재현한 것이 아닙니다.
연도 하나가 점수를 만들어 낼 수 있는가?
시간 분할에도 함정이 하나 더 있습니다. 시험 시기를 가르는 변수가 정답과 함께 움직이면 모델은 화학이 아니라 달력을 배웁니다. LEADBOARD의 시판 후 퇴출 보드가 그 사례입니다. 보드 문서에 따르면 퇴출률은 승인 연대에 따라 1990년대 7.8%, 2010년대 1.2%로 달라집니다. 분자 구조를 전혀 보지 않고 승인 연도만 읽는 예측기가 AUROC 0.636을 얻습니다. 승인 연도를 짝지어 대조군을 맞추면 이 값이 0.504로 내려가 찍기 수준이 됩니다.
운영 중인 보드 API에도 같은 값이 남아 있습니다. 대조군 연도 예측기의 AUROC가 0.5038이고, 열린 시험은 연도를 맞춘 쪽입니다. 구조만 보는 Morgan+LightGBM 기준선은 이 보드에서 0.593으로 그 위에 있습니다. 시험 184개, 학습 408개로 작아서 이 차이의 신뢰구간이 좁다고 말할 수는 없습니다. 보드가 같은 자리에 표본 잡음(약 0.044)을 함께 적어 둔 것도 그래서입니다.
첫 제출을 하려면?
각 보드는 구조만 담긴 시험 파일을 내려받게 하고, 제출은 compound_id,prediction CSV입니다. 어떤 도구든 받습니다. 학습한 모델, 물리 엔진, 언어 모델, 경험 규칙 모두 가능합니다. 채점은 정답을 가진 별도 하드웨어에서 돌아가고 Space에는 정답이 없습니다. 보드마다 채워진 프롬프트와 실행 가능한 뼈대 코드가 들어 있어 코딩 에이전트도 첫 제출까지 갈 수 있습니다.
한 가지 한계는 분명히 적어 두어야 합니다. 현재 열린 46개 보드는 모두 정답이 공개 출처에서 나온 P1·P2 등급입니다. 정답이 어딘가에 공개돼 있으므로 "조회해서 베끼는 길"을 막는 일은 보드의 별도 방어 조항이 맡고, 정답을 아예 비공개로 두는 P3 등급과 아직 존재하지 않는 미래 값을 맞히는 P4 등급은 등급표에는 있지만 현재 열린 보드에는 없습니다. 이 글의 결론도 거기까지입니다. 시간 분할과 사다리 규칙이 막아 주는 것은 "분할이 만든 부풀림"과 "횟수가 만든 부풀림"이지 정답 조회가 아닙니다.
재현 한계도 있습니다. 위 재현은 한 가지 지문(Morgan 반경 2, 2048비트)과 한 가지 모델(LightGBM)입니다. 다른 특성이나 사전학습 표현에서 격차가 얼마나 줄지는 재 보지 않았습니다. 측정값 집계와 문턱을 바꾸면 절대값이 달라지며, 보드 값과 0.02 안팎의 차이가 나는 이유가 이것입니다.
자주 묻는 질문
Q. 무작위 분할 점수는 틀린 값인가요?
틀린 것이 아니라 다른 질문의 답입니다. "이미 아는 화학 시리즈 안에서 빈 칸을 채우는 능력"을 재는 점수이고, 새 분자의 순위를 매기는 능력과는 별개입니다.
Q. 시간 분할 점수가 낮으면 모델이 쓸모없다는 뜻인가요?
아닙니다. 새 화학 공간에서의 기대 성능이 0.6 근처라는 뜻이며, 의사결정에 쓸 때는 보드가 같이 공개하는 실험 잡음과 기준선 대비 얼마나 나은지를 함께 봐야 합니다.
Q. AUROC와 MAE 중 무엇을 봐야 하나요?
쓰임에 따라 다릅니다. 후보를 줄 세워 상위 몇 개만 합성할 때는 순위(AUROC)가, 값 자체를 임계와 비교해 걸러낼 때는 크기(MAE)가 중요합니다. hERG 보드는 이 둘이 갈리는 대표 사례입니다.
Q. 사다리 규칙의 문턱은 어떻게 정하나요?
이 글의 시뮬레이션은 찍기 표준편차의 배수를 임의로 둔 것입니다. 보드는 실험 잡음을 기준으로 삼는다고 문서에 밝혔고, 문턱이 클수록 부풀림은 줄고 작은 진짜 개선도 가려진다는 교환 관계가 있습니다.
Q. 코드를 다시 돌려 볼 수 있나요?
위 골자는 공개 ChEMBL API와 rdkit, lightgbm, scikit-learn만 씁니다. 보드와 같은 숫자가 나온다고 보장하지는 않으며, 데이터 정제 선택이 값에 영향을 줍니다.
출처와 링크
시험 문제는 모델 점수의 일부입니다. 점수를 읽을 때 분할 방식, 시험 크기, 실험 잡음, 제출 횟수를 같이 적어 두는 습관이 무작위 분할의 0.835와 시간 분할의 0.565 사이를 메워 줍니다.
Further reading