Преобразование одного фрейма данных в список фреймов данных (разбор имен столбцов в префиксы и суффиксы) - PullRequest
3 голосов
/ 16 февраля 2020

Я надеюсь определить эффективный способ преобразования одного фрейма данных в список фреймов данных. Ниже приведен мой воспроизводимый MWE:

set.seed(1)
ABAge = runif(100)
ABPoints = rnorm(100)
ACAge = runif(100)
ACPoints = rnorm(100)
BCAge = runif(100)
BCPoints = rnorm(100)

A_B <- data.frame(ID = as.character(paste0("ID", 1:100)), Age = ABAge, Points = ABPoints)
A_C <- data.frame(ID = as.character(paste0("ID", 1:100)), Age = ACAge, Points = ACPoints)
B_C <- data.frame(ID = as.character(paste0("ID", 1:100)), Age = BCAge, Points = BCPoints)
A_B$ID <- as.character(A_B$ID)
A_C$ID <- as.character(A_C$ID)
B_C$ID <- as.character(B_C$ID)

listFormat <- list("A_B" = A_B, "A_C" = A_C, "B_C" = B_C)

dfFormat <- data.frame(ID = as.character(paste0("ID", 1:100)), A_B.Age = ABAge, A_B.Points = ABPoints, A_C.Age = ACAge, A_C.Points = ACPoints, B_C.Age = BCAge, B_C.Points = BCPoints)
dfFormat$ID = as.character(dfFormat$ID)

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

'data.frame':   100 obs. of  7 variables:
 $ ID        : chr  "ID1" "ID2" "ID3" "ID4" ...
 $ A_B.Age   : num  0.266 0.372 0.573 0.908 0.202 ...
 $ A_B.Points: num  0.398 -0.612 0.341 -1.129 1.433 ...
 $ A_C.Age   : num  0.6737 0.0949 0.4926 0.4616 0.3752 ...
 $ A_C.Points: num  0.409 1.689 1.587 -0.331 -2.285 ...
 $ B_C.Age   : num  0.814 0.929 0.147 0.75 0.976 ...
 $ B_C.Points: num  1.474 0.677 0.38 -0.193 1.578 ...

и список фреймов данных listFormat это выглядит так:

List of 3
 $ A_B:'data.frame':    100 obs. of  3 variables:
  ..$ ID    : chr [1:100] "ID1" "ID2" "ID3" "ID4" ...
  ..$ Age   : num [1:100] 0.266 0.372 0.573 0.908 0.202 ...
  ..$ Points: num [1:100] 0.398 -0.612 0.341 -1.129 1.433 ...
 $ A_C:'data.frame':    100 obs. of  3 variables:
  ..$ ID    : chr [1:100] "ID1" "ID2" "ID3" "ID4" ...
  ..$ Age   : num [1:100] 0.6737 0.0949 0.4926 0.4616 0.3752 ...
  ..$ Points: num [1:100] 0.409 1.689 1.587 -0.331 -2.285 ...
 $ B_C:'data.frame':    100 obs. of  3 variables:
  ..$ ID    : chr [1:100] "ID1" "ID2" "ID3" "ID4" ...
  ..$ Age   : num [1:100] 0.814 0.929 0.147 0.75 0.976 ...
  ..$ Points: num [1:100] 1.474 0.677 0.38 -0.193 1.578 ...

Я надеюсь предложить автоматизированный способ преобразования dfFormat в listFormat. Как видно из вышеприведенных объектов, есть два основных условия:

  1. Столбец ID всегда является первым столбцом в dfFormat и всегда является первым столбцом в каждом подсписке. из listFormat.

  2. Количество подсписков равно количеству уникальных имен столбцов в dfFormat перед подчеркиванием ('_'). В этом случае это три префикса (например, «A_B», «A_ C» и «B_ C»). Эти префиксы также являются именами трех подсписков.

  3. В каждом подсписке он содержит количество столбцов, имеющих связанный префикс («A_B»). Для каждого подсписка это было два («Возраст» и «Очки»). Эти суффиксы являются именами столбцов.

Я задал обратный вопрос здесь (т.е. как go с listFormat до dfFormat) и получил несколько полезных ответов, из которых я учусь. Мне нужно иметь код, чтобы поменять оба направления, и кажется, что обратному направлению могут потребоваться новые типы кода. Ниже я попытаюсь показать, как я застрял!

conUnd <- which(sapply(colnames(dfFormat), function(x) grepl("_", x)))
listName <- sapply(colnames(dfFormat[,conUnd]), function(x) strsplit(x, "[.]")[[1]][1])
uListName <- unique(sapply(colnames(dfFormat[,conUnd]), function(x) strsplit(x, "[.]")[[1]][1]))
listCol <- sapply(colnames(dfFormat[,conUnd]), function(x) strsplit(x, "[.]")[[1]][2])

listFormat = list()
for (i in 1:length(uListName)){
   [Gets messy here trying to define column names based on string variables]
}

Буду признателен за любой совет. Я знаю, что мой код неэффективен.

Ответы [ 3 ]

4 голосов
/ 16 февраля 2020

Вы можете использовать split.default в базе R -

output <- lapply(split.default(dfFormat[-1], sub("\\..*", "",names(dfFormat[-1]))), 
          function(x) cbind(dfFormat[1], setNames(x, sub(".*\\.", "", names(x)))))
str(output)

#List of 3
# $ A_B:'data.frame':   100 obs. of  3 variables:
#  ..$ ID    : chr [1:100] "ID1" "ID2" "ID3" "ID4" ...
#  ..$ Age   : num [1:100] 0.266 0.372 0.573 0.908 0.202 ...
#  ..$ Points: num [1:100] 0.398 -0.612 0.341 -1.129 1.433 ...
# $ A_C:'data.frame':   100 obs. of  3 variables:
#  ..$ ID    : chr [1:100] "ID1" "ID2" "ID3" "ID4" ...
#  ..$ Age   : num [1:100] 0.6737 0.0949 0.4926 0.4616 0.3752 ...
#  ..$ Points: num [1:100] 0.409 1.689 1.587 -0.331 -2.285 ...
# $ B_C:'data.frame':   100 obs. of  3 variables:
#  ..$ ID    : chr [1:100] "ID1" "ID2" "ID3" "ID4" ...
#  ..$ Age   : num [1:100] 0.814 0.929 0.147 0.75 0.976 ...
#  ..$ Points: num [1:100] 1.474 0.677 0.38 -0.193 1.578 ...
2 голосов
/ 16 февраля 2020

Решение с использованием tidyverse. Он включает в себя преобразование фрейма данных в длинный формат, разделение столбцов, распространение его и разделение фрейма данных на основе имени группы. В последней строке as.data.frame(stringsAsFactors = FALSE) не требуется, поскольку tibble также является data frame. Я добавил его, чтобы показать, что вывод совпадает с ожидаемым списком.

library(tidyverse)

listFormat_output <- dfFormat %>%
  pivot_longer(cols = -ID, names_to = "Type") %>%
  separate(Type, into = c("Group", "Parameter"), sep = "\\.") %>%
  pivot_wider(names_from = Parameter) %>%
  group_split(Group) %>%
  setNames(nm = map_chr(., ~unique(.x$Group))) %>%
  map(~.x %>% select(-Group) %>% as.data.frame(stringsAsFactors = FALSE))

# Check if the output is the same as the expected list
identical(listFormat, listFormat_output)
# [1] TRUE
0 голосов
/ 16 февраля 2020

Использование mget, ls и регулярное выражение, кажется, получают то, что вы хотите.

ДАННЫЕ :

Редактировать : Ваш фрейм данных dfFormat, который имеет такую ​​структуру:

str(dfFormat)
'data.frame':   100 obs. of  7 variables:
 $ ID        : chr  "ID1" "ID2" "ID3" "ID4" ...
 $ A_B.Age   : num  0.266 0.372 0.573 0.908 0.202 ...
 $ A_B.Points: num  0.398 -0.612 0.341 -1.129 1.433 ...
 $ A_C.Age   : num  0.6737 0.0949 0.4926 0.4616 0.3752 ...
 $ A_C.Points: num  0.409 1.689 1.587 -0.331 -2.285 ...
 $ B_C.Age   : num  0.814 0.929 0.147 0.75 0.976 ...
 $ B_C.Points: num  1.474 0.677 0.38 -0.193 1.578 ...

SOLUTION :

Решение выбирает имена столбцов в dfFormat, соответствующие столбцам, по которым вы хотите преобразовать кадр данных в список, используя регулярное выражение:

listFormat <-  mget(ls(pattern = "^A_B|^A_C|^B_C"))

РЕЗУЛЬТАТ :

str(listFormat)
List of 3
 $ A_B:'data.frame':    100 obs. of  3 variables:
  ..$ ID    : chr [1:100] "ID1" "ID2" "ID3" "ID4" ...
  ..$ Age   : num [1:100] 0.266 0.372 0.573 0.908 0.202 ...
  ..$ Points: num [1:100] 0.398 -0.612 0.341 -1.129 1.433 ...
 $ A_C:'data.frame':    100 obs. of  3 variables:
  ..$ ID    : chr [1:100] "ID1" "ID2" "ID3" "ID4" ...
  ..$ Age   : num [1:100] 0.6737 0.0949 0.4926 0.4616 0.3752 ...
  ..$ Points: num [1:100] 0.409 1.689 1.587 -0.331 -2.285 ...
 $ B_C:'data.frame':    100 obs. of  3 variables:
  ..$ ID    : chr [1:100] "ID1" "ID2" "ID3" "ID4" ...
  ..$ Age   : num [1:100] 0.814 0.929 0.147 0.75 0.976 ...
  ..$ Points: num [1:100] 1.474 0.677 0.38 -0.193 1.578 ...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...