컬럼의 DBC 측정하기
1. DBC(dynamic binding capacity)란 무엇인가?¶
DBC는 단백질 정제에서 크로마토그래피 컬럼의 특정 실험 조건에 결합 할 수 있는 표적 단백질의 최대 양을 나타냅니다. 그러나 DBC는 유속이나 버퍼의 조성 및 단백질 시료에 따라 달라지기 때문에 실험 조건에 따라 달라 집니다.
그렇기 때문에 단백질 정제에서 적합한 레진을 선택하기 위해서는 DBC에 대한 정보가 매우 중요합니다. 보통 레진의 제조사는 일반적인 단백질 정제 조건에서의 DBC 정보를 제공하고는 있지만 특정 단백질에 대한 최상의 레진 및 실험 조건을 찾기 위해 직접 DBC를 측정해야 할 일 이 생깁니다.
1.1. breakthrough 곡선¶
image from cytiva
breakthrough 곡선은 컬럼에 결합하지 못하고 흘러 나온 단백질의 양을 그래프로 표현한 것입니다. 그리고 전체의 10%의 단백질이 흘러나온 경우를 QB10 값이라 합니다.
1.2. DBC 계산법¶
image from cytiva
위 그래프의 파란색 영역은 지연 볼륨(delay volume)으로 사용한 컬럼의 볼륨과 AKTA 시스템에 의해 발생합니다. 주황색 영역은 비 결합 단백질의 양을 나타냅니다. 파란색 곡선은 단백질 breakthrough를 나타내는 것으로 녹색 영역은 X% breakthrough에서 누출 된 단백질의 양을 나타냅니다. X% 에서의 총 DBC는 회색 영역으로 표시됩니다.
위 그림을 예시로 Aoffset은 50 mAu이고 Amax는 1000 mAu 이라는 것을 알 수 있습니다.
50 ml(Vx)에서 측정된 UV 흡광도는 126 mAu 이지만 아래의 계산을 통해 실제 값은 76 mAu라고 생각할 수 있습니다.
A- Aoffset = 126 – 50 = 76 mAu
그리고 최대 UV 흡광도도 마찬가지로 950 mAu가 될 것입니다.
Amax - Aoffset = 1000 – 50 = 950 mAu
따라서 breakthrough의 비율은
(A - Aoffset) / (Amax - Aoffset) = Percentage of breakthrough
를 통해 계산합니다. 결과적으로 50ml에서 breakthrough의 비율은 8%가 됩니다.
% breakthrough = 76 / 950 = 8%
2. DBC 계산하기¶
실제 실험을 통해 얻은 데이터를 통해 DBC(QB10)을 계산해보도록 하겠습니다.
2.1. 실험 데이터 불러오기¶
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
from scipy.optimize import curve_fit
from pynverse import inversefunc
delayed_vol = 2.0 # 컬럼을 거치는데 필요한 부피(ml)
protein_conc = 3.97 # 사용한 단백질의 농도(mg/ml)
df = pd.read_csv("0827_ProteinA_DBC.csv")
df
# 테이블 두개로 분리하기
df1 = df[df["Residence_time"] == 3]
df2 = df[df["Residence_time"] == 4]
df1
2.2. 전체 데이터 시각화¶
시각화를 통해 전체 데이터의 모습을 확인합니다.
plt.plot(df1["Volume(ml)"], df1["Breakthrough(%)"], label="Residence_time=3")
plt.plot(df2["Volume(ml)"], df2["Breakthrough(%)"], label="Residence_time=4")
plt.ylabel("Breakthrough(%)")
plt.xlabel("Volume(ml)")
plt.legend()
2.3. 그래프 피팅하기¶
시그모이드 함수 정의하고 curvefit
으로 피팅하기
def sigmoid(x, L, x0, k, b):
y = L / (1 + np.exp(-k * (x - x0))) + b
return y
def fitting(xdata, ydata):
p0 = [max(ydata), np.median(xdata), 1, min(ydata)]
popt, pcov = curve_fit(sigmoid, xdata, ydata, p0, method="dogbox")
residuals = ydata - sigmoid(xdata, *popt)
ss_res = np.sum(residuals**2)
ss_tot = np.sum((ydata - np.mean(ydata)) ** 2)
r_squared = 1 - (ss_res / ss_tot)
return xdata, ydata, popt, r_squared
Run1 = fitting(df1["Volume(ml)"], df1["Breakthrough(%)"])
Run2 = fitting(df2["Volume(ml)"], df2["Breakthrough(%)"])
2.3.1. Residence time 3분 DBC 계산¶
피팅이 올바른지 그림으로 확인한다.
x_fit = np.linspace(1, 60, 100)
y_fit = sigmoid(x_fit, *Run1[2])
plt.plot(Run1[0], Run1[1], "o", label="data", color="k")
plt.plot(x_fit, y_fit, label="fit", color="r")
plt.text(40, 20, s=f"r_squared={Run1[3]:.3f}", fontsize=10)
plt.ylabel("Breakthrough(%)")
plt.xlabel("Volume(ml)")
plt.legend()
qb10_run1 = inversefunc(sigmoid, args=tuple(Run1[2]), y_values=10)
print(f"10% breakthrough 일때 fraction(ml)의 값 {qb10_run1:.3f} ml 이고")
dbc_run1 = (qb10_run1 - delayed_vol) * protein_conc
print(f"따라서 DBC(QB10)의 값은 {dbc_run1:.3f} mg/ml 이다.")
2.3.1. Residence time 4분 DBC 계산¶
앞서 사용한 방법과 동일하게 진행한다.
x_fit = np.linspace(1, 60, 100)
y_fit = sigmoid(x_fit, *Run2[2])
plt.plot(Run2[0], Run2[1], "o", label="data", color="k")
plt.plot(x_fit, y_fit, label="fit", color="r")
plt.text(40, 20, s=f"r_squared={Run2[3]:.3f}", fontsize=10)
plt.ylabel("Breakthrough(%)")
plt.xlabel("Volume(ml)")
plt.legend()
qb10_run2 = inversefunc(sigmoid, args=tuple(Run2[2]), y_values=10)
print(f"10% breakthrough 일때 fraction(ml)의 값 {qb10_run2:.3f} ml 이고")
dbc_run2 = (qb10_run2 - delayed_vol) * protein_conc
print(f"따라서 DBC(QB10)의 값은 {dbc_run2:.3f} mg/ml 이다.")
3. 결론¶
Residence time은 평균적으로 단백질 시료가 정제 컬럼에 체류하는 시간의 값 입니다. 따라서 평균 체류 시간이 길수록 DBC는 증가할 것으로 예측할 수 있습니다. 위의 예시를 통해서도 3분일때는 72.902 mg/ml, 4분일때는 88.928 mg/ml 이라는 확인 할 수 있습니다.
3.1. 참고 자료¶
- GE Healthcare Life Sciences
- Pranav Gupte et. al, Dynamic Binding Capacities of Protein A Resins for Antibody Capture: A Comparative Evaluation, 2020, BioProcessInternational.