#r #cluster-analysis #hierarchical #rscript
#r #кластерный анализ #иерархический #rscript
Вопрос:
Я хотел бы выполнить иерархическую кластеризацию по строкам, а затем по столбцам. Я придумал этот полный взлом решения:
#! /path/to/my/Rscript --vanilla
args <- commandArgs(TRUE)
mtxf.in <- args[1]
clusterMethod <- args[2]
mtxf.out <- args[3]
mtx <- read.table(mtxf.in, as.is=T, header=T, stringsAsFactors=T)
mtx.hc <- hclust(dist(mtx), method=clusterMethod)
mtx.clustered <- as.data.frame(mtx[mtx.hc$order,])
mtx.c.colnames <- colnames(mtx.clustered)
rownames(mtx.clustered) <- mtx.clustered$topLeftColumnHeaderName
mtx.clustered$topLeftColumnHeaderName <- NULL
mtx.c.t <- as.data.frame(t(mtx.clustered), row.names=names(mtx))
mtx.c.t.hc <- hclust(dist(mtx.c.t), method=clusterMethod)
mtx.c.t.c <- as.data.frame(mtx.c.t[mtx.c.t.hc$order,])
mtx.c.t.c.t <- as.data.frame(t(mtx.c.t.c))
mtx.c.t.c.t.colnames <- as.vector(names(mtx.c.t.c.t))
names(mtx.c.t.c.t) <- mtx.c.colnames[as.numeric(mtx.c.t.c.t.colnames) 1]
write.table(mtx.c.t.c.t, file=mtxf.out, sep='t', quote=F, row.names=T)
Переменные mtxf.in
и mtxf.out
представляют входные матричные и кластеризованные выходные матричные файлы соответственно. Переменная clusterMethod
является одним из hclust
методов, таких как single
, average
, и т.д.
В качестве примера ввода приведем матрицу данных:
topLeftColumnHeaderName col1 col2 col3 col4 col5 col6
row1 0 3 0 0 0 3
row2 6 6 6 6 6 6
row3 0 3 0 0 0 3
row4 6 6 6 6 6 6
row5 0 3 0 0 0 3
row6 0 3 0 0 0 3
Запустив этот скрипт, я теряю свой верхний левый угловой элемент mtxf.in
. Вот результат, который получается из этого скрипта:
col5 col4 col1 col3 col2 col6
row6 0 0 0 0 3 3
row5 0 0 0 0 3 3
row1 0 0 0 0 3 3
row3 0 0 0 0 3 3
row2 6 6 6 6 6 6
row4 6 6 6 6 6 6
Мои вопросы: Помимо поиска способа сохранить исходную структуру файла входной матрицы, я также не знаю, сколько памяти это потребляет или существуют ли более быстрые и чистые, более «R»-подобные способы для этого.
Действительно ли так сложно кластеризоваться по строкам и столбцам в R? Есть ли конструктивные способы улучшить этот скрипт? Спасибо за ваш совет.
Комментарии:
1. На самом деле сейчас есть сайт для проверки кода, возможно, стоит попробовать и там / вместо этого. codereview.stackexchange.com
2. На самом деле я бы сказал, что вы, скорее всего, получите здесь помощь, специфичную для R.
Ответ №1:
После того, как вы очистили свои данные (т. Е. Удалили первый столбец), для этого действительно требуется всего три строки кода:
Очистить данные (назначить имена строк из первого столбца, затем удалить первый столбец):
dat <- mtfx.in
rownames(dat) <- dat[, 1]
dat <- dat[, -1]
Кластеризация и изменение порядка:
row.order <- hclust(dist(dat))$order
col.order <- hclust(dist(t(dat)))$order
dat[row.order, col.order]
Результаты:
col5 col4 col1 col3 col2 col6
row6 0 0 0 0 3 3
row5 0 0 0 0 3 3
row1 0 0 0 0 3 3
row3 0 0 0 0 3 3
row2 6 6 6 6 6 6
row4 6 6 6 6 6 6
Ответ №2:
Честно говоря, я не совсем понимаю, почему вы делаете некоторые вещи, которые вы делаете, поэтому вполне возможно, что я неправильно понял, что вы ищете. Если я далеко от базы, дайте мне знать, и я удалю этот ответ.
Но я подозреваю, что ваша жизнь будет намного проще (и ваши результаты действительно верны), если вы прочитаете свои данные в using row.names = 1
, чтобы указать, что первый столбец на самом деле является именами строк. Например:
#Read the data in
d1 <- read.table(textConnection("topLeftColumnHeaderName col1 col2 col3 col4 col5 col6
row1 0 3 0 0 0 3
row2 6 6 6 6 6 6
row3 0 3 0 0 0 3
row4 6 6 6 6 6 6
row5 0 3 0 0 0 3
row6 0 3 0 0 0 3"),
sep = "",as.is = TRUE,header = TRUE,
stringsAsFactors = TRUE,row.names = 1)
#So d1 looks like this:
d1
col1 col2 col3 col4 col5 col6
row1 0 3 0 0 0 3
row2 6 6 6 6 6 6
row3 0 3 0 0 0 3
row4 6 6 6 6 6 6
row5 0 3 0 0 0 3
row6 0 3 0 0 0 3
#Simple clustering based on rows
clus1 <- hclust(dist(d1))
d2 <- d1[clus1$order,]
d2
col1 col2 col3 col4 col5 col6
row6 0 3 0 0 0 3
row5 0 3 0 0 0 3
row1 0 3 0 0 0 3
row3 0 3 0 0 0 3
row2 6 6 6 6 6 6
row4 6 6 6 6 6 6
#Now cluster on columns and display the result
clus2 <- hclust(dist(t(d2)))
t(t(d2)[clus2$order,])
col5 col4 col1 col3 col2 col6
row6 0 0 0 0 3 3
row5 0 0 0 0 3 3
row1 0 0 0 0 3 3
row3 0 0 0 0 3 3
row2 6 6 6 6 6 6
row4 6 6 6 6 6 6
Поскольку вы отметили это code-review
, я думаю, я также укажу, что стилистически многие люди из R предпочитают не использовать T
and F
для логических значений, поскольку они могут быть замаскированы, в то время TRUE
как and FALSE
не может.
Комментарии:
1. Я смущен вашим ответом. Вы хотите сказать, что кластеризация, которую делает мой код, неверна? Похоже, вы получаете тот же конечный результат, что и я. В конечном счете, моя цель — сохранить данные во входных данных (например, метку в верхнем левом углу).
2. @AlexReynolds Извините; все, что я имел в виду, это то, что ваш текущий код фактически включает столбец имен строк в первом раунде кластеризации. Это означает, что этот фактор принудительно передается NAs by
dist
. Это работает для вашего примера, но я бы не стал полагаться на это в целом. Обратите внимание, что у Андри, как и у меня, этот столбец включает в себя имена строк. Однако его метод явно сохраняет ту информацию, которую вы хотите, поэтому я бы последовал его примеру.