R: добавление к фрейму данных в цикле for

Итак, у меня есть этот цикл, и он записывает несколько файлов csv, каждый из которых был добавлен из результатов запуска. Как вы можете видеть ниже, этот конкретный цикл запускает статистическую функцию (zScore) для каждой строки подмножества из gex против mxy, затем публикует результаты для каждой строки, а затем переходит к следующему подмножеству gex.

Мой вопрос: вместо того, чтобы записывать добавленный результат в виде файла csv, есть ли способ, которым я могу просто создать кадр данных в цикле, который выглядит одинаково?

Спасибо за вашу помощь.

gex <- data.frame("sample" =  c("BIX","HEF","TUR","ZOP","VAG"), 
                  "TCGA-F4-6703-01" = runif(5, -1, 1),
                  "TCGA-DM-A28E-01" = runif(5, -1, 1),
                  "TCGA-AY-6197-01" = runif(5, -1, 1),
                  "TCGA-A6-5657-01" = runif(5, -1, 1))
colnames(gex) <- gsub("[.]", "_",colnames(gex))

listx <- c("TCGA_DM_A28E_01","TCGA_A6_5657_01")

mxy <- data.frame("TCGA-AD-6963-01" = runif(5, -1, 1),
                  "TCGA-AA-3663-11" = runif(5, -1, 1),
                  "TCGA-AD-6901-01" = runif(5, -1, 1),
                  "TCGA-AZ-2511-01" = runif(5, -1, 1),
                  "TCGA-A6-A567-01" = runif(5, -1, 1)) 

colnames(mxy) <- gsub("[.]", "_",colnames(mxy))

zScore <- function(x,y)((as.numeric(x) - as.numeric(rowMeans(y,na.rm=T)))/as.numeric(sd(y,na.rm=T)))

   for(i in seq(nrow(mxy))){
      for(colName in listx){
        zvalues <- zScore(gex[i,colName],
                          mxy[i,])
        geneexptest <- data.frame(gex$sample[i], zvalues, row.names = NULL, 
                                  stringsAsFactors = TRUE)
        write.table(geneexptest, file = paste0(colName, "mxyinput", ".csv"),
                    row.names=FALSE, col.names=FALSE,  quote=F,
                    sep = ",", dec = ".", append=(i > 1))
      }
    }

person Henri Wathieu    schedule 05.02.2015    source источник
comment
Объявить кадр данных вне цикла, а затем использовать rbind или cbind для добавления строк или столбцов в каждой итерации цикла?   -  person Sam Firke    schedule 05.02.2015
comment
Привет @SamFirke, спасибо за отзыв - как мне объявить фрейм данных вне цикла, при этом используя каждую итерацию цикла?   -  person Henri Wathieu    schedule 05.02.2015
comment
@SamFirke, как правило, это довольно неэффективно в R - посмотрите Круг 2 в R Ад.   -  person josliber♦    schedule 05.02.2015
comment
Спасибо за ссылку @josilber, я знаю, что вообще следует избегать циклов for в R, но не знал о последствиях для памяти. @HenriW, см. решение josilber; вы можете сначала создать фрейм данных, как это делает он, а затем добавлять его на каждой итерации цикла, используя вызов rbind, но его решение с lapply лучше, как он объясняет.   -  person Sam Firke    schedule 05.02.2015


Ответы (1)


В вашем опубликованном коде у вас есть один CSV-файл для каждого элемента listx, и вы записываете несколько строк одну за другой в каждый из этих файлов. Вместо этого вы можете создать фрейм данных для каждого элемента listx и записать каждый с помощью одного вызова write.table.

dfs <- lapply(listx, function(colName) {
  do.call(rbind, lapply(seq(nrow(mxy)), function(i) {
    zvalues <- zScore(gex[i,colName], mxy[i,])
    data.frame(gex$sample[i], zvalues, row.names = NULL, stringsAsFactors = TRUE)
  }))
})
dfs
# [[1]]
#   gex.sample.i.    zvalues
# 1           BIX  1.1105593
# 2           HEF  0.5451948
# 3           TUR -1.4060388
# 4           ZOP -1.4218218
# 5           VAG  0.2780513
# 
# [[2]]
#   gex.sample.i.   zvalues
# 1           BIX 2.0607386
# 2           HEF 1.6703912
# 3           TUR 1.3249181
# 4           ZOP 0.8865058
# 5           VAG 1.5289732

Теперь вы можете вывести полный фрейм данных для каждого столбца, используя write.table.

Объединение всех фреймов данных вместе в одном вызове rbind будет намного эффективнее, чем вызов rbind на каждой итерации цикла; см. Круг 2 в R Inferno для получения более подробной информации.

person josliber♦    schedule 05.02.2015
comment
Я понимаю ваши изменения с точки зрения эффективности, но это не так, как мне хотелось бы. Моя проблема в том, что, как вы можете видеть в OP, я пишу geneexptest каждый раз, когда создаю его. Ключом является опция append=(i > 1) в write.table. Я хочу сделать то же самое, но манипулировать geneexptest (в его добавленной форме...) в другой фрейм данных, а ЗАТЕМ записать его в csv. (Затем переходите к следующему раунду и т. д.). Любая идея, как я мог это сделать? - person Henri Wathieu; 09.02.2015
comment
@HenriW этот код добавляет каждый geneexptest в один фрейм данных. Вы можете просто записать это в файл в конце с write.table. К сожалению, ваш исходный пост не воспроизводим (я не могу запустить ваш код в том виде, в котором он опубликован), поэтому сложно точно воспроизвести его функциональность. Я бы посоветовал вам обновить свой вопрос, чтобы сделать его воспроизводимым, если вам нужна дополнительная помощь. - person josliber♦; 10.02.2015
comment
Я приложил некоторые материалы для создания соответствующих входных данных - пожалуйста, дайте мне знать, что вы думаете. Так вот, хотелось бы, чтобы у него был такой же функционал, но с возможностью включения каких-то дополнительных манипуляций ДО вывода каждого раунда в write.table. Вот почему я спросил о добавлении фреймов данных в цикл for. - person Henri Wathieu; 13.02.2015
comment
@HenriW Я обновил свой код на основе вашего обновленного вопроса. Это действительно подчеркивает важность публикации воспроизводимого примера вашей проблемы в ваших вопросах на SO. - person josliber♦; 14.02.2015
comment
Очень полезно!! Итак, последнее: я пытаюсь модулировать вещи внутри цикла, который теперь показан в дополнении к исходному сообщению. Там вы можете видеть, что последний data.frame(...) пытается произвести geneexptotal, а не geneexptest, как раньше. Однако то, что производится, на самом деле geneexptestapp. Есть ли причина, по которой он останавливается в этот момент? - person Henri Wathieu; 16.02.2015
comment
@HenriW в целом лучше задавать новые вопросы, если у вас есть новые проблемы с программированием, а не редактировать старые - это гарантирует, что все сообщество увидит вашу новую проблему. Если мой ответ решил ваш первоначальный вопрос, я бы посоветовал вам принять его и задать новый вопрос с вашей новой проблемой. - person josliber♦; 16.02.2015