import matplotlib.pyplot as plt
import numpy as np
import prody as pr
import seaborn as sns
import pandas as pd
from scipy.stats import pearsonr
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import r2_score
structure = pr.parsePDB('7axc')
selection = structure.select('protein')
hv = selection.getHierView()
hv
Получение pd-dataframe, содержащего средние значения В-факторов для атомов, а также координаты их центров масс.
B_factors = np.zeros((264, 6))
for i, residue in enumerate(hv.iterResidues()):
B_factors[i][1] = np.mean(residue.getBetas())
B_factors[i][0] = residue.getResnum()
string = "resnum "
string+= str(residue.getResnum())
group = structure.select(string)
B_factors[i][2], B_factors[i][3], B_factors[i][4] = pr.calcCenter(group, weights=group.getMasses())
data = pd.DataFrame(B_factors, columns = ["Number", "B-factor", "x_mass", "y_mass", "z_mass", "to_center"])
Поиск остатка, имеющего максимальный средний В-фактор.
data[data["B-factor"] == data["B-factor"].max()]
Поиск остатка, имеющего минимальный средний В-фактор.
data[data["B-factor"] == data["B-factor"].min()]
Подсчет центра масс для всей белковой молекулы.
whole_protein_mass = pr.calcCenter(selection, weights=selection.getMasses())
whole_protein_mass
for index, row in data.iterrows():
row["to_center"] = np.sqrt((row["x_mass"] - whole_protein_mass[0])**2 + (row["y_mass"] - whole_protein_mass[1])**2 + (row["z_mass"] - whole_protein_mass[2])**2)
data.head()
plt.figure(figsize=(10, 8), dpi=80)
plt.suptitle('График зависимости В-фактора от расстояния до центра масс белка')
ax = []
plt.xlabel("Расстояние, ангстремы")
plt.ylabel("В-фактор")
plt.xlim(0, 35)
plt.ylim(0, 90)
sns.scatterplot(x = data["to_center"], y = data["B-factor"])
На графике видно, что, конечно, с ростом расстояния от центра увеличивается величина В-фактора, причем, по первому взгляду, зависимость наблюдается практически линейная с присутствием некоторого разброса, который может объясняться иными факторами (например, положение центра масс каждого остатка, а не только расстояние между ним и общим центром масс).
Посмотрим на величину пирсоновского коэффициента корреляции.
corr, _ = pearsonr(data["to_center"], data["B-factor"])
print('Pearsons correlation: %.3f' % corr)
Как и предполагалось, мы наблюдаем достаточно высокий коэффициент корреляции между данными параметрами.
linear_regression = LinearRegression()
X_train, X_test, y_train, y_test = train_test_split(data["to_center"].values, data["B-factor"].values, test_size=0.33)
linear_regression.fit(X_train.reshape(-1, 1), y_train)
print("Coef: ", round(linear_regression.coef_[0], 4), "; Intercept: ", round(linear_regression.intercept_, 4))
i = 0
x_reg = [i for i in range(34)]
y_reg = [k*1.6658 + 12.9251 for k in x_reg]
plt.figure(figsize=(10, 8), dpi=80)
plt.suptitle('График зависимости В-фактора от расстояния до центра масс белка с регрессионной прямой')
ax = []
plt.xlabel("Расстояние, ангстремы", fontsize = 13)
plt.ylabel("В-фактор", fontsize = 13)
plt.xlim(0, 35)
plt.ylim(0, 90)
sns.scatterplot(x = data["to_center"], y = data["B-factor"], label = "True points")
sns.lineplot(x = x_reg, y = y_reg, color = 'red', label = "Regression line")
plt.legend(fontsize = 13)
linear_regression.score(X_test.reshape(-1, 1), y_test)
Мы наблюдает достаточно невысокое качество полученной модели, так как входных данных, как мне кажется, не достаточно для более точной модели. Построим линейную модель, которая использует большее количество параметров, а именно, координаты центра масс для каждого остатка.
X_many = data[["x_mass", "y_mass", "z_mass", "to_center"]]
y_many = data["B-factor"]
X_train, X_test, y_train, y_test = train_test_split(X_many, y_many, test_size=0.33)
linear_regression = LinearRegression()
linear_regression.fit(X_train, y_train)
linear_regression.score(X_test, y_test)
linear_regression.coef_
y_pred = linear_regression.predict(X_test)
plt.figure(figsize=(10, 8), dpi=80)
plt.suptitle('График зависимости В-фактора от расстояния до центра масс белка с регрессионной прямой')
ax = []
plt.xlabel("Расстояние, ангстремы", fontsize = 13)
plt.ylabel("В-фактор", fontsize = 13)
plt.xlim(0, 35)
plt.ylim(0, 90)
sns.scatterplot(x = X_test["to_center"], y = y_test, label = "True points")
sns.scatterplot(x = X_test["to_center"], y = y_pred, label = "Predicted points", color = 'red')
В данной модели мы видим на порядок более высокое качество по сравнению с обычной линейной регрессией, такую модель, возможно, можно использовать для предсказания B-факторов других структур.
out = {}
for i in range(1,51):
regr = RandomForestRegressor(n_estimators=i)
regr.fit(X_train, y_train)
pred = regr.predict(X_test)
out[i] = r2_score(y_test, pred)
out
Можно сказать, что начиная с 6 деревьев качество модели перестает очевидно расти. Остановимся на этом количестве и построим такую модель, оценим качество ее работы численно и графически.
regr = RandomForestRegressor(n_estimators=6)
regr.fit(X_train, y_train)
pred = regr.predict(X_test)
regr.score(X_test, y_test)
plt.figure(figsize=(10, 8), dpi=80)
plt.suptitle('График зависимости В-фактора от расстояния до центра масс белка с регрессионной прямой')
ax = []
plt.xlabel("Расстояние, ангстремы", fontsize = 13)
plt.ylabel("В-фактор", fontsize = 13)
plt.xlim(0, 35)
plt.ylim(0, 90)
sns.scatterplot(x = X_test["to_center"], y = y_test, label = "True points")
sns.scatterplot(x = X_test["to_center"], y = pred, label = "Predicted points", color = 'red')
Данная модель работает немного лучше, чем линейная со множественными параметрами; способна не занижать точки на краях и показывает чуть больший разброс. И хотя тест качества проводился на тестовой выборке, это все равно может отражать переобучение под конкретную модель.
structure = pr.parsePDB('7PNH')
selection = structure.select('protein')
hv = selection.getHierView()
hv
B_factors = np.zeros((129, 6))
for i, residue in enumerate(hv.iterResidues()):
B_factors[i][1] = np.mean(residue.getBetas())
B_factors[i][0] = residue.getResnum()
string = "resnum "
string+= str(residue.getResnum())
group = structure.select(string)
B_factors[i][2], B_factors[i][3], B_factors[i][4] = pr.calcCenter(group, weights=group.getMasses())
data = pd.DataFrame(B_factors, columns = ["Number", "B-factor", "x_mass", "y_mass", "z_mass", "to_center"])
whole_protein_mass = pr.calcCenter(selection, weights=selection.getMasses())
for index, row in data.iterrows():
row["to_center"] = np.sqrt((row["x_mass"] - whole_protein_mass[0])**2 + (row["y_mass"] - whole_protein_mass[1])**2 + (row["z_mass"] - whole_protein_mass[2])**2)
data.head()
plt.figure(figsize=(10, 8), dpi=80)
plt.suptitle('График зависимости В-фактора от расстояния до центра масс белка')
ax = []
plt.xlabel("Расстояние, ангстремы")
plt.ylabel("В-фактор")
plt.xlim(0, 30)
plt.ylim(0, 60)
sns.scatterplot(x = data["to_center"], y = data["B-factor"])
Запустим линейную модель.
X = data[["x_mass", "y_mass", "z_mass", "to_center"]]
y = data["B-factor"]
y_pred = linear_regression.predict(X)
plt.figure(figsize=(10, 8), dpi=80)
plt.suptitle('График зависимости В-фактора от расстояния до центра масс белка с регрессионной прямой')
ax = []
plt.xlabel("Расстояние, ангстремы", fontsize = 13)
plt.ylabel("В-фактор", fontsize = 13)
plt.xlim(0, 35)
plt.ylim(-5, 90)
sns.scatterplot(x = X["to_center"], y = y, label = "True points")
sns.scatterplot(x = X["to_center"], y = y_pred, label = "Predicted points", color = 'red')
Запустим случайный лес.
y_pred = regr.predict(X)
plt.figure(figsize=(10, 8), dpi=80)
plt.suptitle('График зависимости В-фактора от расстояния до центра масс белка с регрессионной прямой')
ax = []
plt.xlabel("Расстояние, ангстремы", fontsize = 13)
plt.ylabel("В-фактор", fontsize = 13)
plt.xlim(0, 35)
plt.ylim(-5, 90)
sns.scatterplot(x = X["to_center"], y = y, label = "True points")
sns.scatterplot(x = X["to_center"], y = y_pred, label = "Predicted points", color = 'red')
Как мы видим, в данном случае и линейная модель, и случайный лес, работают достаточно плохо, хотя множественная линейная модель имеет визуально более высокое качество. Наверно, для описания такой взаимосвязи можно использовать линейные модели со множеством параметров, однако, обучать их стоит на совокупности данных большого количества белковых структур. Более сложные модели также могут лучше справиться с описанием данной зависимости.