Sök…


Anmärkningar

En funktion i *apply familjen är en abstraktion av en for loop. Jämfört med for slingor *apply följande fördelar:

  1. Kräv mindre kod för att skriva.
  2. Har inte en iterationsräknare.
  3. Använder inte tillfälliga variabler för att lagra mellanresultat.

Men for slingor är mer generella och kan ge oss mer kontroll så att vi kan uppnå komplexa beräkningar som inte alltid är triviala att använda med *apply funktioner.

Förhållandet mellan for slingor och *apply förklaras i dokumentationen for slingor .

Medlemmar i *apply familjen

Funktionen *apply innehåller flera varianter av samma princip som skiljer sig främst på vilken typ av utgång de returnerar.

fungera Inmatning Produktion
apply matrix , data.frame eller array vektor eller matris (beroende på längden på varje returnerat element)
sapply vektor eller list vektor eller matris (beroende på längden på varje returnerat element)
lapply vektor eller list list
vapply vektor eller `lista vektor eller matris (beroende på längden på varje återlämnat element) i den användardesignerade klassen
mapply flera vektorer, lists eller en kombination list

Se "Exempel" för att se hur var och en av dessa funktioner används.

Använd anonyma funktioner med tillämp

apply används för att utvärdera en funktion (kanske en anonym) över marginalerna för en matris eller matris.

Låt oss använda iris datasättet för att illustrera denna idé. iris datasättet har mätningar av 150 blommor från 3 arter. Låt oss se hur detta datasats är strukturerat:

> head(iris)

  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1         5.1          3.5          1.4         0.2  setosa
2         4.9          3.0          1.4         0.2  setosa
3         4.7          3.2          1.3         0.2  setosa
4         4.6          3.1          1.5         0.2  setosa
5         5.0          3.6          1.4         0.2  setosa
6         5.4          3.9          1.7         0.4  setosa

Föreställ dig nu att du vill veta medelvärdet för var och en av dessa variabler. Ett sätt att lösa detta kan vara att använda en for loop, men R-programmerare föredrar ofta att använda apply (av anledningar, se anmärkningar):

> apply(iris[1:4], 2, mean)

Sepal.Length  Sepal.Width Petal.Length  Petal.Width 
    5.843333     3.057333     3.758000     1.199333
  • I den första parametern lägger vi ned iris att de endast inkluderar de första fyra kolumnerna, eftersom mean bara fungerar på numeriska data.
  • Det andra parametervärdet på 2 indikerar att vi bara vill arbeta på kolumnerna (det andra underskriptet för rxc-arrayen); 1 skulle ge raden medel.

På samma sätt kan vi beräkna mer meningsfulla värden:

# standard deviation
apply(iris[1:4], 2, sd)
# variance
apply(iris[1:4], 2, var)

Varning : R har några inbyggda funktioner som är bättre för att beräkna colMeans och rowMeans och medel: colMeans and rowMeans .

Nu, låt oss göra en annorlunda och mer meningsfull uppgift: låt oss beräkna medelvärdet endast för de värden som är större än 0.5 . För det skapar vi vår egen mean .

> our.mean.function <- function(x) { mean(x[x > 0.5]) }
> apply(iris[1:4], 2, our.mean.function)

Sepal.Length  Sepal.Width Petal.Length  Petal.Width 
    5.843333     3.057333     3.758000     1.665347

(Observera skillnaden i medelvärdet för Petal.Width )

Men vad händer om vi inte vill använda den här funktionen i resten av vår kod? Sedan kan vi använda en anonym funktion och skriva vår kod så här:

apply(iris[1:4], 2, function(x) { mean(x[x > 0.5]) })

Så, som vi har sett, kan vi använda apply att utföra samma operation på kolumner eller rader i ett datasats med bara en rad.

Varning : Eftersom apply returnerar mycket olika typer av output beroende på längden på resultaten för den angivna funktionen, är det kanske inte det bästa valet i de fall där du inte arbetar interaktivt. Några av de andra *apply familjefunktionerna är lite mer förutsägbara (se Anmärkningar).

Laddning av massfil

för ett stort antal filer som kan behöva köras i en liknande process och med välstrukturerade filnamn.

Först måste en vektor av filnamnen som ska nås skapas, det finns flera alternativ för detta:

  • Skapa vektorn manuellt med paste0()

     files <- paste0("file_", 1:100, ".rds")
    
  • Att använda list.files() med en regex-sökterm för filtypen kräver kunskap om reguljära uttryck ( regex ) om andra filer av samma typ finns i katalogen.

     files <- list.files("./", pattern = "\\.rds$", full.names = TRUE)
    

där X är en vektor av en del av filnamnsformatet som används.

lapply kommer att mata ut varje svar som element i en lista.

readRDS är specifikt för .rds filer och kommer att ändras beroende på processens tillämpning.

my_file_list <- lapply(files, readRDS)

Detta är inte nödvändigtvis snabbare än en för-loop från testning men tillåter alla filer att vara ett element i en lista utan att tilldela dem uttryckligen.

Slutligen måste vi ofta ladda flera paket samtidigt. Detta trick kan göra det ganska enkelt genom att tillämpa library() på alla bibliotek som vi vill importera:

lapply(c("jsonlite","stringr","igraph"),library,character.only=TRUE)

Kombinera flera `data.frames` (` lapply`, `mapply`)

I denna övning kommer vi att generera fyra linjära regressionsmodeller för bootstrap och kombinera sammanfattningarna av dessa modeller till en enda dataram.

library(broom)

#* Create the bootstrap data sets
BootData <- lapply(1:4,
                   function(i) mtcars[sample(1:nrow(mtcars),
                                             size = nrow(mtcars),
                                             replace = TRUE), ])

#* Fit the models
Models <- lapply(BootData,
                 function(BD) lm(mpg ~ qsec + wt + factor(am),
                                 data = BD))

#* Tidy the output into a data.frame
Tidied <- lapply(Models,
                 tidy)

#* Give each element in the Tidied list a name
Tidied <- setNames(Tidied, paste0("Boot", seq_along(Tidied)))

På denna punkt kan vi ta två sätt att infoga namnen i data.frame.

#* Insert the element name into the summary with `lapply`
#* Requires passing the names attribute to `lapply` and referencing `Tidied` within
#* the applied function.
Described_lapply <- 
 lapply(names(Tidied),
        function(nm) cbind(nm, Tidied[[nm]]))

Combined_lapply <- do.call("rbind", Described_lapply)

#* Insert the element name into the summary with `mapply`
#* Allows us to pass the names and the elements as separate arguments.
Described_mapply <- 
 mapply(
  function(nm, dframe) cbind(nm, dframe),
  names(Tidied),
  Tidied,
  SIMPLIFY = FALSE)

Combined_mapply <- do.call("rbind", Described_mapply)

Om du är en fan av magrittr , kan du utföra hela uppgiften i en enda kedja (även om det kanske inte är klokt att göra det om du behöver någon av mellanobjekten, till exempel själva modellobjekten):

library(magrittr)
library(broom)
Combined <- lapply(1:4,
                   function(i) mtcars[sample(1:nrow(mtcars),
                                             size = nrow(mtcars),
                                             replace = TRUE), ]) %>%
 lapply(function(BD) lm( mpg ~ qsec + wt + factor(am), data = BD)) %>%
 lapply(tidy) %>%
 setNames(paste0("Boot", seq_along(.))) %>%
 mapply(function(nm, dframe) cbind(nm, dframe),
        nm = names(.),
        dframe = .,
        SIMPLIFY = FALSE) %>%
 do.call("rbind", .)

Använda inbyggda funktionaliteter

Inbyggda funktioner: lapply (), sapply () och mapply ()

R levereras med inbyggda funktionaliteter, varav de kanske mest kända är tillämpningsfamiljen av funktioner. Här är en beskrivning av några av de vanligaste tillämpningsfunktionerna:

  • lapply() = tar en lista som ett argument och tillämpar den angivna funktionen på listan.
  • sapply() = samma som lapply() men försöker förenkla utgången till en vektor eller en matris.
    • vapply() = en variant av sapply() där utgångsobjektets typ måste anges.
  • mapply() = gillar lapply() men kan överföra flera vektorer som inmatning till den angivna funktionen. Kan förenklas som sapply() .
    • Map() är ett alias för att mapply() med SIMPLIFY = FALSE .

lapply ()

lapply() kan användas med två olika iterationer:

  • lapply(variable, FUN)
  • lapply(seq_along(variable), FUN)
# Two ways of finding the mean of x
set.seed(1)
df <- data.frame(x = rnorm(25), y = rnorm(25))
lapply(df, mean)
lapply(seq_along(df), function(x) mean(df[[x]))

sapply ()

sapply() kommer att försöka lösa dess utgång till antingen en vektor eller en matris.

# Two examples to show the different outputs of sapply()
sapply(letters, print)  ## produces a vector
x <- list(a = 1:10, beta = exp(-3:3), logic = c(TRUE,FALSE,FALSE,TRUE))
sapply(x, quantile)  ## produces a matrix

mapply ()

mapply() fungerar ungefär som lapply() förutom att det kan ta flera vektorer som input (därav m för multivariat).

mapply(sum, 1:5, 10:6, 3) # 3 will be "recycled" by mapply

Använda användardefinierade funktioner

Användardefinierade funktioner

Användare kan skapa sina egna funktioner i varierande grad av komplexitet. Följande exempel är från Functionals av Hadley Wickham:

randomise <- function(f) f(runif(1e3))
        
lapply2 <- function(x, f, ...) {
    out <- vector("list", length(x))
    for (i in seq_along(x)) {
        out[[i]] <- f(x[[i]], ...)
    }
    out
}

I det första fallet accepterar randomise ett enda argument f och kallar det för ett urval av enhetliga slumpmässiga variabler. För att visa likvärdighet kallar vi set.seed nedan:

set.seed(123)
randomise(mean)
#[1] 0.4972778
    
set.seed(123)
mean(runif(1e3))
#[1] 0.4972778


set.seed(123)
randomise(max)
#[1] 0.9994045

set.seed(123)
max(runif(1e3))
#[1] 0.9994045

Det andra exemplet är en base::lapply av base::lapply , som använder funktionaliteter för att tillämpa en operation ( f ) på varje element i en lista ( x ). Den ... parameter tillåter användaren att skicka ytterligare argument till f , såsom na.rm alternativet i mean funktion:

lapply(list(c(1, 3, 5), c(2, NA, 6)), mean)
# [[1]]
# [1] 3
# 
# [[2]]
# [1] NA

lapply2(list(c(1, 3, 5), c(2, NA, 6)), mean)
# [[1]]
# [1] 3
# 
# [[2]]
# [1] NA


lapply(list(c(1, 3, 5), c(2, NA, 6)), mean, na.rm = TRUE)
# [[1]]
# [1] 3
# 
# [[2]]
# [1] 4

lapply2(list(c(1, 3, 5), c(2, NA, 6)), mean, na.rm = TRUE)
# [[1]]
# [1] 3
# 
# [[2]]
# [1] 4


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow