2017-07-17 25 views
10

Tôi đang cố gắng chia danh sách lồng nhau theo biến nhóm. Vui lòng xem xét cấu trúc sau:Tách và điều chỉnh danh sách lồng nhau

> str(L1) 
List of 2 
$ names:List of 2 
    ..$ first: chr [1:5] "john" "lisa" "anna" "mike" ... 
    ..$ last : chr [1:5] "johnsson" "larsson" "johnsson" "catell" ... 
$ stats:List of 2 
    ..$ physical:List of 2 
    .. ..$ age : num [1:5] 14 22 53 23 31 
    .. ..$ height: num [1:5] 165 176 179 182 191 
    ..$ mental :List of 1 
    .. ..$ iq: num [1:5] 102 104 99 87 121 

Bây giờ tôi cần phải tạo ra hai danh sách, trong đó sử dụng cả hai L1$names$last để ghép, kết quả là L2L3 xem bên dưới:

L2: Kết quả phân nhóm theo L1$names$last

> str(L2) 
List of 3 
$ johnsson:List of 2 
    ..$ names:List of 1 
    .. ..$ first: chr [1:2] "john" "anna" 
    ..$ stats:List of 2 
    .. ..$ physical:List of 2 
    .. .. ..$ age : num [1:2] 14 53 
    .. .. ..$ height: num [1:2] 165 179 
    .. ..$ mental :List of 1 
    .. .. ..$ iq: num [1:2] 102 99 
$ larsson :List of 2 
    ..$ names:List of 1 
    .. ..$ first: chr [1:2] "lisa" "steven" 
    ..$ stats:List of 2 
    .. ..$ physical:List of 2 
    .. .. ..$ age : num [1:2] 22 31 
    .. .. ..$ height: num [1:2] 176 191 
    .. ..$ mental :List of 1 
    .. .. ..$ iq: num [1:2] 104 121 
$ catell :List of 2 
    ..$ names:List of 1 
    .. ..$ first: chr "mike" 
    ..$ stats:List of 2 
    .. ..$ physical:List of 2 
    .. .. ..$ age : num 23 
    .. .. ..$ height: num 182 
    .. ..$ mental :List of 1 
    .. .. ..$ iq: num 87 

L3: Mỗi nhóm chỉ cho phép một lần xuất hiện L1$names$last

List of 2 
$ 1:List of 2 
    ..$ names:List of 2 
    .. ..$ first: chr [1:3] "john" "lisa" "mike" 
    .. ..$ last : chr [1:3] "johnsson" "larsson" "catell" 
    ..$ stats:List of 2 
    .. ..$ physical:List of 2 
    .. .. ..$ age : num [1:3] 14 22 23 
    .. .. ..$ height: num [1:3] 165 176 182 
    .. ..$ mental :List of 1 
    .. .. ..$ iq: num [1:3] 102 104 87 
$ 2:List of 2 
    ..$ names:List of 2 
    .. ..$ first: chr [1:2] "anna" "steven" 
    .. ..$ last : chr [1:2] "johnsson" "larsson" 
    ..$ stats:List of 2 
    .. ..$ physical:List of 2 
    .. .. ..$ age : num [1:2] 53 31 
    .. .. ..$ height: num [1:2] 179 191 
    .. ..$ mental :List of 1 
    .. .. ..$ iq: num [1:2] 99 121 

`ve đã cố gắng áp dụng this solution, nhưng có vẻ như điều này sẽ không làm việc cho các danh sách lồng nhau.

mã thể sanh sản:

L1 <- list("names" = list("first" = c("john","lisa","anna","mike","steven"),"last" = c("johnsson","larsson","johnsson","catell","larsson")),"stats" = list("physical" = list("age" = c(14,22,53,23,31), "height" = c(165,176,179,182,191)), "mental" = list("iq" = c(102,104,99,87,121)))) 

L2 <- list("johnsson" = list("names" = list("first" = c("john","anna")),"stats" = list("physical" = list("age" = c(14,53), "height" = c(165,179)), "mental" = list("iq" = c(102,99)))), "larsson" = list("names" = list("first" = c("lisa","steven")),"stats" = list("physical" = list("age" = c(22,31), "height" = c(176,191)), "mental" = list("iq" = c(104,121)))), "catell" = list("names" = list("first" = "mike"),"stats" = list("physical" = list("age" = 23, "height" = 182), "mental" = list("iq" = 87)))) 

L3 <- list("1" = list("names" = list("first" = c("john","lisa","mike"),"last" = c("johnsson","larsson","catell")),"stats" = list("physical" = list("age" = c(14,22,23), "height" = c(165,176,182)), "mental" = list("iq" = c(102,104,87)))), "2" = list("names" = list("first" = c("anna","steven"),"last" = c("johnsson","larsson")),"stats" = list("physical" = list("age" = c(53,31), "height" = c(179,191)), "mental" = list("iq" = c(99,121))))) 

EDIT: Xin lưu ý rằng các số liệu thực tế là khá lớn và nhiều hơn nữa lồng nhau sâu sắc hơn so với ví dụ được cung cấp.

+0

dữ liệu của bạn có vẻ rất có cấu trúc, tức là hình chữ nhật, tại sao bạn không sử dụng khung dữ liệu – rawr

+0

Tôi không xem xét điều đó khi tạo dữ liệu mẫu. Dữ liệu thực tế tôi đang làm việc với các thay đổi động và không nhất thiết là hình chữ nhật. –

+0

Bạn có thể cung cấp ví dụ trong đó các vectơ không phải danh sách không có cùng độ dài không? Cùng với kết quả mong muốn cuối cùng? –

Trả lời

6

Thông thường để sửa đổi danh sách bạn sẽ muốn sử dụng đệ quy. Ví dụ, hãy xem xét chức năng này:

foo <- function(x, idx) { 

    if (is.list(x)) { 
     return(lapply(x, foo, idx = idx)) 
    } 
    return(x[idx]) 
} 

phải mất một danh sách như x và một số chỉ số idx. Nó sẽ kiểm tra nếu x là một danh sách, và nếu đó là trường hợp nó sẽ lapply chính nó cho tất cả các subelements của danh sách. Khi x không còn là danh sách nữa, chúng tôi lấy các yếu tố được đưa ra bởi idx. Trong toàn bộ quá trình, cấu trúc của danh sách gốc sẽ vẫn nguyên vẹn.

Dưới đây là ví dụ đầy đủ. Lưu ý rằng mã này giả định tất cả các vectơ trong danh sách có 5 phần tử.

L1 <- list("names" = list("first" = c("john","lisa","anna","mike","steven"),"last" = c("johnsson","larsson","johnsson","catell","larsson")),"stats" = list("physical" = list("age" = c(14,22,53,23,31), "height" = c(165,176,179,182,191)), "mental" = list("iq" = c(102,104,99,87,121)))) 

L2 <- list("johnsson" = list("names" = list("first" = c("john","anna")),"stats" = list("physical" = list("age" = c(14,53), "height" = c(165,179)), "mental" = list("iq" = c(102,99)))), "larsson" = list("names" = list("first" = c("lisa","steven")),"stats" = list("physical" = list("age" = c(22,31), "height" = c(176,191)), "mental" = list("iq" = c(104,121)))), "catell" = list("names" = list("first" = "mike"),"stats" = list("physical" = list("age" = 23, "height" = 182), "mental" = list("iq" = 87)))) 

L3 <- list("1" = list("names" = list("first" = c("john","lisa","mike"),"last" = c("johnsson","larsson","catell")),"stats" = list("physical" = list("age" = c(14,22,23), "height" = c(165,176,182)), "mental" = list("iq" = c(102,104,87)))), "2" = list("names" = list("first" = c("anna","steven"),"last" = c("johnsson","larsson")),"stats" = list("physical" = list("age" = c(53,31), "height" = c(179,191)), "mental" = list("iq" = c(99,121))))) 

# make L2 
foo <- function(x, idx) { 

    if (is.list(x)) { 
     return(lapply(x, foo, idx = idx)) 
    } 
    return(x[idx]) 
} 

levels <- unique(L1$names$last) 
L2_2 <- vector("list", length(levels)) 
names(L2_2) <- levels 
for (i in seq_along(L2_2)) { 

    idx <- L1$names$last == names(L2_2[i]) 
    L2_2[[i]] <- list(names = foo(L1$names[-2], idx), 
         stats = foo(L1$stats, idx)) 

} 
identical(L2, L2_2) 

str(L2) 
str(L2_2) 

# make L3 

dups <- duplicated(L1$names$last) 
L3_2 <- vector("list", 2) 
names(L3_2) <- 1:2 
for (i in 1:2) { 

    if (i == 1) 
     idx <- !dups 
    else 
     idx <- dups 

    L3_2[[i]] <- foo(L1, idx) 

} 
identical(L3, L3_2) 
str(L3) 
str(L3_2) 
+0

Cảm ơn bạn rất nhiều, giải pháp của bạn hoạt động tốt với danh sách nhỏ nhưng trong trường hợp của tập dữ liệu của tôi (~ 920 quan sát trên ~ 50 biến) của nó không khả thi. –

+0

Tại sao nó không khả thi? Thời gian? Ký ức? Lỗi? – CPak

1

Đây không phải là câu trả lời hoàn chỉnh nhưng tôi hy vọng điều đó sẽ hữu ích.

Xem nếu công trình này cho L3:

x = data.frame(L1, stringsAsFactors = F) 
y = x[order(x$names.last),] 
y$seq = 1 
y$seq = ifelse(y$names.last == shift(y$names.last),shift(y$seq)+1,1) 
y$seq[1] = 1 

z = list(list(names=list(first=z[[1]]$names.first, last=z[[1]]$names.last), stats=list(physical = list(age =z[[1]]$stats.physical.age, height= z[[1]]$stats.physical.height), mental=list(iq= z[[1]]$stats.iq))), list(names=list(first=z[[2]]$names.first, last=z[[2]]$names.last), stats=list(physical = list(age =z[[2]]$stats.physical.age, height= z[[2]]$stats.physical.height), mental=list(iq= z[[2]]$stats.iq)))) 

Phần cuối cùng (z), nơi mà biến đổi trở lại thành một danh sách có thể được thực hiện với một vòng lặp. Giả sử cùng một tên không đến quá nhiều vòng lặp sẽ không quá chậm.

Bạn nói nó được lồng ghép nhiều hơn, trong trường hợp này, bạn sẽ cần phải thêm các hàm is.null và hoặc tryCatch để xử lý lỗi.

Các vấn đề liên quan