A hiányzó értékek (NA) pótlása az R-ben: na.omit & na.rm

⚡ Okos összefoglaló

Az R-ben a hiányzó értékek cseréje című rész az NA értékek detektálását, a hiányos sorok eltávolítását a na.omit() függvénnyel, valamint az átlag vagy medián pótlását a mutate() függvénnyel tárgyalja. Ez a bemutató a Titanic adathalmazt használja, ahol a kor és a viteldíj is hiányzó megfigyeléseket tartalmaz.

  • ???? Első felismerés: A colSums(is.na(df)) függvény oszloponként megszámolja a hiányzó értékeket, mielőtt döntést hozna a kezelésükről.
  • 🗑️ Sor eltávolítása: Az na.omit() függvény minden NA-t tartalmazó sort eldob, így a Titanic adatainak számát 1,309 sorról 1,045-re csökkenti.
  • 📐 Átlagos imputáció: Az apply() függvény az na.rm = TRUE függvénnyel kiszámítja az oszlopátlagot, a mutate() függvény pedig az ifelse() függvénnyel egy új oszlopba írja azt.
  • 📊 Medián alternatíva: A medián ellenáll a kiugró értékeknek, ami biztonságosabb választássá teszi a ferde változók, például a viteldíj esetében.
  • ⚡ Tömeges imputálás: Az apply() vagy across() ugyanazt a szabályt alkalmazza egyetlen utasítás minden numerikus oszlopára.
  • ⚠️ Ismert kompromisszum: Az átlag imputációja csökkenti a varianciát és gyengíti a korrelációkat, ezért soha nem szabad vakon alkalmazni.

Hiányzó értékek cseréje NA az R-ben

Mik a hiányzó értékek az R-ben?

Hiányzó értékek akkor jelennek meg, ha egy megfigyelés oszlopában nincs rögzített érték, vagy ha egy nem numerikus helyőrző található a szám helyén. Ezeket el kell távolítani vagy ki kell cserélni bármilyen számítás előtt, mivel a legtöbb R függvény NA értéket ad vissza, amint jelen van.

Ez az oktatóanyag bemutatja, hogyan kezelheti a hiányzó értékeket a dplyr könyvtárral, amely a tidyverse adatelemzési ökoszisztéma része.

Cserélje ki a hiányzó értékeket az R-ben

Az első lépés mindig annak kiderítése, hogy hány érték hiányzik és hol.

Hogyan észleljük és számoljuk a hiányzó értékeket R-ben?

Mielőtt eldöntenéd, mit tegyél a hiányzó értékekkel, tudnod kell, hogy hány van belőlük, és hol helyezkednek el. Az R négyféle ellenőrzést kínál, az egyetlen igen-nem választól kezdve a teljes oszloponkénti összesítésig.

# 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)

A gyakorlatban a colSums() függvényt érdemes használni. Egy névvel ellátott vektort ad vissza, oszloponként egy darabszámmal, amely azonnal megmutatja, hogy egy változóból hiányzik-e néhány érték, vagy többnyire üres.

Teljes sorok számlálása. A complete.cases() függvény TRUE értéket ad vissza azokra a sorokra, amelyekben sehol sem hiányzik érték, ami előre megmutatja, hogy az na.omit() függvény mennyi adatot dobna ki:

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

Figyelmeztetés a helykitöltőkkel kapcsolatban. Az R csak az NA értékeket ismeri fel. Az adathalmazok gyakran kódolják a hiányzó értékeket üres karakterláncként, szóközként, „N/A”, „-” vagy őrszámként, például -99 vagy 999. Ezek a fenti ellenőrzéseken észrevétlenül átmennek. Importáláskor konvertáljuk őket, hogy a munkafolyamat többi része a következőképpen viselkedjen:

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

Importálás után mindig vizsgáld meg az egyes numerikus oszlopok tartományát. A -99-es kor vagy a 9999-es ár sokkal veszélyesebb, mint egy őszinte NA, mert egyetlen függvény sem fog figyelmeztetni rá.

Hiányzó adatok típusai: MCAR, MAR és MNAR

Az, hogy egy érték miért hiányzik, meghatározza, hogy biztonságos-e annak imputálása. A statisztikusok három mechanizmust ismernek.

  • MCAR, teljesen véletlenszerűen hiányzik. Az eltűnés valószínűsége független bármitől, legyen az megfigyelt vagy sem, például egy érzékelő véletlenszerű pillanatokban meghibásodik.ping Vagy ezen sorok imputálása nem okoz torzítást, csak pontosságvesztést.
  • MAR, véletlenszerűen hiányzik. A valószínűség más megfigyelt változóktól függ, de nem magától a hiányzó értéktől. Ha az idősebb utasok életkorát kisebb valószínűséggel rögzítették, akkor az életkor a többi oszlop alapján MAR. Az ezeket az oszlopokat használó imputálás jól kezeli ezt.
  • MNAR, nem véletlenszerűen hiányzik. A valószínűség magától a nem megfigyelt értéktől függ, például attól, hogy a magas keresetűek nem hajlandók megadni a jövedelmüket. Ezt egyetlen imputációs módszer sem tudja pusztán az adatokból kiküszöbölni, és maga a hiányzó érték is olyan információt hordoz, amelyet érdemes egy jelzőoszlopban rögzíteni.

Az ebben az oktatóanyagban használt átlagimputáció csak MCAR és egyszerű MAR esetén védhető. Még ebben az esetben is ismert a költsége: minden üres hely kitöltése ugyanazzal a számmal csökkenti az oszlop varianciáját, és gyengíti a korrelációját minden mással. Komoly munkához használjon modellalapú módszert, például a mice csomagot, és mindig jelölje meg egy oszlopban, hogy mely értékeket imputálta.

mute()

mutate() a dplyr egy új változót létrehozó vagy egy meglévőt felülíró ige, ami természetes eszközzé teszi egy oszlop tisztított másolatának létrehozásához.

Két részben folytatjuk. Megtanuljuk, hogyan:

  • zárja ki a hiányzó értékeket egy adatkeretből
  • a hiányzó értékeket az átlaggal és a mediánnal imputálja

A mute() ige nagyon könnyen használható. Létrehozhatunk egy új változót a következő szintaxis szerint:

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()

Hiányzó értékek kizárása (NA)

Az na.omit() egy alap R függvény, nem egy dplyr ige, de mégis tisztán pipe-ol. Elvesz minden olyan sort, amely legalább egy NA-t tartalmaz. Ez a leggyorsabb lehetőség, és ritkán a legjobb, mert egyetlen hiányzó érték elveti az egész megfigyelést.

A hiányzó megfigyelések problémájának megoldására a Titanic adatkészletet fogjuk használni. Ebben az adatállományban hozzáférünk a fedélzeten tartózkodó utasok információihoz a tragédia idején. Ez az adatkészlet sok NA-val rendelkezik, amelyekről gondoskodni kell.

Töltsd be a CSV fájlt az internetről, majd listázd ki az NA-t tartalmazó oszlopokat:

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

output:

## [1] "age"  "fare"

Itt,

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

visszaadja azoknak az oszlopoknak a nevét, amelyek legalább egy hiányzó értéket tartalmaznak.

Az életkor és a viteldíj oszlopok értékei hiányoznak.

Eldobhatjuk őket a na.omit() paranccsal.

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

output:

## [1] 1045   13

Az új adatkészlet 1045 sort tartalmaz, szemben az eredeti adatkészlet 1309 sorával.

A hiányzó értékek kizárása

Hiányzó adatok pótlása az átlaggal és a mediánnal

A hiányzó értékeket imputálhatjuk, azaz kitölthetjük az átlaggal vagy a mediánnal. Jó gyakorlat, ha két külön változót hozunk létre az átlaghoz és a mediánhoz. Létrehozás után a hiányzó értékeket az újonnan létrehozott változókkal helyettesíthetjük.

Az NA-val rendelkező oszlop átlagának kiszámításához az Apply módszert fogjuk használni. Lássunk egy példát

Step 1) Az oktatóanyag korábbi részében a list_na nevű listában tároltuk az oszlopok nevét a hiányzó értékekkel. Ezt a listát fogjuk használni

Step 2) Számítsa ki az átlagot az na.rm = TRUE argumentummal. Ez az argumentum kötelező, mert az oszlopokból hiányoznak adatok, és ez arra utasítja az R-t, hogy hagyja figyelmen kívül azokat.

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

Code Magyarázat:

4 argumentumot adunk át az alkalmazó metódusban.

  • df: df_titanic[,colnames(df_titanic) %in% list_na]. Ez a kód visszaadja a list_na objektum oszlopnevét (azaz „age” és „fare”)
  • 2: Számítsa ki a függvényt az oszlopokon
  • átlag: Számítsa ki az átlagot
  • na.rm = TRUE: A hiányzó értékek figyelmen kívül hagyása

output:

##      age     fare 
## 29.88113 33.29548

Sikeresen elkészítettük a hiányzó megfigyeléseket tartalmazó oszlopok átlagát. Ezzel a két értékkel pótoljuk a hiányzó megfigyeléseket.

Step 3) Cserélje ki az NA értékeket

A dplyr könyvtárból származó mute ige hasznos új változó létrehozásához. Nem feltétlenül akarjuk megváltoztatni az eredeti oszlopot, hogy új változót tudjunk létrehozni az NA nélkül. A mute használata egyszerű, csak kiválasztunk egy változónevet, és meghatározzuk, hogyan kell létrehozni ezt a változót. Itt a teljes kód

# 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 Magyarázat:

Két változót hozunk létre, a change_mean_age és a change_mean_fare értéket a következők szerint:

  • csere_átlagos_kor = ifelse(is.na(kor), átlagos_hiányzó[1], életkor)
  • csere_átlagos_viteldíj = ifelse(is.na(viteldíj), átlagos_hiányzó[2],viteldíj)

Ha az életkor oszlopból hiányzó értékek vannak, akkor cserélje ki az átlag_hiányzó (életkor átlaga) első elemére, különben megtartja az eredeti értékeket. Ugyanez a logika a viteldíjnál

sum(is.na(df_titanic_replace$age))

output:

## [1] 263

A csere után az új oszlop egyáltalán nem tartalmaz hiányzó értékeket:

sum(is.na(df_titanic_replace$replace_mean_age))

output:

## [1] 0

Az eredeti „kor” oszlop 263 hiányzó értéket tartalmaz, míg az új „replace_mean_age” oszlop mindegyiket kitöltötte az átlagos életkorral.

Step 4) A hiányzó megfigyeléseket a mediánnal is pótolhatjuk.

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)

output:

Impulálja a hiányzó adatokat az átlaggal és a mediánnal

Step 5) Egy nagy adathalmazon a lépésről lépésre haladó módszer unalmassá válik. Az apply() egyetlen utasításba omlasztja össze az egész eljárást, de ennek az az ára, hogy soha nem látja az imputált értékeket.

az apply nem hoz létre a adatkeret, így a sapply() függvényt becsomagolhatjuk a data.frame() keretbe, hogy adatkeret objektumot hozzunk létre.

# 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)))

Modern imputáció a replace_na() és across() függvényekkel

A fenti apply() és sapply() megközelítések továbbra is működnek, de a tidyr és a dplyr mostantól biztonságosabban és olvashatóbban fejezik ki ugyanazokat a műveleteket.

replace_na() fix értékek esetén. A tidyr::replace_na() függvény egy névvel ellátott oszloplistát és azok helyettesítőit veszi fel:

library(tidyr)

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

across() minden numerikus oszlophoz. Ez a sapply() egysoros utasítás közvetlen, típusbiztos helyettesítője, és a sapply() függvénnyel ellentétben soha nem érinti a karakter- vagy faktoroszlopokat:

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)))

⚠️ Miért kockázatos a sapply() parancsikon használata: az egysoros sapply() példa végigfut minden oszlop, beleértve a karakteres és faktoros oszlopokat is. A mean() meghívása ezekre NA értéket ad vissza figyelmeztetéssel, majd az apply() a teljes eredményt karakteresre alakítja. A fenti across(where(is.numeric), …) verzió ezt teljesen elkerüli.

coalesce() a tartalék oszlopokhoz. Amikor egy második oszlop is tudja a hiányzó értéket megadni, a coalesce() függvény az argumentumai alapján visszaadja az első nem hiányzó bejegyzést:

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

Jegyezd fel, hogy mit változtattál meg. Adjunk hozzá egy jelzőt az imputálás előtt, hogy bármely későbbi modell tanulhasson a hiányzó értékből:

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

Hiányzó értékek kezelése R-ben: Metódusreferencia

Három megközelítést tárgyalunk ebben az oktatóanyagban:

  • Zárja ki az összes hiányzó megfigyelést
  • Imputáld az átlaggal
  • Imputáld a mediánnal

Az alábbi táblázat összefoglalja az észlelést és az eltávolítást:

könyvtár Objektív Code
bázis Sorolja fel a hiányzó megfigyeléseket
colnames(df)[apply(df, 2, anyNA)]
bázis Távolítson el minden NA-t tartalmazó sort
na.omit(df)

Az átlaggal vagy mediánnal való imputálás kétféleképpen történhet

  • Az alkalmazás használata
  • Sapply használata
Módszer Részletek Előnyök Hátrányok
Lépésről lépésre az alkalmazással Ellenőrizze a hiányzó oszlopokat, számítsa ki az átlagot/mediánt, tárolja az értéket, cserélje ki a mute() Láthatja az imputált átlagot vagy mediánt Több végrehajtási idő. Lassú lehet nagy adatkészlettel
Gyors út, applikátorral A sapply() és data.frame() használatával automatikusan megkeresheti és a hiányzó értékeket átlag/mediánra cserélheti Rövid kód és gyors A bevitt értékek soha nem jelennek meg

GYIK

Az NA egy hiányzó értéket jelöl egy vektoron belül. A NULL egy objektum hiányát jelöli, és nulla hosszúságú. A NaN egy definiálatlan numerikus művelet eredménye, például a nulla nullával osztása.

A mediánt ferde változók, például a viteldíj vagy a jövedelem esetén használd, mivel a kiugró értékek felfelé húzzák az átlagot. Az átlagot csak akkor használd, ha az oszlop nagyjából szimmetrikus és mentes a szélsőséges értékektől.

Ha minden rést ugyanazzal az értékkel töltünk ki, az oszlop varianciája csökken, és gyengíti a korrelációját más változókkal. A modellalapú módszerek, mint például a mice csomag, sokkal jobban megőrzik ezeket a kapcsolatokat.

A legtöbb algoritmus nem fogadja el a nulla értékeket (NA), és hibákat jelez, vagy csendben elveti a sorokat. A gondatlan imputáció információszivárgást okozhat a tanuló- és teszthalmazok között, ezért az imputálási értékeket mindig csak a tanulórészleten kell kiszámítani.

Igen. A mesterséges intelligencia asszisztensek metódusokat javasolhatnak a hiányzó minták alapján, és elkészíthetik a dplyr kód vázlatát. Ellenőrizd a választást a saját colSums(is.na()) kimeneted és a hiányzó adatok okára vonatkozó szakterületi ismereteid alapján.

Foglald össze ezt a bejegyzést a következőképpen: