Кодирование R-ight way - избегая цикла for - PullRequest
4 голосов
/ 14 марта 2010

Я просматриваю один из моих файлов .R и, немного его почистив, пытаюсь ближе познакомиться с написанием кода. Как начинающий, одна из моих любимых отправных точек - избавиться от циклов for() и попытаться преобразовать выражение в форму функционального программирования. Итак, вот сценарий:

Я собираю группу data.frames в list для дальнейшего использования.

dataList <- list (dataA,
                  dataB,
                  dataC,
                  dataD,
                  dataE
                  )

Теперь я хотел бы взглянуть на имена столбцов каждого data.frame и заменить некоторые строки символов. Например, мне нравится заменять каждое "foo" и "bar" на "baz". В данный момент я выполняю работу с циклом for(), который выглядит немного неловко.

colnames(dataList[[1]])
[1] "foo"        "code" "lp15"       "bar"       "lh15"  
colnames(dataList[[2]])
[1] "a"        "code" "lp50"       "ls50"       "foo"  

matchVec <- c("foo", "bar")
for (i in seq(dataList)) {
  for (j in seq(matchVec)) {
    colnames (dataList[[i]])[grep(pattern=matchVec[j], x=colnames (dataList[[i]]))] <- c("baz")
  }
}

Поскольку я работаю здесь с list, я подумал о функции lapply. Все мои попытки справиться с работой с помощью функции lapply выглядят хорошо, но только на первый взгляд. Если я напишу

f <- function(i, xList) {
  gsub(pattern=c("foo"), replacement=c("baz"), x=colnames(xList[[i]]))
}
lapply(seq(dataList), f, xList=dataList)

последняя строка выводит почти то, что я ищу. Однако, если я еще раз посмотрю на фактические имена data.frames в dataList:

lapply (dataList, colnames)

Я вижу, что в исходные строки символов не было внесено никаких изменений.

Итак, как мне переписать цикл for() и преобразовать его в функциональную форму программирования? И как мне эффективно заменить обе строки, "foo" и "bar"? Поскольку функция gsub() принимает в качестве аргумента pattern только символьный вектор длины один.

1 Ответ

9 голосов
/ 14 марта 2010

Ваш код почти работает, но помните, что R создает копии объектов, которые вы модифицируете (т.е. семантика передачи по значению). Поэтому вам нужно явно назначить новую строку для имен столбцов, например:

dataA <- dataB <- data.frame(matrix(1:20,ncol=5))
names(dataA) <- c("foo","code","lp15","bar","lh15")
names(dataB) <- c("a","code","lp50","ls50","foo")
dataList <- list(dataA, dataB)
f <- function(i, xList) {
  colnames(xList[[i]]) <- gsub(pattern=c("foo|bar"), replacement=c("baz"), x=colnames(xList[[i]]))
  xList[[i]]
}
dataList <- lapply(seq(dataList), f, xList=dataList)

В новом списке будут фреймы данных с замененными именами. С точки зрения замены как foo, так и bar, просто используйте альтернативный шаблон в регулярном выражении в gsub ("foo | bar").

Заметьте, кстати, что вам не нужно делать это путем индексации в вашем списке - просто используйте функцию, которая работает непосредственно с элементами вашего списка:

f <- function(df) {
  colnames(df) <- gsub(pattern=c("foo|bar"), replacement=c("baz"), x=colnames(df))
  df
}
dataList <- lapply(dataList, f)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...