#r #combinations
Вопрос:
Из приведенного ниже фрейма данных z я хотел бы сгенерировать список новых фреймов данных, в которых каждый фрейм данных основан на уникальной комбинации 3 различных значений вектора имен. В приведенном ниже фрейме данных у меня есть 5 разных имен в столбце Имя (у них несколько записей репликации). Количество различных комбинаций из 3 равно 10 (при выборке без замены и порядка не важно). хотя выбор основан на векторе имени, я бы хотел, чтобы новые кадры данных включали другие столбцы информации. В данном случае в графе «Голосование». Я также хотел бы, чтобы помимо этих двух столбцов каждый фрейм данных содержал два дополнительных столбца со строками, которые не были выбраны. Например, если вы запустите код ниже первого кадра данных в combdf, будет содержать Джона, Ли, Сьюзен и их голоса. Но я не мог найти/понять, как добавить в этот фрейм данных два столбца для оставшихся двух имен и их голосов, и так далее для остальных из них. В этих двух столбцах будет меньше строк, поэтому я согласен с NA для недостающих ячеек.
Name <- c("Jhon", "Lee", "Suzan", "Abhinav",
"Brain")
Vote <- letters[1:21]
z <- as.data.frame (cbind(Name, Vote))
comb<-combn(unique(as.character(z$Name)), 3)
combdf <- apply(comb, 2, function(vec) z[ z$Name %in% vec, ] )
Ответ №1:
Один из более простых вариантов-использовать bind_rows
filter
ed с » vec » в «Имени» и вторыми данными без них, переименовать его так, чтобы он создавал новые столбцы, заполненные NA
library(dplyr)
out <- z %>%
pull(Name) %>%
unique %>%
combn(., 3, FUN = function(vec)
z %>%
filter(Name %in% vec) %>%
bind_rows(z %>%
filter(!Name %in% vec) %>%
rename(Name2 = Name, Vote2 = Vote)), simplify = FALSE)
-выход
out[[1]]
# Name Vote Name2 Vote2
#1 Jhon a <NA> <NA>
#2 Lee b <NA> <NA>
#3 Suzan c <NA> <NA>
#4 Jhon f <NA> <NA>
#5 Lee g <NA> <NA>
#6 Suzan h <NA> <NA>
#7 Jhon k <NA> <NA>
#8 Lee l <NA> <NA>
#9 Suzan m <NA> <NA>
#10 Jhon p <NA> <NA>
#11 Lee q <NA> <NA>
#12 Suzan r <NA> <NA>
#13 Jhon u <NA> <NA>
#14 <NA> <NA> Abhinav d
#15 <NA> <NA> Brain e
#16 <NA> <NA> Abhinav i
#17 <NA> <NA> Brain j
#18 <NA> <NA> Abhinav n
#19 <NA> <NA> Brain o
#20 <NA> <NA> Abhinav s
#21 <NA> <NA> Brain t
Кроме того, если нам нужно, чтобы NA
внизу
out2 <- z %>%
pull(Name) %>%
unique %>%
combn(., 3, FUN = function(vec)
z %>%
filter(Name %in% vec) %>%
bind_rows(z %>%
filter(!Name %in% vec) %>%
rename(Name2 = Name, Vote2 = Vote)) %>%
mutate(across(c(Name2, Vote2),
~ .[order(is.na(.))])), simplify = FALSE)
out2[[1]]
# Name Vote Name2 Vote2
#1 Jhon a Abhinav d
#2 Lee b Brain e
#3 Suzan c Abhinav i
#4 Jhon f Brain j
#5 Lee g Abhinav n
#6 Suzan h Brain o
#7 Jhon k Abhinav s
#8 Lee l Brain t
#9 Suzan m <NA> <NA>
#10 Jhon p <NA> <NA>
#11 Lee q <NA> <NA>
#12 Suzan r <NA> <NA>
#13 Jhon u <NA> <NA>
#14 <NA> <NA> <NA> <NA>
#15 <NA> <NA> <NA> <NA>
#16 <NA> <NA> <NA> <NA>
#17 <NA> <NA> <NA> <NA>
#18 <NA> <NA> <NA> <NA>
#19 <NA> <NA> <NA> <NA>
#20 <NA> <NA> <NA> <NA>
#21 <NA> <NA> <NA> <NA>
Или также может использовать setdiff/anti_join
от dplyr
out <- z %>%
pull(Name) %>%
unique %>%
combn(., 3, FUN = function(vec) {
z1 <- z %>%
filter(Name %in% vec)
z2 <- setdiff(z, z1)
names(z2) <- paste0(names(z2), 2)
bind_rows(z1, z2)
}, simplify = FALSE)
Ответ №2:
f <- function(df,n)
{ # creates n NA rows
naDF = df[1,]
naDF[1,] <- NA
naDF[rep(seq_len(nrow(naDF)), each = n), ]
}
# previous code unchanged
df <- lapply(1:dim(comb)[2], function(x) {df1 = z[ z$Name %in% comb[,x], ]; df2 = z[ !z$Name %in% comb[,x], ]; cbind(df1, rbind(df2, f(df2, nrow(df1)-nrow(df2))))})
> df[[1]]
Name Vote Name Vote
1 Jhon a Abhinav d
2 Lee b Brain e
3 Suzan c Abhinav i
6 Jhon f Brain j
7 Lee g Abhinav n
8 Suzan h Brain o
11 Jhon k Abhinav s
12 Lee l Brain t
13 Suzan m <NA> <NA>
16 Jhon p <NA> <NA>
17 Lee q <NA> <NA>
18 Suzan r <NA> <NA>
21 Jhon u <NA> <NA>