how to efficiently subset a dataframe into several

2019-06-10 07:53发布

问题:

I would appreciate any help to efficiently subset a data frame into several chunks to be passed to a list of lists based on the variable imput.

My code below works for a few subsets, but I have 100 subsets to create and the code becomes too much and difficult to handle. Therefore, I need a more efficient approach which accomplishes the same outcome without too much code.

The approach imputation_groups <- split(dat, dat$imput) discussed here allows me to split my data into a list of several chunks (data frames) based on imput but I want to be able to subsequently extract variables from each of the chunks to create a list from each chunk and then a list of these lists. Additionally, I am not certain how to create the variable N <- nrow(dT_P1), N <- nrow(dT_P2), N <- nrow(dT_P3), N <- nrow(dT_P4), N <- nrow(dT_P5) for each of the lists created from each of the chunks.

my data:

dat <- structure(list(id = c(1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 
3, 3, 4, 4, 4, 4, 4), imput = c(1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 
1, 2, 3, 4, 5, 1, 2, 3, 4, 5), A = c(1, 1, 1, 1, 1, 1, 1, 1, 
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), B = c(1, 1, 1, 1, 1, 0, 
0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0), Pass = c(278, 278, 
278, 278, 278, 100, 100, 100, 100, 100, 153, 153, 153, 153, 153, 
79, 79, 79, 79, 79), Fail = c(740, 743, 742, 743, 740, 7581, 
7581, 7581, 7581, 7581, 1231, 1232, 1235, 1235, 1232, 1731, 1732, 
1731, 1731, 1731), Weights_1 = c(4, 3, 4, 3, 3, 1, 2, 1, 2, 1, 
12, 12, 11, 12, 12, 3, 5, 3, 3, 3), Weights_2 = c(3, 3, 3, 3, 
3, 1, 1, 1, 1, 1, 12, 12, 12, 12, 12, 3, 3, 3, 3, 3), Weights_3 = c(4, 
3, 3, 3, 3, 1, 2, 1, 1, 1, 12, 12, 11, 12, 12, 3, 3, 3, 3, 3), 
    Weights_4 = c(3, 3, 4, 3, 3, 1, 1, 1, 2, 1, 12, 12, 13, 12, 
    12, 3, 2, 3, 3, 3), Weights_5 = c(3, 3, 3, 3, 3, 1, 0, 1, 
    1, 1, 12, 12, 12, 12, 12, 3, 3, 3, 3, 3), Weights_6 = c(4, 
    3, 3, 3, 3, 1, 1, 1, 1, 1, 12, 12, 12, 12, 12, 3, 3, 3, 3, 
    3), Weights_7 = c(3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 12, 12, 12, 
    12, 12, 3, 3, 3, 3, 3), Weights_8 = c(3, 3, 3, 3, 3, 1, 1, 
    1, 1, 1, 15, 12, 12, 12, 12, 3, 3, 3, 3, 3), Weights_9 = c(3, 
    3, 3, 4, 3, 1, 1, 1, 1, 1, 12, 12, 12, 12, 12, 2, 3, 3, 3, 
    3), Weights_10 = c(3, 3, 4, 3, 3, 1, 1, 1, 1, 1, 12, 10, 
    12, 12, 12, 3, 3, 3, 3, 3)), class = "data.frame", row.names = c(NA, 
-20L))

my approach:

##subsetting based on `imput`

    ##imput = `1`
    dT_P1<- dat[dat$imput == '1',]

    N <- nrow(dT_P1)
    C <-ncol(dT_P1)
    ncases <- dT_P1$Pass
    nn <- dT_P1$Fail + dT_P1$Pass
    A <- dT_P1$A
    B <- dT_P1$B
    id <- dT_P1$id
    imput <- dT_P1$imput
    w_1 <- dT_P1$Weights_1
    w_2 <- dT_P1$Weights_2
    w_3 <- dT_P1$Weights_3
    w_4 <- dT_P1$Weights_4
    w_5 <- dT_P1$Weights_5
    w_6 <- dT_P1$Weights_6
    w_7 <- dT_P1$Weights_7
    w_8 <- dT_P1$Weights_8
    w_9 <- dT_P1$Weights_9
    w_10 <- dT_P1$Weights_10

    dat1 <- list (N = N, 
              ncases = ncases, A = A, B = B, id = id, P = imput, nn = nn,
              weights = cbind(w_1, w_2, w_3, w_4, w_5, w_6, w_7, w_8, w_9, w_10))


    ##imput = `2`
    dT_P2<- dat[dat$imput == '2',]

    N <- nrow(dT_P2)
    C <-ncol(dT_P2)
    ncases <- dT_P2$Pass
    nn <- dT_P2$Fail + dT_P2$Pass
    A <- dT_P2$A
    B <- dT_P2$B
    id <- dT_P2$id
    imput <- dT_P2$imput
    w_1 <- dT_P2$Weights_1
    w_2 <- dT_P2$Weights_2
    w_3 <- dT_P2$Weights_3
    w_4 <- dT_P2$Weights_4
    w_5 <- dT_P2$Weights_5
    w_6 <- dT_P2$Weights_6
    w_7 <- dT_P2$Weights_7
    w_8 <- dT_P2$Weights_8
    w_9 <- dT_P2$Weights_9
    w_10 <- dT_P2$Weights_10

    dat2 <- list (N = N, 
              ncases = ncases, A = A, B = B, id = id, P = imput, nn = nn,
              weights = cbind(w_1, w_2, w_3, w_4, w_5, w_6, w_7, w_8, w_9, w_10))

    ##imput = `3`
    dT_P3<- dat[dat$imput == '3',]

    N <- nrow(dT_P3)
    C <-ncol(dT_P3)
    ncases <- dT_P3$Pass
    nn <- dT_P3$Fail + dT_P3$Pass
    A <- dT_P3$A
    B <- dT_P3$B
    id <- dT_P3$id
    imput <- dT_P3$imput
    w_1 <- dT_P3$Weights_1
    w_2 <- dT_P3$Weights_2
    w_3 <- dT_P3$Weights_3
    w_4 <- dT_P3$Weights_4
    w_5 <- dT_P3$Weights_5
    w_6 <- dT_P3$Weights_6
    w_7 <- dT_P3$Weights_7
    w_8 <- dT_P3$Weights_8
    w_9 <- dT_P3$Weights_9
    w_10 <- dT_P3$Weights_10

    dat3 <- list (N = N, 
              ncases = ncases, A = A, B = B, id = id, P = imput, nn = nn,
              weights = cbind(w_1, w_2, w_3, w_4, w_5, w_6, w_7, w_8, w_9, w_10))

    ##imput = `4`
    dT_P4<- dat[dat$imput == '4',]

    N <- nrow(dT_P4)
    C <-ncol(dT_P4)
    ncases <- dT_P4$Pass
    nn <- dT_P4$Fail + dT_P4$Pass
    A <- dT_P4$A
    B <- dT_P4$B
    id <- dT_P4$id
    imput <- dT_P4$imput
    w_1 <- dT_P4$Weights_1
    w_2 <- dT_P4$Weights_2
    w_3 <- dT_P4$Weights_3
    w_4 <- dT_P4$Weights_4
    w_5 <- dT_P4$Weights_5
    w_6 <- dT_P4$Weights_6
    w_7 <- dT_P4$Weights_7
    w_8 <- dT_P4$Weights_8
    w_9 <- dT_P4$Weights_9
    w_10 <- dT_P4$Weights_10

    dat4 <- list (N = N, 
              ncases = ncases, A = A, B = B, id = id, P = imput, nn = nn,
              weights = cbind(w_1, w_2, w_3, w_4, w_5, w_6, w_7, w_8, w_9, w_10))

    ##imput = `5`
    dT_P5<- dat[dat$imput == '5',]

    N <- nrow(dT_P5)
    C <-ncol(dT_P5)
    ncases <- dT_P5$Pass
    nn <- dT_P5$Fail + dT_P5$Pass
    A <- dT_P5$A
    B <- dT_P5$B
    id <- dT_P5$id
    imput <- dT_P5$imput
    w_1 <- dT_P5$Weights_1
    w_2 <- dT_P5$Weights_2
    w_3 <- dT_P5$Weights_3
    w_4 <- dT_P5$Weights_4
    w_5 <- dT_P5$Weights_5
    w_6 <- dT_P5$Weights_6
    w_7 <- dT_P5$Weights_7
    w_8 <- dT_P5$Weights_8
    w_9 <- dT_P5$Weights_9
    w_10 <- dT_P5$Weights_10

    dat5 <- list (N = N, 
              ncases = ncases, A = A, B = B, id = id, P = imput, nn = nn,
              weights = cbind(w_1, w_2, w_3, w_4, w_5, w_6, w_7, w_8, w_9, w_10))

##creating the list of lists:

    mydatalist <- list(dat1, dat2, dat3, dat4, dat5) 

回答1:

you can:

  1. first you split your data.frame using split
  2. then use lapply to apply a function to your list of subsets

here is an example

l <- split(dat, dat$imput)
fun <- function(x) {
  w <- x[, grep('Weights', colnames(x))]
  colnames(w) <- paste0('w_', 1:10)
  w <- data.matrix(w)
  return(list(N = nrow(x),
              C = ncol(x),
              ncases = x$Pass,
              A = x$A,
              B = x$B,
              id = x$id,
              P = x$imput,
              nn = x$Fail + x$Pass,
              weights = w))
}
mydatalist <- lapply(l, fun)


回答2:

Doing duplicate things so many times doesn't conform to the spirit of programming. If you haven't learned enough functions in R, you can try a for loop to achieve that. Here is a by() method. This function is a mixture of split() and lapply().

mylist <- by(dat, dat$imput, function(x){
  nn <- x$Fail + x$Pass
  weights <- x[paste0("Weights_", 1:10)]
  names(weights) <- paste0("w_", 1:10)
  return(list(N = nrow(x), ncases = x$Pass, A = x$A, B = x$B,
              id = x$id, P = x$imput, nn = nn, weights = weights))
})