Группа / Объединить несколько столбцов в R - PullRequest
0 голосов
/ 06 декабря 2018

У меня есть файл данных с n столбцами, разделенными на 3 группы, и каждая группа имеет несколько тем.Таким образом, заголовки G1S1, G1S2 ... G2S1, G2S2 .. Данные в каждом столбце не зависят от других столбцов.То, что я пытаюсь сделать, это поместить все данные из группы 1 в колонку 1.Группа 2 в столбце 2 и т. Д. Я попробовал следующий код, который работает для помещения всех данных из группы 1 в новый кадр данных с одним столбцом G1 в качестве заголовка.

dt <-TestFile [1:5] # extract data from group 1
dt2 <- NULL
tmp1 <- NULL

for (i in 1:ncol(dt)) {
  ColName <- names(dt)[i] #Get the column mame
  tmp1 <- dt[ColName] #copy data to tmp1
  GrpName <- substring(ColName,1,2) #get group name from column name
  names(tmp1)[names(tmp1)==ColName]<-GrpName #rename column header to match column in dt2 '
  dt2 <- rbind (dt2,tmp1) # merge data together
}

Этот код работает для одной группы, однако, если я хочу добавить другую группу, я застрял, потому что функция rbin больше не работает, так как количество столбцов больше не совпадает.

Если я добавлю эти операторы iff в цикл, я смогу создать 3 data.frames, но если я получу файлы с разными номерами групп, мне придется добавить больше операторов if, и это не жизнеспособно в долгосрочной перспективе.

if (GrpName == 'G1'){
    dt1 <- rbind (dt1,tmp1) # merge data together}
  }
  if(GrpName == 'G2'){
    dt2 <- rbind (dt2,tmp1) # merge data together}
  }

  if(GrpName == 'G3'){
    dt3 <- rbind (dt3,tmp1) # merge data together}

  }

Любой совет по поводу того, куда можно пойти отсюда?

1 Ответ

0 голосов
/ 06 декабря 2018

Используя некоторые примеры данных:

dat <- read.table(stringsAsFactors=FALSE, header=TRUE, text="
G1S1 G1S2 G1S3 G2S1 G2S2 G2S3 G3S1 G3S2 G3S3
111  121  131  211  221  231  311  321  331
112  122  132  212  222  232  312  322  332
113  123  133  213  223  233  313  323  333")

Желая разделить только по второму символу каждого имени, давайте сначала узнаем, как отделить это от остальных:

gsub("S.*", "", names(dat))
# [1] "G1" "G1" "G1" "G2" "G2" "G2" "G3" "G3" "G3"

Теперь мы хотим выделить столбцы в эти три группы.Одним из способов является split их.Если мы используем split сам по себе, он не будет работать:

split(dat, gsub("S.*", "", names(dat)))
# Warning in split.default(x = seq_len(nrow(x)), f = f, drop = drop, ...) :
#   data length is not a multiple of split variable
# $G1
#   G1S1 G1S2 G1S3 G2S1 G2S2 G2S3 G3S1 G3S2 G3S3
# 1  111  121  131  211  221  231  311  321  331
# 2  112  122  132  212  222  232  312  322  332
# 3  113  123  133  213  223  233  313  323  333
# $G2
# [1] G1S1 G1S2 G1S3 G2S1 G2S2 G2S3 G3S1 G3S2 G3S3
# <0 rows> (or 0-length row.names)
# $G3
# [1] G1S1 G1S2 G1S3 G2S1 G2S2 G2S3 G3S1 G3S2 G3S3
# <0 rows> (or 0-length row.names)

Это потому, что split видит, что он работает на data.frame и пытается делать что-то построчное, чтоэто не то, что мы хотим.Если вы ищите, есть ряд split S3 методов (функций, которые имеют конкретные версии на основе первого аргумента):

methods("split")
# [1] split.data.frame split.Date       split.default    split.POSIXct   
# see '?methods' for accessing help and source code

Версия, которую мы молча использовали, это split.data.frame, потому чтоdat это рамка.Мы можем переопределить это:

lodf <- split.default(dat, gsub("S.*", "", names(dat)))
lodf
# $G1
#   G1S1 G1S2 G1S3
# 1  111  121  131
# 2  112  122  132
# 3  113  123  133
# $G2
#   G2S1 G2S2 G2S3
# 1  211  221  231
# 2  212  222  232
# 3  213  223  233
# $G3
#   G3S1 G3S2 G3S3
# 1  311  321  331
# 2  312  322  332
# 3  313  323  333

Отсюда: я лично рекомендую хранить их в этой структуре list -фреймов (эрго мое временное имя lodf).Это сделано при условии, что что-то, что вы делаете с одним, вы будете делать (то же самое) с другими, и в этом случае lapply является естественным выбором для операций.

Если вам действительно нужно прерватьэто вниз (опять же, обескураженный), вы можете назначить их как имена групп для вызывающей среды с помощью:

for (nm in names(lodf)) assign(nm, lodf[[nm]])
ls()
# [1]  "dat"   "G1"   "G2"   "G3" "lodf"

Ответ, связанный с фреймами в списках: Как мне сделатьсписок фреймов данных?


Вы могли бы сделать еще один шаг, возможно, справиться с этим в «аккуратном» (т. е. «длинном») формате: включить группу в сами фреймы:

do.call(rbind.data.frame, c(mapply(function(nm, x) {
  # remove the 'G#' from each column name, allows row-binding later
  names(x) <- gsub(paste0("^", nm), "", names(x))
  # add the group name as a new column
  transform(x, Grp = nm)
}, names(lodf), lodf, SIMPLIFY = FALSE), list(stringsAsFactors = FALSE)))
#       S1  S2  S3 Grp
# G1.1 111 121 131  G1
# G1.2 112 122 132  G1
# G1.3 113 123 133  G1
# G2.1 211 221 231  G2
# G2.2 212 222 232  G2
# G2.3 213 223 233  G2
# G3.1 311 321 331  G3
# G3.2 312 322 332  G3
# G3.3 313 323 333  G3

(мне не нравятся имена строк G1.1 и т. Д., Но они безвредны.) Объяснение:

  • mapply похоже на lapply за исключением того, что для каждого вызова функции требуется 1 или более аргументов, что фактически позволяет "сжать" список аргументов вместе.Аргументами для этого являются names(lodf) и lodf, поэтому первый вызов (вызов anonfunc анонимной функции, принимающей в качестве аргументов (nm, x)) выглядит как anonfunc(names(lodf)[[1]], lodf[[1]]), второй anonfunc(names(lodf)[[2]], lodf[[2]]) и т. Д.
  • внутри этой анонимной функции я сначала удаляю G# из имен столбцов.Это позволяет нам связывать их позже как S1, S2 и т. Д.
  • Я добавляю имя группы в кадры как Grp.

Этот форматпозволяет сделать одну вещь один раз , применяя группировку по переменной Grp по мере необходимости.Например, если вы используете dplyr или data.table, это довольно просто сделать ... %>% dplyr::group_by(Grp) %>% ... или DT[, .(...), by="Grp"], соответственно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...