Автор Сохил Шах [LinkedIn] [GitHub]

Соавторы: Николас Джангреко [LinkedIn] [GitHub], Хорди Франк [LinkedIn] [GitHub] и Мэтью Энг [LinkedIn] [GitHub]

Это пост 3 из 4-х частей серии по геномике рака. Вы можете найти код из этого поста на Github. Если нет, ознакомьтесь с Постом 1, в котором объясняется, как нужна геномная перспектива для поиска новых методов лечения рака печени, и Постом 2, в котором подробно рассказывается о исследовательском анализе, иллюстрирующем общедоступные геномные данные о раке печени.

Этот пост прольет свет на то, как мы использовали подход к обучению без учителя для выявления основных закономерностей между данными RNA-Seq, представляющими отличительные признаки рака, и прогрессированием рака печени (т. Е. Стадией опухоли). В качестве нашей исходной гипотезы существует связь между членством пациентов в кластере, полученным на основе данных об экспрессии генов, и стадией рака печени пациента.

Подход к обучению без учителя помогает раскрыть структуру данных для установления отношений без каких-либо ранее назначенных меток. Мы сгруппировали пациентов, используя их экспрессию генов и клиническую информацию, в кластеры, используя алгоритмы уменьшения размеров и кластеризации. Мы использовали объединенный набор данных, созданный во втором сообщении в блоге, и удалили информацию о стадии рака печени (т. Е. Метки). Мы ограничили нашу методологию только теми 4220 генами, которые представляют признаки рака.

full_df_stage = pd.merge(rnaseq_sub.reset_index(), clinical[['submitter_id','gender','race','ethnicity','tumor_stage']], left_on='bcr_patient_barcode', right_on='submitter_id', how='inner') \
    .set_index('bcr_patient_barcode') \
    .drop('submitter_id', axis=1)
#ensuring ID uniqueness
full_df_stage.index = [x + '-' + str(i) for i,x in enumerate(full_df_stage.index)]
print(full_df_stage.shape)
full_df_stage.head()

Машинное обучение - конвейер кластеризации:

Как мы видим в приведенном выше фрагменте данных, данные содержат данные об экспрессии генов по признакам рака и демографическую информацию, такую ​​как пол, раса, этническая принадлежность, пол и т. Д. На рисунке ниже показан весь наш конвейер сквозной кластеризации.

Категориальная кодировка:

В качестве первого шага после подготовки данных мы быстро закодировали категориальные поля, такие как пол, раса, пол и т. Д., Для использования в наших моделях машинного обучения. Как показано в приведенном ниже примере фрагмента данных, теперь у нас есть новые двоичные столбцы, такие как gender_female, race_asian и т. Д. После однократного кодирования. Мы использовали функцию get_dummies pandas ’для применения техники кодирования.

# One hot encoding on full data frame to convert categorical fields into binary fields
full_df_onehot = pd.get_dummies(full_df, drop_first=False)
full_df_onehot.head()

Стандартизация и масштабирование данных:

Как мы можем видеть в приведенном выше фрагменте данных, каждое выражение гена РНК имеет свой диапазон значений. Некоторые значения выражены в тысячах номиналов, а некоторые даже являются двоичными числами, полученными после категориального кодирования. Чтобы устранить смещение, вызванное различиями в масштабах данных, мы стандартизировали весь набор данных, используя метод масштабирования функций, называемый масштабирование минимум-максимум. Следовательно, этот подход к масштабированию функций сохраняет все значения функций в стандартном диапазоне от 0 до 1.

# Transforming the data within a range e.g. [0, 1]:Feature Scaling  
x = full_df_onehot_filter #returns a numpy array
min_max_scaler = preprocessing.MinMaxScaler()
x_scaled = min_max_scaler.fit_transform(x)
genome_clinic_df = pd.DataFrame(x_scaled,columns=full_df_onehot_filter\
            .loc[:, full_df_onehot_filter.columns != 'index'].columns)
# Standardized data fame
index_df = full_df_onehot_filter.reset_index()
genome_clinic_std_concat = pd.concat([index_df['index'],genome_clinic_df],axis=1)genome_clinic_std_concat.set_index('index', inplace=True)
genome_clinic_std_concat.head()

Как видно из приведенного выше фрагмента, масштабирование функции нормализовало высокие значения шкалы также между 0 и 1.

Уменьшение размерности с помощью разреженного PCA:

После преобразований данных, описанных выше, мы все еще имели дело с пространством функций очень большой размерности, что означает, что около 4200+ функций описывают набор данных. Чтобы подход кластеризации K-средних работал правильно, мы должны сосредоточиться на представлении функций в более низком измерении. Следовательно, мы применили один из самых известных методов - Анализ главных компонентов (PCA), который может уменьшить пространство признаков нашего набора данных с 4200+ столбцов до двух основных компонентов, улавливающих наибольшую вариативность, объясняющую структуру набора данных.

В любом конкретном образце экспрессируются тысячи генов, но у пациента могут быть очень разные гены, экспрессируемые в зависимости от таких факторов, как тип ткани, метод отбора образцов и время отбора образцов. Это означает, что пространство функций среди наших выборок сильно разрежено. Мы использовали разреженный модуль PCA , доступный в библиотеке scikit learn в Python . Этот модуль помогает сократить пространство функций до наиболее вариативных функций (также называемых основными компонентами или ПК), а также справиться с разреженностью данных. В следующем фрагменте объясняется, как данные сужаются до двух основных компонентов, вносящих наибольший вклад в вариации.

# Dimensionality Reduction using Principal Component Analysis 
from sklearn.decomposition import PCA, SparsePCA
n=2
pcs = ['PC'+str(x) for x in range(n)]
pca = SparsePCA(n_components=n,max_iter=20,n_jobs=4)
principalComponents = pca.fit_transform(genome_clinic_std_concat)
#print(pca.explained_variance_)
principalDf = pd.DataFrame(data = principalComponents
             , columns = pcs)
principalDfConcat = pd.concat([index_df['index'],principalDf],axis=1)
principalDfConcat.head()

Кластеризация K-средних:

  1. Определение оптимального количества кластеров:

Теперь у нас есть двухмерное представление наших данных, которое способствует процессу кластеризации. Кластеризация K-средних - это популярный алгоритм кластеризации, который сегментирует данные в K групп на основе базовых шаблонов данных. Мы использовали библиотеку sci-kit learn для применения кластеризации к основным компонентам. Информация о количестве кластеров, т.е. K, должна быть известна либо по базе знаний, либо по методу локтя. Мы подошли к методу локтя, чтобы определить лучшие K кластеров для нашего набора данных.

# Checking for best K when number of groups or clusters are not known - Used Elbow Plot. 
import matplotlib.pyplot as plt
distortions = []
for k in range(1,11):
    kmeans = KMeans(
        n_clusters=k, init = "random",
        n_init=10, max_iter=300, random_state=0
    )
    kmeans.fit(principalDfConcat.set_index('patient_id'))
    distortions.append(kmeans.inertia_)
    
#plot
plt.plot(range(1,11), distortions, marker='o')
plt.xlabel("Number of clusters")
plt.ylabel("Distortions")
plt.show()

Приведенный выше график локтя не отображает точную структуру локтя. Однако первый изгиб находится при K = 3, что означает, что его можно считать лучшим выбором для количества кластеров. Таким образом, мы можем предположить, что эти три кластера представляют наши базовые данные.

2. Оценка сходства между результатами кластера и стадиями рака, указанными в клинических данных:

На этом этапе мы применили алгоритм K-средних, чтобы сгруппировать пациентов в три группы 0, 1 и 2. Эти кластеры представляют все данные. Но они по-прежнему не указывают информацию о стадии рака у пациента.

# Clustering Model building using KMeans and concatenating labels with the corresponding patient
#from scipy import stats
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters=3, random_state=0).fit(principalDfConcat.set_index('index'))
labels = kmeans.labels_
#Glue back to original data
principalDfConcat['clusters'] = labels
cols = ['patient_id']
cols.extend(pcs)
cols.extend(['clusters'])
principalDfConcat.columns= cols
principalDfConcat.head()

Чтобы подтвердить нашу первоначальную гипотезу о взаимосвязи между кластерами, представляющими экспрессию генов РНК пациентов на одном конце и стадиями рака печени на другом конце, мы вычислили процентное соотношение каждой группы кластеров и для каждой стадии рака.

#Validating relationship between clusters and liver cancer stages
df_stage_valid = pd.merge(df_stage[['index','tumor_stage']], principalDfConcat[['patient_id','clusters']], right_on='patient_id', left_on='index', how='left').set_index('patient_id') \
    .drop('index', axis=1)
#ensuring ID uniqueness
df_stage_valid.index = [x + '-' + str(i) for i,x in enumerate(df_stage_valid.index)]
df_stage_valid.head()

Приведенный выше фрагмент кода демонстрирует, как каждый репрезентативный кластер распространяется на несколько стадий рака. Мы наблюдаем из приведенных выше результатов, что вариации экспрессии генов не полностью отражают данные стадии опухоли для образцов. Возникает вопрос, а что общего между этими кластерами? Следовательно, в нашей следующей публикации мы сделаем глубокое погружение, чтобы понять, какие признаки рака связаны с каждой из стадий рака, используя подход контролируемой классификации.

Будьте на связи!