Как воспроизвести цикл, используя функцию в R-пакете purrr - PullRequest
3 голосов
/ 07 ноября 2019

Я часто использую циклы в своем коде. Мне сказали, что вместо использования циклов я должен использовать функции, и что цикл можно переписать, используя функцию в мурлыканье пакета R.

В качестве примера код показывает только количестворазличные виды в наборе данных радужной оболочки, где Sepal.Width <3 </p>

 library(dplyr)
 #dataframe to put the output in
 sepaltable <- data.frame(Species=character(),
                     Total=numeric(), 
                     stringsAsFactors=FALSE) 

 #list of species to iterate over
 specieslist<-unique(iris$Species)

 #loop to populate the dataframe with the name of the species 
 #and the count of how many there were in the iris dataset

 for (i in  seq_along (specieslist)){
 a<-paste(specieslist[i])  
 b<- filter(iris,`Species`==a & Sepal.Width <=3)
 c<-nrow(b)
 sepaltable[i,"Species"]<-a
 sepaltable[i,"Total"]<-c
 }

Цикл заполняет сепарируемый кадр данных названием каждого вида и сколько их было в наборе данных радужной оболочки. Я хочу воспроизвести эффекты этого цикла, используя функцию в мурлыканье пакета R без использования цикла. Кто-нибудь может помочь?

Ответы [ 2 ]

5 голосов
/ 07 ноября 2019

Мы можем использовать группу с помощью sum логического выражения в dplyr

library(dplyr)
iris %>% 
   group_by(Species) %>%
   summarise(Total = sum(Sepal.Width <=3))

Или, если необходимо purrr

library(purrr)
map_dfr(specieslist,  ~iris %>% 
      summarise(Total = sum(Species == .x & Sepal.Width <=3),
          Species = .x )) %>%
   select(Species, Total)

ПРИМЕЧАНИЕ: map или apply семейные функции (lapply/sapply/vapply/rapply/mapply/Map/apply) - это все циклы

2 голосов
/ 07 ноября 2019

Для приведенного вами примера типа ответ akrun является наиболее простым подходом, тем более что вы уже используете dplyr. Пакет dplyr написан для обработки основных сводок таблиц данных, особенно статистики групп, используемой в вашем примере.
Но в более сложных случаях большую часть времени, когда вы пишете цикл, вы можете выполнить то же самое, используя функцию иприменять семью.

используя ваш пример:

# write function that does the stuff you put in your loop
summSpecies <- function(a) {
      b<- filter(iris,`Species`==a & Sepal.Width <=3)
      c<-nrow(b)
      return(c)
}

# apply the loop over your list
sapply(specieslist,summSpecies) #sapply simplifies the output to return a vector (in this case)
#[1]  8 42 33

# You can build this into a data frame
sepaltable <- data.frame(Species=specieslist,
                         Total=sapply(specieslist,summSpecies), 
                         stringsAsFactors=FALSE) 
sepaltable
#      Species Total
# 1     setosa     8
# 2 versicolor    42
# 3  virginica    33

Для чего я сделал сравнение методов, предложенных в примере:

Unit: microseconds
#            expr      min        lq     mean   median        uq       max neval
#      ForLoop.OP 2548.519 2725.9020 3107.153 2819.837 3006.5915 11654.194   100
#     Apply.Brian 2385.638 2534.2390 2810.854 2625.050 2822.5145  9641.172   100
#     dplyr.akrun 721.136  837.6065 1180.244  864.604  902.9815 13440.076   100
#     purrr.akrun 3572.656 3783.2845 4147.900 3874.095 4073.5690 10517.602   100
#    purrr.Axeman 2440.973 2527.322 2866.7686 2586.8960 2774.097  9577.360   100

Не должно быть сюрпризом, чтоСуществующая функция, оптимизированная для такого рода задач, является явным победителем. Подход цикла for отстает от подхода семейного применения.

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