Как взять объединение элементов во вложенном списке в R - PullRequest
4 голосов
/ 25 апреля 2011

У меня есть вложенный список, скажем, lst (все элементы класса int). Я не знаю длину lst заранее; однако я знаю, что каждый элемент lst является списком длины, скажем, k

length(lst[[i]]) # this equals k and is known in advance, 
                 # this is true for i = 1 ... length(lst)

Как мне взять union 1-го элемента, 2-го элемента, ..., k-го элемента всех элементов lst

В частности, если длина lst равна n, я хочу (не код R):

# I know that union can only be taken for 2 elements, 
# following is for illustration purposes
listUnion1 <- union(lst[[1, 1]], lst[[2, 1]], ..., lst[[n, 1]])
listUnion2 <- union(lst[[1, 2]], lst[[2, 2]], ..., lst[[n, 2]])
.
.
.
listUnionk <- union(lst[[1, k]], lst[[2, k]], ..., lst[[n, k]])

Любая помощь или указатели очень ценятся.

Вот набор данных, который можно использовать, n = 3 и k = 2

list(structure(list(a = 1:5, b = 6:11), .Names = c("a", "b")), 
    structure(list(a = 6:11, b = 1:5), .Names = c("a", "b")), 
    structure(list(a = 12, b = 12), .Names = c("a", "b")))

Ответы [ 5 ]

4 голосов
/ 25 апреля 2011

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

unique(c(as.vector(x), as.vector(y)))

и бит внутри unique() может быть достигнут путем исключения из списка n-го компонента каждого списка.

Полное решение: 1010 *

unionFun <- function(n, obj) {
    unique(unlist(lapply(obj, `[[`, n)))
}
lapply(seq_along(lst[[1]]), FUN = unionFun, obj = lst)

, что дает:

[[1]]
 [1]  1  2  3  4  5  6  7  8  9 10 11 12

[[2]]
 [1]  6  7  8  9 10 11  1  2  3  4  5 12

на данных, которые вы показали.

Несколько полезных функций:

  • мы используем `[[` для подмножества obj в unionFun. Это похоже на function(x) x$a в ответе @ Ramnath's. Однако нам не нужна анонимная функция (вместо этого мы используем `[[`). Эквивалент ответа @ Ramnath: lapply(lst, `[[`, 1)
  • , чтобы обобщить вышесказанное, мы заменим 1 выше на n в unionFun() и позволим передать наш список в качестве аргумента obj.

Теперь, когда у нас есть функция, которая будет обеспечивать объединение n -ых элементов данного списка, мы можем lapply() по индексам k, применяя наш unionFun() к каждому подэлементу lst, используя тот факт, что длина lst[[1]] равна length(lst[[k]]) для всех k.

Если это помогает иметь имена n th элементов в возвращаемом объекте, мы можем сделать:

> unions <- lapply(seq_along(lst[[1]]), FUN = unionFun, obj = lst)
> names(unions) <- names(lst[[1]])
> unions
$a
 [1]  1  2  3  4  5  6  7  8  9 10 11 12

$b
 [1]  6  7  8  9 10 11  1  2  3  4  5 12
3 голосов
/ 25 апреля 2011

Вот одно из решений

# generate dummy data
x1 = sample(letters[1:5], 20, replace = T)
x2 = sample(letters[1:5], 20, replace = T)
df = data.frame(x1, x2, stringsAsFactors = F)

# find unique elements in each column
union_df = apply(df, 2, unique)

Дайте мне знать, если это работает

РЕДАКТИРОВАТЬ: Вот решение для списков с использованием предоставленных вами данных

mylist = list(structure(list(a = 1:5, b = 6:11), .Names = c("a", "b")), 
              structure(list(a = 6:11, b = 1:5), .Names = c("a", "b")), 
              structure(list(a = 12, b = 12), .Names = c("a", "b")))
list_a = lapply(mylist, function(x) x$a)
list_b = lapply(mylist, function(x) x$b)

union_a = Reduce(union, list_a)
union_b = Reduce(union, list_b)

Если в вашем списке более 2 элементов, мы можем обобщить этот код.

2 голосов
/ 25 апреля 2011

Вот еще один способ: используйте do.call/rbind, чтобы выстроить списки по «имени» во фрейм данных, затем apply unique/do.call для каждого столбца этого фрейма данных. (Я немного изменил ваши данные, чтобы объединения 'a' и 'b' имели разную длину, чтобы убедиться, что они работают правильно).

lst <- list(structure(list(a = 1:5, b = 6:11), .Names = c("a", "b")), 
    structure(list(a = 6:10, b = 1:5), .Names = c("a", "b")), 
    structure(list(a = 12, b = 12), .Names = c("a", "b")))

> apply(do.call(rbind, lst),2, function( x ) unique( do.call( c, x)))
$a
 [1]  1  2  3  4  5  6  7  8  9 10 12

$b
 [1]  6  7  8  9 10 11  1  2  3  4  5 12
1 голос
/ 25 апреля 2011

Ваши данные

df <- list(structure(list(a = 1:5, b = 6:11), .Names = c("a", "b")), 
           structure(list(a = 6:11, b = 1:5), .Names = c("a", "b")), 
           structure(list(a = 12, b = 12), .Names = c("a", "b")))

Это дает вам уникальные значения вложенных списков:

library(plyr)
df.l <- llply(df, function(x) unlist(unique(x)))

R> df.l
[[1]]
 [1]  1  2  3  4  5  6  7  8  9 10 11

[[2]]
 [1]  6  7  8  9 10 11  1  2  3  4  5

[[3]]
[1] 12

EDIT

Благодаря Рамнатху я немного изменил код и надеюсь, что этот ответ соответствует потребностям вашего вопроса. Для иллюстрации я сохранил и предыдущий ответ. Слегка измененные данные теперь имеют дополнительный список.

df <- list(structure(list(a = 1:5, b = 6:11), .Names = c("a", "b")), 
           structure(list(a = 6:11, b = 1:5), .Names = c("a", "b")), 
           structure(list(a = 12, b = 12, c = 10:14), .Names = c("a", "b", "c")))


f.x <- function(x.list) {
  x.names <- names(x.list)
  i <- combn(x.names, 2)
  l <- apply(i, 2, function(y) x.list[y])
  llply(l, unlist)
}

Теперь вы можете применить функцию к вашим данным.

all.l <- llply(df, f.x)
llply(all.l, function(x) llply(x, unique))

R> [[1]]
[[1]][[1]]
 [1]  1  2  3  4  5  6  7  8  9 10 11


[[2]]
[[2]][[1]]
 [1]  6  7  8  9 10 11  1  2  3  4  5


[[3]]
[[3]][[1]]
[1] 12

[[3]][[2]]
[1] 12 10 11 13 14

[[3]][[3]]
[1] 12 10 11 13 14

Однако вложенная структура не очень удобна для пользователя. Это можно немного изменить ...

0 голосов
/ 17 марта 2014

Согласно документации «unlist» является рекурсивной функцией, следовательно, независимо от уровня вложенности предоставленных списков, вы можете получить все элементы, передав их unlist.Вы можете получить объединение подсписков следующим образом.

lst <- list(structure(list(a = 1:5, b = 6:11), .Names = c("a", "b")), 
structure(list(a = 6:11, b = 1:5), .Names = c("a", "b")), 
structure(list(a = 12, b = 12), .Names = c("a", "b")))

lapply(lst, function(sublst) unique(unlist(sublst)))

[[1]]
[1]  1  2  3  4  5  6  7  8  9 10 11

[[2]]
[1]  6  7  8  9 10 11  1  2  3  4  5

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