Puuttuvien arvojen (NA) korvaaminen R:ssä: na.omit & na.rm

⚡ Älykäs yhteenveto

R:n Replace Missing Values ​​-oppikurssi kattaa NA-arvojen havaitsemisen, epätäydellisten rivien poistamisen na.omit()-funktiolla ja niiden korvaamisen keskiarvolla tai mediaanilla mutate()-funktiolla. Tässä läpikäynnissä käytetään Titanic-tietokantaa, jossa sekä ikä että maksu sisältävät puuttuvia havaintoja.

  • 🔎 Havaitseminen ensin: colSums(is.na(df)) laskee puuttuvat arvot sarakkeittain ennen kuin tehdään päätöksiä niiden käsittelystä.
  • 🗑️ Rivin poisto: na.omit() poistaa kaikki NA:n sisältävät rivit, jolloin Titanicin datan 1 309 rivistä 1 045 riviin.
  • 📐 Keskimääräinen imputointi: apply() laskee sarakkeen keskiarvon funktiolla na.rm = TRUE ja mutate() kirjoittaa sen uuteen sarakkeeseen funktiolla ifelse()
  • 📊 Mediaanivaihtoehto: Mediaani vastustaa poikkeavia arvoja, mikä tekee siitä turvallisemman vaihtoehdon vinoille muuttujille, kuten hinnalle.
  • ⚡ Massaimputointi: apply() tai across() soveltaa samaa sääntöä kaikkiin numeerisiin sarakkeisiin yhdessä lausekkeessa.
  • ⚠️ Tunnettu kompromissi: Keskiarvon imputointi pienentää varianssia ja heikentää korrelaatioita, joten sitä ei pitäisi koskaan soveltaa sokeasti.

Korvaa puuttuvat arvot NA R:ssä

Mitä ovat puuttuvat arvot R:ssä?

Puuttuvia arvoja näkyy, kun havainnon sarakkeessa ei ole tallennettua arvoa tai kun ei-numeerinen paikkamerkki on numeron paikalla. Ne on poistettava tai korvattava ennen laskutoimituksia, koska useimmat R-funktiot palauttavat arvon NA heti, kun sellainen on läsnä.

Tässä tutoriaalissa näytetään, miten puuttuvia arvoja käsitellään dplyr-kirjaston avulla, joka on osa tidyverse-ekosysteemiä data-analyysiä varten.

Korvaa puuttuvat arvot R:ssä

Ensimmäinen askel on aina selvittää, kuinka monta arvoa puuttuu ja mistä.

Puuttuvien arvojen havaitseminen ja laskeminen R:ssä

Ennen kuin päätät, mitä tehdä puuttuville arvoille, sinun on tiedettävä, kuinka monta niitä on ja missä ne sijaitsevat. R tarjoaa neljä tarkistusmenetelmää, yhdestä kyllä-tai-ei-vastauksesta täyteen sarakkeen laskentaan.

# 1. Is there any NA at all?
anyNA(df_titanic)

# 2. How many in total?
sum(is.na(df_titanic))

# 3. How many per column, the most useful view
colSums(is.na(df_titanic))

# 4. Percentage missing per column
round(colMeans(is.na(df_titanic)) * 100, 1)

Käytännössä kannattaa käyttää colSums()-funktiota. Se palauttaa nimetyn vektorin, jossa on yksi laskuri saraketta kohden, mikä näyttää välittömästi, puuttuuko muuttujasta muutama arvo vai onko se enimmäkseen tyhjä.

Kokonaisten rivien laskeminen. complete.cases() palauttaa arvon TRUE riveille, joilla ei ole puuttuvaa arvoa missään kohdassa. Tämä kertoo etukäteen, kuinka paljon dataa na.omit() hylkäisi:

sum(complete.cases(df_titanic))       # rows that would survive
sum(!complete.cases(df_titanic))      # rows that would be dropped

Varoitus paikkamerkeistä. R tunnistaa vain NA:t. Datajoukot koodaavat usein puuttuvat arvot tyhjänä merkkijonona, välilyöntinä, merkillä "N/A", "-" tai vartijanumerona, kuten -99 tai 999. Nämä läpäisevät kaikki yllä olevat tarkastukset huomaamatta. Muunna ne tuonnin yhteydessä, jotta loput työnkulusta toimivat seuraavasti:

df <- read.csv(PATH, na.strings = c("", " ", "NA", "N/A", "-", "-99"))

Tarkista aina jokaisen numeerisen sarakkeen alue tuonnin jälkeen. Ikä -99 tai hinta 9999 on paljon vaarallisempi kuin rehellinen NA, koska mikään funktio ei varoita sinua siitä.

Puuttuvien tietojen tyypit: MCAR, MAR ja MNAR

Se, miksi arvo puuttuu, määrää, onko sen imputointi turvallista. Tilastotieteilijät tunnistavat kolme mekanismia.

  • MCAR, puuttuu kokonaan sattumanvaraisesti. Kadonmisen todennäköisyys ei liity mihinkään havaittuun tai havaittuun, esimerkiksi anturiin, joka vikaantuu satunnaisina hetkinä.ping Tai näiden rivien imputointi ei aiheuta harhaa, ainoastaan ​​tarkkuuden menetystä.
  • MAR, puuttuu satunnaisesti. Todennäköisyys riippuu muista havaituista muuttujista, mutta ei itse puuttuvasta arvosta. Jos vanhemmilla matkustajilla on pienempi todennäköisyys ikänsä kirjaamiseen, ikä on MAR, kun otetaan huomioon muut sarakkeet. Näitä sarakkeita käyttävä imputointi hoitaa tämän hyvin.
  • MNAR, puuttuu, ei sattumanvaraisesti. Todennäköisyys riippuu itse havaitsemattomasta arvosta, esimerkiksi suurituloisista, jotka kieltäytyvät ilmoittamasta tulojaan. Mikään imputointimenetelmä ei voi korjata tätä pelkästään datasta, ja itse puuttuva arvo sisältää tietoa, joka kannattaa kirjata merkintäsarakkeeseen.

Tässä opetusohjelmassa käytetty keskiarvon imputointi on puolustettavissa vain MCAR- ja yksinkertainen MAR-menetelmien käytössä. Silloinkin sillä on tunnettu hinta: jokaisen aukon täyttäminen samalla luvulla pienentää sarakkeen varianssia ja heikentää sen korrelaatiota kaiken muun kanssa. Vakavammassa työssä kannattaa käyttää mallipohjaista menetelmää, kuten mice-pakettia, ja pitää aina sarakkeessa merkintää siitä, mitkä arvot on imputoitu.

muuttua()

mutate() on dplyr verbi, joka luo uuden muuttujan tai korvaa olemassa olevan, mikä tekee siitä luonnollisen työkalun sarakkeen siivotun kopion rakentamiseen.

Jatketaan kahdessa osassa. Opimme kuinka:

  • sulje pois puuttuvat arvot tietokehyksestä
  • laskea puuttuvat arvot keskiarvolla ja mediaanilla

Verbi mutate() on erittäin helppokäyttöinen. Voimme luoda uuden muuttujan noudattamalla tätä syntaksia:

mutate(df, name_variable_1 = condition, ...)
arguments:
-df: Data frame used to create a new variable
-name_variable_1: Name and the formula to create the new variable
-...: No limit constraint. Possibility to create more than one variable inside mutate()

Sulje pois puuttuvat arvot (NA)

na.omit() on R-perusfunktio, ei dplyr-verbi, mutta se pipetoi tiedot silti puhtaasti. Se poistaa jokaisen rivin, joka sisältää vähintään yhden NA:n. Tämä on nopein vaihtoehto ja harvoin paras, koska yksi puuttuva arvo hylkää koko havainnon.

Puuttuvien havaintojen ongelman ratkaisemiseksi käytämme Titanic-tietoaineistoa. Tässä tietoaineistossa meillä on pääsy lentokoneessa olevien matkustajien tietoihin tragedian aikana. Tässä tietojoukossa on monia NA:ita, joista on huolehdittava.

Lataa CSV-tiedosto internetistä ja listaa sitten sarakkeet, jotka sisältävät NA:n:

PATH <- "https://raw.githubusercontent.com/guru99-edu/R-Programming/master/test.csv"
df_titanic <- read.csv(PATH, sep = ",")
# Return the column names containing missing observations
list_na <- colnames(df_titanic)[ apply(df_titanic, 2, anyNA) ]
list_na

lähtö:

## [1] "age"  "fare"

Täällä

colnames(df_titanic)[apply(df_titanic, 2, anyNA)]

palauttaa niiden sarakkeiden nimet, joista puuttuu vähintään yksi arvo.

Ikä- ja hintasarakkeista puuttuvat arvot.

Voimme pudottaa ne komennolla na.omit().

library(dplyr)
# Exclude the missing observations
df_titanic_drop <-df_titanic %>%
na.omit()		
dim(df_titanic_drop)

lähtö:

## [1] 1045   13

Uusi tietojoukko sisältää 1045 riviä verrattuna 1309 riviin alkuperäisessä tietojoukossa.

Sulje pois puuttuvat arvot

Implementoi puuttuvat tiedot keskiarvolla ja mediaanilla

Voit myös imputoida eli täyttää puuttuvat arvot keskiarvolla tai mediaanilla. Hyvä käytäntö on luoda kaksi erillistä muuttujaa keskiarvolle ja mediaanille. Kun muuttujat on luotu, voimme korvata puuttuvat arvot uusilla muuttujilla.

Käytämme soveltamismenetelmää sarakkeen keskiarvon laskemiseen NA:lla. Katsotaanpa esimerkkiä

Vaihe 1) Aiemmin opetusohjelmassa tallensimme sarakkeiden nimet ja puuttuvat arvot luetteloon lista_na. Käytämme tätä luetteloa

Vaihe 2) Laske keskiarvo argumentilla na.rm = TRUE. Tämä argumentti on pakollinen, koska sarakkeista puuttuu dataa, ja tämä käskee R:ää jättämään ne huomiotta.

# Create mean
average_missing <- apply(df_titanic[,colnames(df_titanic) %in% list_na],
      2,
      mean,
      na.rm =  TRUE)
average_missing

Code Selitys:

Välitämme 4 argumenttia soveltamismenetelmässä.

  • df: df_titanic[,colnames(df_titanic) %in% list_na]. Tämä koodi palauttaa sarakkeiden nimet list_na-objektista (eli "age" ja "fare")
  • 2: Laske sarakkeiden funktio
  • keskiarvo: Laske keskiarvo
  • na.rm = TOSI: Ohita puuttuvat arvot

lähtö:

##      age     fare 
## 29.88113 33.29548

Loimme onnistuneesti puuttuvia havaintoja sisältävien sarakkeiden keskiarvon. Näitä kahta arvoa käytetään korvaamaan puuttuvat havainnot.

Vaihe 3) Vaihda NA-arvot

Dplyr-kirjaston verbi mutate on hyödyllinen uuden muuttujan luomisessa. Emme välttämättä halua muuttaa alkuperäistä saraketta, jotta voimme luoda uuden muuttujan ilman NA:ta. mutate on helppokäyttöinen, valitsemme vain muuttujan nimen ja määritämme kuinka tämä muuttuja luodaan. Tässä on täydellinen koodi

# Create a new variable with the mean and median
df_titanic_replace <- df_titanic %>%
   mutate(replace_mean_age  = ifelse(is.na(age), average_missing[1], age),
   replace_mean_fare = ifelse(is.na(fare), average_missing[2], fare))

Code Selitys:

Luomme kaksi muuttujaa, korvaa_keskiarvo ja korvaa_mean_fare seuraavasti:

  • korvaa_keskimääräinen_ikä = ifelse(on.na(ikä), keskimääräinen_puuttuva[1], ikä)
  • korvaa_keskihinta = ifelse(on.na(hinta), keskimääräinen_puuttuu[2],hinta)

Jos sarakkeesta ikä puuttuu arvoja, vaihda ensimmäisellä elementillä medium_missing (iän keskiarvo), muuten säilytä alkuperäiset arvot. Sama logiikka hinnoissa

sum(is.na(df_titanic_replace$age))

lähtö:

## [1] 263

Korvauksen jälkeen uudessa sarakkeessa ei ole lainkaan puuttuvia arvoja:

sum(is.na(df_titanic_replace$replace_mean_age))

lähtö:

## [1] 0

Alkuperäisessä ikä-sarakkeessa on 263 puuttuvaa arvoa, kun taas uusi replace_mean_age-sarake on täyttänyt jokaisen niistä keski-iällä.

Vaihe 4) Voimme korvata puuttuvat havainnot myös mediaanilla.

median_missing <- apply(df_titanic[,colnames(df_titanic) %in% list_na],
      2,
      median,
      na.rm =  TRUE)
df_titanic_replace <- df_titanic %>%
            mutate(replace_median_age  = ifelse(is.na(age), median_missing[1], age), 
            replace_median_fare = ifelse(is.na(fare), median_missing[2], fare))
head(df_titanic_replace)

lähtö:

Imputoi puuttuvat tiedot keskiarvolla ja mediaanilla

Vaihe 5) Laajalla tietojoukolla vaiheittainen menetelmä muuttuu työlääksi. sapply() tiivistää koko proseduurin yhdeksi lausekkeeksi, mutta imputoituja arvoja ei koskaan nähdä.

sapply ei luo a datakehys, joten voimme kääriä sapply()-funktion data.frame()-tiedostoon datakehysobjektin luomiseksi.

# Quick code to replace missing values with the mean
df_titanic_impute_mean <- data.frame(
    sapply(
        df_titanic,
        function(x) ifelse(is.na(x),
            mean(x, na.rm = TRUE),
            x)))

Moderni imputointi replace_na():n ja across():n avulla

Yllä mainitut apply()- ja sapply()-lähestymistavat toimivat edelleen, mutta tidyr ja dplyr ilmaisevat nyt samat operaatiot turvallisemmin ja luettavammin.

replace_na() kiinteille arvoille. tidyr::replace_na() ottaa nimetyn luettelon sarakkeista ja niiden korvaavista sarakkeista:

library(tidyr)

df_titanic %>%
    replace_na(list(age = 29.88, fare = 33.30))

across() jokaiselle numeeriselle sarakkeelle. Tämä on suora, tyyppivarma korvaaja sapply()-funktiolle, ja toisin kuin sapply(), se ei koskaan koske merkki- tai tekijäsarakkeisiin:

library(dplyr)

# Mean-impute every numeric column
df_titanic %>%
    mutate(across(where(is.numeric),
                  ~ ifelse(is.na(.x), mean(.x, na.rm = TRUE), .x)))

# Median-impute instead
df_titanic %>%
    mutate(across(where(is.numeric),
                  ~ ifelse(is.na(.x), median(.x, na.rm = TRUE), .x)))

⚠️ Miksi sapply()-oikotie on riskialtis: Yhden rivin sapply()-esimerkki suoritetaan uudelleen joka sarake, mukaan lukien merkki- ja tekijäsarakkeet. Mean()-funktion kutsuminen näille palauttaa NA:n varoituksella, ja apply() pakottaa sitten koko tuloksen merkkimuotoon. Yllä oleva across(where(is.numeric), …)-versio välttää tämän kokonaan.

coalesce() varalla oleville sarakkeille. Kun toinen sarake voi antaa puuttuvan arvon, coalesce() palauttaa ensimmäisen ehjän arvon argumenttiensa perusteella:

df %>% mutate(age_final = coalesce(age, age_estimated, 0))

Pidä kirjaa muutoksistasi. Lisää lippu ennen imputointia, jotta mikä tahansa myöhempi malli voi oppia puuttuvasta arvosta:

df_titanic %>%
    mutate(age_was_missing = is.na(age),
           age = ifelse(is.na(age), mean(age, na.rm = TRUE), age))

Puuttuvien arvojen käsittely R:ssä: Metodiviite

Tässä opetusohjelmassa käsitellään kolmea lähestymistapaa:

  • Sulje pois kaikki puuttuvat havainnot
  • Imuta keskiarvolla
  • Imuta mediaanin kanssa

Alla oleva taulukko yhteenvetää havaitsemisen ja poistamisen:

Kirjasto Tavoite Code
pohja Listaa puuttuvat havainnot
colnames(df)[apply(df, 2, anyNA)]
pohja Poista jokainen rivi, joka sisältää NA:n
na.omit(df)

Imputointi keskiarvolla tai mediaanilla voidaan tehdä kahdella tavalla

  • Käytä sovellusta
  • Sapplyn käyttö
Menetelmä Lisätiedot edut Haitat
Askel askeleelta hakemuksen kanssa Tarkista sarakkeet, joissa puuttuu, laske keskiarvo/mediaani, tallenna arvo, korvaa mutate() Voit nähdä laskennallisen keskiarvon tai mediaanin Lisää toteutusaikaa. Voi olla hidasta suurella tietojoukolla
Nopea tapa sapplylla Käytä sapply() ja data.frame() etsiäksesi ja korvataksesi puuttuvat arvot automaattisesti keskiarvolla/mediaanilla Lyhyt koodi ja nopea Laskettuja arvoja ei koskaan näytetä

UKK

NA merkitsee puuttuvaa arvoa vektorin sisällä. NULL edustaa objektin puuttumista ja sen pituus on nolla. NaN on määrittelemättömän numeerisen operaation, kuten nollan jakamisen nollalla, tulos.

Käytä mediaania vinoille muuttujille, kuten maksulle tai tuloille, koska poikkeavat arvot vetävät keskiarvoa ylöspäin. Käytä keskiarvoa vain silloin, kun sarake on suunnilleen symmetrinen eikä siinä ole ääriarvoja.

Jokaisen aukon täyttäminen samalla arvolla pienentää sarakkeen varianssia ja heikentää sen korrelaatiota muiden muuttujien kanssa. Mallipohjaiset menetelmät, kuten mice-paketti, säilyttävät nämä suhteet paljon paremmin.

Useimmat algoritmit eivät hyväksy NA:ta ja aiheuttavat virheitä tai pudottavat rivejä hiljaa. Huolimaton imputointi vuotaa tietoa harjoitus- ja testijoukkojen välillä, joten laske imputointiarvot aina pelkästään harjoitusjaon perusteella.

Kyllä. Tekoälyavustajat voivat ehdottaa metodeja puutekuvion perusteella ja luonnostella dplyr-koodin. Tarkista valinta omaa colSums(is.na())-tulostasi ja toimialueen tietämystäsi vasten siitä, miksi data puuttuu.

Tiivistä tämä viesti seuraavasti: