индексирование по значениям вложенного списка с использованием mapply

#r #mapply

#r #mapply

Вопрос:

У меня есть список списков, каждый из которых содержит 3 значения. Моя цель — систематически перебирать каждое значение этого вложенного списка (т. Е. Начинать со списка 1, перебирать все 3 значения, переходить к списку 2 и так далее), применяя функцию к каждому. Но моя функция обнаруживает пропущенные значения и прерывается, и я проследил проблему до самой индексации, которая ведет себя не так, как я ожидаю. Списки создаются как:

 pop <- 1:100
treat.temp <- NULL
treat <- NULL

## Generate 5 samples of pop
for (i in 1:5){
    treat.temp <- sample(pop, 3)
    treat[[i]] <- treat.temp
}

## Create a list with which to index mapply
iterations <- (1:5)
  

Иллюстративная функция и результаты.

 test.function <- function(j, k){
  for (n in 1:3){
    print(k[[n]][j])
  }
}

results <- mapply(test.function, iterations, treat)

[1] 61
[1] 63
[1] 73
[1] NA
[1] NA
[1] NA
[1] NA
[1] NA
<snipped>
  

Для первого цикла через ‘j’ это работает. Но после этого он выбрасывает NAs. Но если я сделаю это вручную, он вернет значения, которые я ожидал.

 > print(treat[[1]][1])
[1] 61
> print(treat[[1]][2])
[1] 63
> print(treat[[1]][3])
[1] 73
> print(treat[[2]][1])
[1] 59
> print(treat[[2]][2])
[1] 6
> print(treat[[2]][3])
[1] 75
<snipped>
  

Я уверен, что это основной вопрос, но, похоже, я не могу найти правильные условия поиска, чтобы найти ответ здесь или в Google. Заранее спасибо!

Отредактировано для добавления: ответ MrFlick хорошо подходит для моей проблемы. У меня есть несколько входных данных списка (следовательно, mapply) в моем фактическом использовании. Более подробный пример с несколькими примечаниями.

 pop <- 1:100
years <- seq.int(2000, 2014, 1)

treat.temp <- NULL
treat <- NULL
year.temp <- NULL
year <- NULL

## Generate 5 samples of treated states, control states and treatment years 
for (i in 1:5){
  treat.temp <- sample(pop, 20)
  treat[[i]] <- treat.temp

  year.temp <- sample(years, 1)
  year[[i]] <- year.temp
}

## Create a list with which to index mapply
iterations <- (1:5)

## Define function 
test.function <- function(j, k, l){
  for (n in 1:3){

    ## Cycles treat through each value of jXn
    print(k[n])
    ## Holds treat (k) fixed for each 3 cycle set of n (using first value in each treat sub-list); cycles through sub-lists as j changes
    print(k[1])
    ## Same as above, but with 2nd value in each sub-list of treat
    print(k[2])
    ## Holds year (l) fixed for each 3 cycle set of n, cycling through values of year each time j changes
    print(l[1])
    ## Functionally equivalent to
    print(l)
  }
}

results <- mapply(test.function, iterations, treat, year)
  

Комментарии:

1. Ваш пример настройки представляет собой список векторов, и в этом случае кажется простым применить некоторую функцию к каждому значению в каждом векторе, используя lapply — как, lapply(treat, function(x) x/2) если бы вы просто хотели разделить все на 2. Не могли бы вы немного подробнее прояснить свою проблему?

2. Я думаю, что вы правы (как и MrFlick ниже) относительно lapply в моем примере. Я добавил более подробный пример для потомков. Я использую mapply, потому что у меня есть несколько входных списков, и некоторые из них нужно циклически использовать с j, но они остаются фиксированными на всех итерациях n, в то время как другие должны циклически использоваться как с j, так и с n . Возможно, lapply справится с этим, я просто не знаю как.

Ответ №1:

Ну, возможно, вы неправильно понимаете, как mapply это работает. Функция будет проходить через обе итерации, которые вы передаете в качестве параметров, что означает treat , что также будет подмножеством каждой итерации. По сути, вызываемые функции

 test.function(iterations[1], treat[[1]])
test.function(iterations[2], treat[[2]])
test.function(iterations[3], treat[[3]])
...
  

и вы, кажется, обрабатываете k переменную так, как если бы это был весь список. Кроме того, у вас также есть обратные индексы. Но просто для того, чтобы ваш тест работал, вы можете сделать

 test.function <- function(j, k){
  for (n in 1:3) print(k[n]) 
}

results <- mapply(test.function, iterations, treat)
  

но на самом деле это не самый лучший способ перебора списка. Чего именно вы пытаетесь достичь?

Комментарии:

1. Можете ли вы объяснить, почему это неоптимально перебирать список таким образом?

2. Если бы вы просто хотели, чтобы эти значения были в таком порядке, вы могли бы просто сделать unlist(treat) . Нет ничего плохого в том, чтобы делать это таким образом, просто кажется, что это может быть проще для lapply или что-то в самом списке. Это зависит от того, что вы делаете со значениями, которые я предполагаю.