Cum se creează o funcție în R: Exemple de median personalizat și ggplot2

URMĂREȘTE-NE
16,065FaniÎmi place
1,142CititoriConectați-vă

(Acest articol a fost publicat pentru prima dată pe RStudioDataLabși cu amabilitate a contribuit la R-bloggeri). (Puteți raporta problema legată de conținutul acestei pagini aici)


Doriți să vă distribuiți conținutul pe R-bloggeri? dați clic aici dacă aveți un blog, sau aici dacă nu aveți.

Dacă ați scris același bloc de cod R de trei ori în această săptămână – un rezumat de grup, un complot, un pas de curățare – nu aveți nevoie de alt pachet. Ai nevoie de o funcție. O funcție personalizată este soluția. De exemplu, două funcții pe care le veți reutiliza de fapt: un median() personalizat construit de la zero și o funcție reutilizabilă ggplot2 care prezintă semnificațiile grupului pentru orice variabilă din orice cadru de date – genul de lucru care economisește timp real în capitolele disertației.

Simplificarea codului R cu funcții Exemplu de funcție mediană Demonstrează crearea de funcții Funcția de diagramă de comparație de grup Oferă un instrument de vizualizare gata de utilizat.

Pentru cine este acesta:
Rulați deja funcții R, cum ar fi mean(), lm()sau filter(). Acum doriți să-l scrieți pe propriul dvs. – fie pentru a opri repetarea codului în scripturile de analiză, fie pentru că un examinator/supervizor cere cod reproductibil, parametrizat.

Cuprins

Sintaxa: Funcție, Corp, Întoarcere

Fiecare funcție R are aceleași trei părți: un nume, un set de argumente și un corp.

my_function <- function(arg1, arg2) {
  result <- arg1 + arg2
  return(result)
}

my_function(3, 5)
#> (1) 8

Atribuiți funcția unui nume cu <-enumerați intrările din interior function()și scrieți logica în interior { }. Odată ce aceasta rulează, my_function există în mediul tău exact ca mean() sau sd()până când reporniți sesiunea sau o eliminați.

De fapt nu ai nevoie return() — R returnează automat valoarea lui ultima linie evaluată în organism, cu sau fără:

add_two <- function(x) x + 2   # no return() needed
add_two(10)
#> (1) 12

return() încă merită păstrat atunci când doriți să părăsiți o funcție mai devreme sau când explică punctul de ieșire pentru oricine vă citește codul mai târziu, inclusiv pe dvs. în șase luni. Și de când return() trimite înapoi doar un obiect, când aveți nevoie de mai multe rezultate, ambalați-le într-un list(): list(mean = mean(x), sd = sd(x)) returnează ambele într-un singur apel.

Cum se creează o funcție în R: Exemple de median personalizat și ggplot2Cum se creează o funcție în R: Exemple de median personalizat și ggplot2

Baza R median() este o cutie neagră până când scrii singur logica o dată. Iată o funcție care o reproduce, folosind mtcars set de date:

get_median <- function(x) {
  x <- sort(x)
  n <- length(x)

  if (n %% 2 == 0) {
    (x(n / 2) + x(n / 2 + 1)) / 2   # even count: average the two middle values
  } else {
    x((n + 1) / 2)                  # odd count: take the middle value
  }
}

get_median(mtcars$mpg)
#> (1) 19.2

median(mtcars$mpg)
#> (1) 19.2

mtcars$mpg are 32 de observații – un număr par – așa că funcția sortează toate cele 32 de valori și face media celor două din mijloc (pozițiile 16 și 17, ambele 19,2 în acest set de date). Se potrivește cu R de bază median() exact, confirmarea logicii este mai degrabă corectă decât întâmplător corectă pentru o intrare.

De ce să te deranjezi să scrii asta dacă median() exista deja?
Nu pentru a-l înlocui — pentru a înțelege o dată logica de ramificare impară/pare, astfel încât să nu ghiciți când un recenzent vă cere să justificați o „împărțire mediană” sau o alegere robustă de statistică în secțiunea de metodologie. Este același motiv pentru care trecem prin matematica ANOVA înainte de a alerga aov().

O funcție reutilizabilă ggplot2 pentru comparații de grup

Aceasta este funcția care merită păstrată în propriul set de instrumente R personal. Este nevoie de orice cadru de date, orice coloană de grupare și orice coloană numerică și returnează o diagramă cu bare de medii de grup cu bare de eroare standard – diagrama exactă de care au nevoie în mod repetat cele mai multe capitole ale rezultatelor disertației, pentru diferite variabile, fără a rescrie codul ggplot2 de fiecare dată.

library(dplyr)
library(ggplot2)

plot_group_means <- function(data, group_var, value_var, plot_title = NULL) {
  summary_df <- data %>%
    group_by({{ group_var }}) %>%
    summarise(
      mean_val = mean({{ value_var }}, na.rm = TRUE),
      se_val   = sd({{ value_var }}, na.rm = TRUE) / sqrt(n()),
      .groups  = "drop"
    )

  ggplot(summary_df, aes(x = {{ group_var }}, y = mean_val)) +
    geom_col(fill = "#4C72B0", width = 0.6) +
    geom_errorbar(
      aes(ymin = mean_val - se_val, ymax = mean_val + se_val),
      width = 0.15
    ) +
    labs(title = plot_title, y = "Mean", x = NULL) +
    theme_minimal(base_size = 13)
}

plot_group_means(mtcars, cyl, mpg, "Mean MPG by Cylinder Count")
Media MPG prin Cilindru Count utilizând funcția personalizată de la dplyr și ggplot2Media MPG prin Cilindru Count utilizând funcția personalizată de la dplyr și ggplot2

The {{ }} Sintaxa (curly-curly) este ceea ce face ca această funcție să fie reutilizabilă, mai degrabă decât o singură dată. Vă permite să treceți un nume de coloană goală – cylnu "cyl" — în dplyr verbe în interiorul propriei funcții, la fel cum l-ați introduce direct într-un script. Fără ea, această funcție ar funcționa numai dacă ați codificat greu numele coloanelor, ceea ce învinge punctul de a o scrie în primul rând.

Iată ce calculează de fapt funcția înainte de a reprezenta orice, așa că logica nu este ascunsă:

Cilindrii n MPG mediu Eroare standard
4 11 26.7 1.36
6 7 19.7 0,55
8 14 15.1 0,68

Schimbați propriul cadru de date și numele coloanelor — plot_group_means(my_data, treatment_group, outcome_score) — iar funcția realizează gruparea, rezumarea și reprezentarea într-un singur apel. Dacă nu ați instalat încă ggplot2, pașii de configurare sunt aici: cum să instalați ggplot2 în R. Pentru stilul de ieșire în continuare – centrarea titlurilor, eliminarea legendelor, ajustarea temelor – consultați acest ghid pentru personalizarea ggplot2 și foaia completă de cheat ggplot2 pentru a extinde acest lucru în alte tipuri de diagrame.

Flexibilizarea funcțiilor

Patru lucruri separă o funcție care funcționează o dată de una pe care o veți reutiliza de fapt.

Argumente implicite

Setați o valoare implicită cu = pentru a face un argument opțional:

greet <- function(name = "Guest") paste("Hello,", name)
greet()
#> (1) "Hello, Guest"

The ... argument

Adăuga ... atunci când doriți ca funcția dvs. să trimită argumente suplimentare, fără nume direct către o altă funcție din interiorul ei – acesta este modul în care includeți o funcție R de bază fără a codifica fiecare dintre argumentele sale:

my_plot <- function(x, y, ...) plot(x, y, ...)
my_plot(mtcars$wt, mtcars$mpg, col = "steelblue", pch = 16)

Domeniul de aplicare și de ce să evite <<-

O variabilă creată în interiorul unei funcții există doar în interiorul acelei funcții – acesta este domeniul de aplicare local și este o caracteristică: funcțiile dvs. nu pot suprascrie în tăcere variabilele din scriptul principal din întâmplare. <<- (superatribuire) permite unei funcții să ajungă în afara ei și să modifice o variabilă globală. Funcționează, dar face ca comportamentul unei funcții să depindă de starea din afara propriilor argumente – exact tipul de eroare greu de urmărit într-un script de analiză de 300 de linii. Implicit, transmiterea valorilor ca argumente și obținerea rezultatelor înapoi cu return(); rezervaţie <<- pentru cazuri cu adevărat rare, cum ar fi actualizarea unui contor prin apeluri repetate.

O variabilă creată în interiorul unei funcții există doar în interiorul acelei funcțiiO variabilă creată în interiorul unei funcții există doar în interiorul acelei funcții

Funcții anonime

Pentru o operațiune scurtă, o singură dată, mai ales în interior sapply(), lapply()sau purrr::map() — de multe ori nu trebuie să denumiți deloc funcția:

sapply(1:5, (i) i * 2)   # R 4.1+ shorthand
#> (1)  2  4  6  8 10

Utilizați o funcție numită atunci când logica va fi reutilizată sau are mai mult de una sau două linii; folosiți unul anonim atunci când este cu adevărat de unică folosință.

Greșeli frecvente la scrierea funcțiilor R

  1. Uitare {{ }} în interiorul verbelor dplyr. Dacă funcția dvs. personalizată folosește group_by() sau summarise() și treceți un nume de coloană ca argument, aveți nevoie {{ }} în jurul lui — nume simple de argumente vor genera o eroare „obiect negăsit”.
  2. Scrierea logicii scalare și așteptarea ca aceasta să se vectorizeze. Un if instrucțiunea verifică o condiție, nu una pe rând. Pentru logica rând cu rând pe un vector, utilizați ifelse() sau dplyr::case_when() în loc de if/else în interiorul unei funcții menite să ruleze pe o întreagă coloană.
  3. Întinzând pentru <<- pentru a „remedia” o eroare de domeniu. Dacă o funcție nu poate vedea o variabilă, soluția este aproape întotdeauna de a o transmite ca argument – nu de a forța funcția să ajungă în afara ei.
  4. Fără validare de intrare. O funcție care presupune că intrarea sa este întotdeauna numerică, întotdeauna completă sau întotdeauna lungimea potrivită va eșua în tăcere sau va produce un număr greșit în loc de o eroare. Un singur stopifnot() linia de sus prinde atât de devreme.
Greșeli frecvente la scrierea funcțiilor RGreșeli frecvente la scrierea funcțiilor R

Întrebări frecvente

Trebuie să folosesc return() în fiecare funcție R?

Nu. R returnează automat valoarea ultimei linii evaluate în corpul funcției. Utilizare return() atunci când doriți să părăsiți funcția devreme sau când face punctul de ieșire mai clar pentru cineva care citește codul mai târziu.

Poate o funcție R să returneze mai multe valori?

O funcție poate trece înapoi doar un obiect return()dar acel obiect poate fi a list() deținând cât de multe rezultate denumite aveți nevoie – o medie, o abatere standard și o dimensiune a eșantionului într-un singur apel, de exemplu.

Care este diferența dintre o funcție și un script în R?

Un script rulează de sus în jos o dată. O funcție este un cod reutilizabil pe care îl definiți o dată și îl apelați în mod repetat, cu intrări diferite de fiecare dată, fără a reintroduce logica. Dacă vă treziți să copiați și lipiți aceleași 5 rânduri cu un număr schimbat, aceasta este o funcție, nu un script.

De ce funcția mea personalizată eșuează în interiorul mutate() sau summarise(), dar funcționează în afara acesteia?

Aceasta înseamnă aproape întotdeauna că funcția primește un nume de coloană ca argument simplu în loc să folosească o evaluare ordonată. Încheiați argumentul {{ }} oriunde este folosit în interiorul unui verb dplyr, așa cum se arată în plot_group_means() exemplu de mai sus.

Cum las funcția mea să accepte un nume de coloană fără ghilimele?

Utilizare {{ }} (creț-creț) din sistemul de evaluare ordonat al tidyverse. Vă permite să scrieți my_function(data, cyl) în loc de my_function(data, "cyl")care corespunde modului în care ați introduce numele coloanei direct într-un script.

Următorul pas

Scrierea unei funcții de uz general este simplă odată ce ați făcut-o de câteva ori. Scrierea uneia care supraviețuiește contactului cu un set de date de disertație real – valori lipsă, grupuri dezechilibrate, niveluri de factori non-standard – este locul în care se întrerupe majoritatea codului R autodidact. Dacă construiți o funcție sau un canal complet de analiză pentru un capitol de teză și doriți o a doua pereche de ochi asupra ei, trimiteți-ne un mesaj direct pe WhatsApp.

Lectură înrudită: statistici descriptive în R · cum să utilizați dplyr în R · fișă de cheat dplyr

📊

Aveți nevoie de această analiză pentru teza sau disertația dvs.? Mă voi descurca în R, SPSS sau Minitab – cu rezultate în format APA livrate rapid.

Dominic Botezariu
Dominic Botezariuhttps://www.noobz.ro/
Creator de site și redactor-șef.

Cele mai noi știri

Pe același subiect

LĂSAȚI UN MESAJ

Vă rugăm să introduceți comentariul dvs.!
Introduceți aici numele dvs.