Funktioner i R-programmering med exempel
Vad är en funktion i R?
A fungera, i en programmeringsmiljö, är en uppsättning instruktioner. En programmerare bygger en funktion för att undvika upprepar samma uppgift, eller minska komplexitet.
En funktion bör vara
- skriven för att utföra vissa uppgifter
- kan innehålla argument eller inte
- innehålla en kropp
- kan eller kanske inte returnerar ett eller flera värden.
En allmän inställning till en funktion är att använda argumentdelen som ingångar, mata kropp del och slutligen tillbaka en produktion. Syntaxen för en funktion är följande:
function (arglist) { #Function body }
R viktiga inbyggda funktioner
Det finns många inbyggda funktioner i R. R matchar dina indataparametrar med dess funktionsargument, antingen efter värde eller position, och kör sedan funktionskroppen. Funktionsargument kan ha standardvärden: om du inte anger dessa argument kommer R att ta standardvärdet.
Anmärkningar:
Det är möjligt att se källkoden för en funktion genom att köra namnet på själva funktionen i konsolen.
Vi kommer att se tre grupper av funktioner i aktion
- Allmän funktion
- Matematik funktion
- Statistisk funktion
Allmänna funktioner
Vi är redan bekanta med allmänna funktioner som cbind(), rbind(),range(),sort(),order()-funktioner. Var och en av dessa funktioner har en specifik uppgift, tar argument för att returnera en utdata. Följande är viktiga funktioner man måste känna till
diff() funktion
Om du jobbar på tidsföljder, måste du stilla serien genom att ta deras fördröjningsvärden. En stationär process tillåter konstant medelvärde, varians och autokorrelation över tid. Detta förbättrar främst förutsägelsen av en tidsserie. Det kan enkelt göras med funktionen diff(). Vi kan bygga en slumpmässig tidsseriedata med en trend och sedan använda funktionen diff() för att stationära serien. Funktionen diff() accepterar ett argument, en vektor, och returnerar lämplig fördröjd och itererad skillnad.
Anmärkningar: Vi behöver ofta skapa slumpmässiga data, men för inlärning och jämförelse vill vi att siffrorna ska vara identiska på alla maskiner. För att säkerställa att vi alla genererar samma data använder vi funktionen set.seed() med godtyckliga värden på 123. Funktionen set.seed() genereras genom processen med pseudoslumptalsgenerator som gör att alla moderna datorer har samma sekvens av siffror. Om vi inte använder funktionen set.seed() kommer vi alla att ha olika talföljd.
set.seed(123) ## Create the data x = rnorm(1000) ts <- cumsum(x) ## Stationary the serie diff_ts <- diff(ts) par(mfrow=c(1,2)) ## Plot the series plot(ts, type='l') plot(diff(ts), type='l')
length() funktion
I många fall vill vi veta längd av en vektor för beräkning eller för att användas i en for-loop. Funktionen length() räknar antalet rader i vektorn x. Följande koder importerar bilens datauppsättning och returnerar antalet rader.
Anmärkningar: length() returnerar antalet element i en vektor. Om funktionen skickas in i en matris eller en dataram returneras antalet kolumner.
dt <- cars ## number columns length(dt)
Produktion:
## [1] 1
## number rows length(dt[,1])
Produktion:
## [1] 50
Matematiska funktioner
R har en rad matematiska funktioner.
Operator | Description |
---|---|
abs (x) | Tar det absoluta värdet av x |
log(x,bas=y) | Tar logaritmen av x med basen y; om bas inte anges, returnerar den naturliga logaritmen |
exp(x) | Returnerar exponentialen för x |
sqrt (x) | Returnerar kvadratroten av x |
factorial(x) | Returnerar faktorvärdet av x (x!) |
# sequence of number from 44 to 55 both including incremented by 1 x_vector <- seq(45,55, by = 1) #logarithm log(x_vector)
Produktion:
## [1] 3.806662 3.828641 3.850148 3.871201 3.891820 3.912023 3.931826 ## [8] 3.951244 3.970292 3.988984 4.007333
#exponential exp(x_vector)
#squared root sqrt(x_vector)
Produktion:
## [1] 6.708204 6.782330 6.855655 6.928203 7.000000 7.071068 7.141428 ## [8] 7.211103 7.280110 7.348469 7.416198
#factorial factorial(x_vector)
Produktion:
## [1] 1.196222e+56 5.502622e+57 2.586232e+59 1.241392e+61 6.082819e+62 ## [6] 3.041409e+64 1.551119e+66 8.065818e+67 4.274883e+69 2.308437e+71 ## [11] 1.269640e+73
Statistiska funktioner
R standardinstallation innehåller ett stort antal statistiska funktioner. I den här handledningen kommer vi kort att titta på den viktigaste funktionen..
Grundläggande statistikfunktioner
Operator | Description |
---|---|
medelvärde(x) | Medelvärde av x |
median(x) | Median av x |
var(x) | Varians av x |
sd(x) | Standardavvikelse för x |
skala (x) | Standardpoäng (z-poäng) för x |
kvantil (x) | Kvartilerna för x |
sammanfattning(x) | Sammanfattning av x: medelvärde, min, max osv. |
speed <- dt$speed speed # Mean speed of cars dataset mean(speed)
Produktion:
## [1] 15.4
# Median speed of cars dataset median(speed)
Produktion:
## [1] 15
# Variance speed of cars dataset var(speed)
Produktion:
## [1] 27.95918
# Standard deviation speed of cars dataset sd(speed)
Produktion:
## [1] 5.287644
# Standardize vector speed of cars dataset head(scale(speed), 5)
Produktion:
## [,1] ## [1,] -2.155969 ## [2,] -2.155969 ## [3,] -1.588609 ## [4,] -1.588609 ## [5,] -1.399489
# Quantile speed of cars dataset quantile(speed)
Produktion:
## 0% 25% 50% 75% 100% ## 4 12 15 19 25
# Summary speed of cars dataset summary(speed)
Produktion:
## Min. 1st Qu. Median Mean 3rd Qu. Max. ## 4.0 12.0 15.0 15.4 19.0 25.0
Fram till denna punkt har vi lärt oss många inbyggda R-funktioner.
Anmärkningar: Var försiktig med argumentets klass, dvs numerisk, boolesk eller sträng. Om vi till exempel behöver skicka ett strängvärde måste vi omge strängen inom citattecken: "ABC" .
Skrivfunktion i R
Vid vissa tillfällen behöver vi skriva vår egen funktion eftersom vi måste utföra en viss uppgift och ingen färdig funktion existerar. En användardefinierad funktion involverar en namn, argument och en kropp.
function.name <- function(arguments) { computations on the arguments some other code }
Anmärkningar: En bra praxis är att namnge en användardefinierad funktion som skiljer sig från en inbyggd funktion. Det undviker förvirring.
En argumentfunktion
I nästa utdrag definierar vi en enkel kvadratisk funktion. Funktionen accepterar ett värde och returnerar kvadraten på värdet.
square_function<- function(n) { # compute the square of integer `n` n^2 } # calling the function and passing value 4 square_function(4)
Kodförklaring
- Funktionen heter square_function; det kan kallas vad vi vill.
- Den får argumentet "n". Vi angav inte typen av variabel så att användaren kan skicka ett heltal, en vektor eller en matris
- Funktionen tar ingången "n" och returnerar kvadraten på ingången. När du är klar med funktionen kan vi ta bort den med funktionen rm().
# efter att du skapat funktionen
rm(square_function) square_function
På konsolen kan vi se ett felmeddelande: Fel: objektet 'square_function' hittades inte som talar om att funktionen inte existerar.
Miljö Scoping
I R, den miljö är en samling av objekt som funktioner, variabler, dataram, etc.
R öppnar en miljö varje gång Rstudio uppmanas.
Den tillgängliga toppnivåmiljön är global miljö, kallad R_GlobalEnv. Och vi har lokal miljö.
Vi kan lista innehållet i den aktuella miljön.
ls(environment())
Produktion
## [1] "diff_ts" "dt" "speed" "square_function" ## [5] "ts" "x" "x_vector"
Du kan se alla variabler och funktioner som skapats i R_GlobalEnv.
Listan ovan kommer att variera för dig baserat på den historiska koden du kör i R Studio.
Observera att n, argumentet för funktionen square_function är inte i denna globala miljö.
A ny miljö skapas för varje funktion. I exemplet ovan skapar funktionen square_function() en ny miljö i den globala miljön.
För att klargöra skillnaden mellan global och lokal miljö, låt oss studera följande exempel
Dessa funktioner tar ett värde x som ett argument och lägger till det till y definiera utanför och inuti funktionen
Funktionen f returnerar utgången 15. Detta beror på att y definieras i den globala miljön. Vilken variabel som helst som definieras i den globala miljön kan användas lokalt. Variabeln y har värdet 10 under alla funktionsanrop och är tillgänglig när som helst.
Låt oss se vad som händer om variabeln y är definierad inuti funktionen.
Vi måste släppa "y" innan vi kör den här koden med rm r
Utdata är också 15 när vi anropar f(5) men returnerar ett fel när vi försöker skriva ut värdet y. Variabeln y finns inte i den globala miljön.
Slutligen använder R den senaste variabeldefinitionen för att passera in i kroppen av en funktion. Låt oss överväga följande exempel:
R ignorerar y-värdena som definierats utanför funktionen eftersom vi uttryckligen skapade en ay-variabel inuti funktionens kropp.
Multi argument funktion
Vi kan skriva en funktion med mer än ett argument. Tänk på funktionen som kallas "tider". Det är en enkel funktion som multiplicerar två variabler.
times <- function(x,y) { x*y } times(2,4)
Produktion:
## [1] 8
När ska vi skriva funktion?
Dataforskare behöver göra många repetitiva uppgifter. För det mesta kopierar och klistrar vi in bitar av kod upprepade gånger. Normalisering av en variabel rekommenderas till exempel starkt innan vi kör en maskininlärning algoritm. Formeln för att normalisera en variabel är:
Vi vet redan hur man använder funktionen min() och max() i R. Vi använder tibble-biblioteket för att skapa dataramen. Tibble är hittills den mest bekväma funktionen för att skapa en datamängd från grunden.
library(tibble) # Create a data frame data_frame <- tibble( c1 = rnorm(50, 5, 1.5), c2 = rnorm(50, 5, 1.5), c3 = rnorm(50, 5, 1.5), )
Vi kommer att gå vidare i två steg för att beräkna funktionen som beskrivs ovan. I det första steget kommer vi att skapa en variabel som heter c1_norm som är omskalningen av c1. I steg två kopierar vi bara och klistrar in koden för c1_norm och ändrar med c2 och c3.
Detalj av funktionen med kolumnen c1:
Nominator: : data_frame$c1 -min(data_frame$c1))
Nämnare: max(data_frame$c1)-min(data_frame$c1))
Därför kan vi dela dem för att få det normaliserade värdet av kolumn c1:
(data_frame$c1 -min(data_frame$c1))/(max(data_frame$c1)-min(data_frame$c1))
Vi kan skapa c1_norm, c2_norm och c3_norm:
Create c1_norm: rescaling of c1 data_frame$c1_norm <- (data_frame$c1 -min(data_frame$c1))/(max(data_frame$c1)-min(data_frame$c1)) # show the first five values head(data_frame$c1_norm, 5)
Produktion:
## [1] 0.3400113 0.4198788 0.8524394 0.4925860 0.5067991
Det fungerar. Vi kan kopiera och klistra in
data_frame$c1_norm <- (data_frame$c1 -min(data_frame$c1))/(max(data_frame$c1)-min(data_frame$c1))
ändra sedan c1_norm till c2_norm och c1 till c2. Vi gör samma sak för att skapa c3_norm
data_frame$c2_norm <- (data_frame$c2 - min(data_frame$c2))/(max(data_frame$c2)-min(data_frame$c2)) data_frame$c3_norm <- (data_frame$c3 - min(data_frame$c3))/(max(data_frame$c3)-min(data_frame$c3))
Vi skalade om variablerna c1, c2 och c3 perfekt.
Denna metod är dock benägen att misstag. Vi kan kopiera och glömma att ändra kolumnnamnet efter att ha klistrat in. Därför är en bra praxis att skriva en funktion varje gång du behöver klistra in samma kod mer än två gånger. Vi kan ordna om koden till en formel och kalla den när det behövs. För att skriva vår egen funktion måste vi ge:
- Namn: normalisera.
- antalet argument: Vi behöver bara ett argument, vilket är den kolumn vi använder i vår beräkning.
- Kroppen: detta är helt enkelt formeln vi vill returnera.
Vi kommer att gå vidare steg för steg för att skapa funktionen normalisera.
Steg 1) Vi skapar nominator, vilket är . I R kan vi lagra nämnaren i en variabel så här:
nominator <- x-min(x)
Steg 2) Vi beräknar nämnare: . Vi kan replikera idén med steg 1 och lagra beräkningen i en variabel:
denominator <- max(x)-min(x)
Steg 3) Vi utför uppdelningen mellan nämnare och nämnare.
normalize <- nominator/denominator
Steg 4) För att returnera värde till anropande funktion måste vi skicka normalize inuti return() för att få utdata från funktionen.
return(normalize)
Steg 5) Vi är redo att använda funktionen genom att linda in allt i fästet.
normalize <- function(x){ # step 1: create the nominator nominator <- x-min(x) # step 2: create the denominator denominator <- max(x)-min(x) # step 3: divide nominator by denominator normalize <- nominator/denominator # return the value return(normalize) }
Låt oss testa vår funktion med variabeln c1:
normalize(data_frame$c1)
Det fungerar perfekt. Vi skapade vår första funktion.
Funktioner är ett mer omfattande sätt att utföra en repetitiv uppgift. Vi kan använda normaliseringsformeln över olika kolumner, som nedan:
data_frame$c1_norm_function <- normalize (data_frame$c1) data_frame$c2_norm_function <- normalize (data_frame$c2) data_frame$c3_norm_function <- normalize (data_frame$c3)
Även om exemplet är enkelt kan vi härleda kraften i en formel. Ovanstående kod är lättare att läsa och undvik speciellt misstag när du klistrar in koder.
Fungerar med skick
Ibland måste vi inkludera villkor i en funktion för att koden ska kunna returnera olika utdata.
I maskininlärningsuppgifter måste vi dela upp datasetet mellan en tåguppsättning och en testuppsättning. Tåguppsättningen låter algoritmen lära sig av data. För att testa vår modells prestanda kan vi använda testsetet för att returnera prestandamåttet. R har ingen funktion för att skapa två datamängder. Vi kan skriva vår egen funktion för att göra det. Vår funktion tar två argument och kallas split_data(). Tanken bakom är enkel, vi multiplicerar längden på datasetet (dvs antalet observationer) med 0.8. Till exempel, om vi vill dela datamängden 80/20, och vår datauppsättning innehåller 100 rader, kommer vår funktion att multiplicera 0.8*100 = 80. 80 rader kommer att väljas ut för att bli vår träningsdata.
Vi kommer att använda luftkvalitetsdataset för att testa vår användardefinierade funktion. Luftkvalitetsdataset har 153 rader. Vi kan se det med koden nedan:
nrow(airquality)
Produktion:
## [1] 153
Vi kommer att gå tillväga enligt följande:
split_data <- function(df, train = TRUE) Arguments: -df: Define the dataset -train: Specify if the function returns the train set or test set. By default, set to TRUE
Vår funktion har två argument. Argumenttåget är en boolesk parameter. Om den är satt till TRUE skapar vår funktion tågdatasetet, annars skapar den testdatasetet.
Vi kan fortsätta som vi gjorde med normalise()-funktionen. Vi skriver koden som om det bara vore engångskod och lindar sedan in allt med villkoret i kroppen för att skapa funktionen.
Steg 1:
Vi måste beräkna längden på datasetet. Detta görs med funktionen nrow(). Nrow returnerar det totala antalet rader i datamängden. Vi kallar den variabla längden.
length<- nrow(airquality) length
Produktion:
## [1] 153
Steg 2:
Vi multiplicerar längden med 0.8. Det kommer att returnera antalet rader att välja. Det ska vara 153*0.8 = 122.4
total_row <- length*0.8 total_row
Produktion:
## [1] 122.4
Vi vill välja 122 rader bland de 153 raderna i luftkvalitetsdatauppsättningen. Vi skapar en lista som innehåller värden från 1 till total_row. Vi lagrar resultatet i variabeln som kallas split
split <- 1:total_row split[1:5]
Produktion:
## [1] 1 2 3 4 5
split väljer de första 122 raderna från datamängden. Till exempel kan vi se att vår variabeldelning samlar värdena 1, 2, 3, 4, 5 och så vidare. Dessa värden kommer att vara indexet när vi väljer de rader som ska returneras.
Steg 3:
Vi måste välja raderna i luftkvalitetsdataset baserat på värdena som lagras i den delade variabeln. Detta görs så här:
train_df <- airquality[split, ] head(train_df)
Produktion:
##[1] Ozone Solar.R Wind Temp Month Day ##[2] 51 13 137 10.3 76 6 20 ##[3] 15 18 65 13.2 58 5 15 ##[4] 64 32 236 9.2 81 7 3 ##[5] 27 NA NA 8.0 57 5 27 ##[6] 58 NA 47 10.3 73 6 27 ##[7] 44 23 148 8.0 82 6 13
Steg 4:
Vi kan skapa testdatauppsättningen genom att använda de återstående raderna, 123:153. Detta görs genom att använda – framför split.
test_df <- airquality[-split, ] head(test_df)
Produktion:
##[1] Ozone Solar.R Wind Temp Month Day ##[2] 123 85 188 6.3 94 8 31 ##[3] 124 96 167 6.9 91 9 1 ##[4] 125 78 197 5.1 92 9 2 ##[5] 126 73 183 2.8 93 9 3 ##[6] 127 91 189 4.6 93 9 4 ##[7] 128 47 95 7.4 87 9 5
Steg 5:
Vi kan skapa villkoret inuti kroppen av funktionen. Kom ihåg att vi har ett argumenttåg som är ett booleskt satt till TRUE som standard för att returnera tåguppsättningen. För att skapa villkoret använder vi if-syntaxen:
if (train ==TRUE){ train_df <- airquality[split, ] return(train) } else { test_df <- airquality[-split, ] return(test) }
Detta är det, vi kan skriva funktionen. Vi behöver bara ändra luftkvaliteten till df eftersom vi vill prova vår funktion till ev dataram, inte bara luftkvalitet:
split_data <- function(df, train = TRUE){ length<- nrow(df) total_row <- length *0.8 split <- 1:total_row if (train ==TRUE){ train_df <- df[split, ] return(train_df) } else { test_df <- df[-split, ] return(test_df) } }
Låt oss prova vår funktion på datauppsättningen för luftkvalitet. vi borde ha ett tågset med 122 rader och ett testset med 31 rader.
train <- split_data(airquality, train = TRUE) dim(train)
Produktion:
## [1] 122 6
test <- split_data(airquality, train = FALSE) dim(test)
Produktion:
## [1] 31 6