Ändern Sie die leeren Zellen in "NA"

79

Hier ist der Link meiner Daten.

Mein Ziel ist es, allen leeren Zellen "NA" zuzuweisen, unabhängig von kategorialen oder numerischen Werten. Ich benutze na.strings = "" . Es wird jedoch nicht allen leeren Zellen NA zugewiesen.

## reading the data
dat <- read.csv("data2.csv")
head(dat)
  mon hr        acc   alc sex spd axles door  reg                                 cond1 drug1
1   8 21 No Control  TRUE   F   0     2    2      Physical Impairment (Eyes, Ear, Limb)     A
2   7 20 No Control FALSE   M 900     2    2                                Inattentive     D
3   3  9 No Control FALSE   F 100     2    2 2004                                Normal     D
4   1 15 No Control FALSE   M   0     2    2      Physical Impairment (Eyes, Ear, Limb)     D
5   4 21 No Control FALSE      25    NA   NA                                                D
6   4 20 No Control    NA   F  30     2    4                Drinking Alcohol - Impaired     D
       inj1 PED_STATE st rac1
1     Fatal      <NA>  F <NA>
2  Moderate      <NA>  F <NA>
3  Moderate      <NA>  M <NA>
4 Complaint      <NA>  M <NA>
5 Complaint      <NA>  F <NA>
6  Moderate      <NA>  M <NA>


## using na.strings
dat2 <- read.csv("data2.csv", header=T, na.strings="")
head(dat2)
  mon hr        acc   alc sex spd axles door  reg                                 cond1 drug1
1   8 21 No Control  TRUE   F   0     2    2 <NA> Physical Impairment (Eyes, Ear, Limb)     A
2   7 20 No Control FALSE   M 900     2    2 <NA>                           Inattentive     D
3   3  9 No Control FALSE   F 100     2    2 2004                                Normal     D
4   1 15 No Control FALSE   M   0     2    2 <NA> Physical Impairment (Eyes, Ear, Limb)     D
5   4 21 No Control FALSE      25    NA   NA <NA>                                  <NA>     D
6   4 20 No Control    NA   F  30     2    4 <NA>           Drinking Alcohol - Impaired     D
       inj1 PED_STATE st rac1
1     Fatal        NA  F   NA
2  Moderate        NA  F   NA
3  Moderate        NA  M   NA
4 Complaint        NA  M   NA
5 Complaint        NA  F   NA
6  Moderate        NA  M   NA
S Das
quelle
Bitte verwenden Sie Text, keine Bilder / Links, für Text - einschließlich Tabellen und ERDs. Paraphrase oder Zitat aus anderem Text. Verwenden Sie Bilder nur für das, was nicht als Text ausgedrückt werden kann, oder um Text zu erweitern. Bilder können nicht gesucht oder ausgeschnitten und eingefügt werden. Fügen Sie einem Bild eine Legende / einen Schlüssel und eine Erklärung hinzu. Machen Sie Ihren Beitrag in sich geschlossen. Fügen Sie Bilder / Links mit Bearbeitungsfunktionen ein.
Philipxy

Antworten:

95

Ich gehe davon aus, dass Sie über Zeile 5 Spalte "Sex" sprechen. Es kann vorkommen, dass die Zelle in der Datei data2.csv ein Leerzeichen enthält und daher von R nicht als leer betrachtet wird.

Außerdem habe ich festgestellt, dass in Zeile 5 Spalten "Achsen" und "Tür" die aus data2.csv gelesenen Originalwerte die Zeichenfolge "NA" sind. Sie möchten diese wahrscheinlich auch als na.strings behandeln. Um dies zu tun,

dat2 <- read.csv("data2.csv", header=T, na.strings=c("","NA"))

BEARBEITEN:

Ich habe Ihre data2.csv heruntergeladen. Ja, in Zeile 5, Spalte "Geschlecht", ist ein Leerzeichen. Also du möchtest

na.strings=c(""," ","NA")
Badoe
quelle
34

Sie können gsub verwenden, um mehrere Mutationen von Leerzeichen wie "" oder einem Leerzeichen als NA zu ersetzen:

data= data.frame(cats=c('', ' ', 'meow'), dogs=c("woof", " ", NA))
apply(data, 2, function(x) gsub("^$|^ $", NA, x))
sclarky
quelle
2
Kann auch verwendet werden gsub("^$", NA, trimws(x)), um mehr als ein Leerzeichen innerhalb einer Zelle zu verarbeiten. Beachten Sie jedoch, dass beide Ansätze alle Spalten in Zeichenfolgen- / Zeichenvariablen konvertieren (falls nicht bereits geschehen).
JWilliman
26

Eine augenfreundlichere Lösung dplyrwäre

require(dplyr)

## fake blank cells
iris[1,1]=""

## define a helper function
empty_as_na <- function(x){
    if("factor" %in% class(x)) x <- as.character(x) ## since ifelse wont work with factors
    ifelse(as.character(x)!="", x, NA)
}

## transform all columns
iris %>% mutate_each(funs(empty_as_na)) 

Um die Korrektur nur auf eine Teilmenge von Spalten anzuwenden, können Sie Spalten von Interesse mithilfe der Spaltenanpassungssyntax von dplyr angeben. Beispiel:mutate_each(funs(empty_as_na), matches("Width"), Species)

Wenn Ihre Tabelle Daten enthält, sollten Sie eine typsicherere Version von verwendenifelse

Holger Brandl
quelle
11
Wie ist das Hinzufügen einer neuen Bibliothek und das Erstellen einer neuen Funktion augenfreundlicher ? Und ich denke, Sie werden brauchen ifelse(x %in% c(""," ","NA"), NA, x).
zx8754
4
Die Verwendung einer Funktion zusammen mit mutate_eachbietet mehr Flexibilität und ein wiederverwendbares Muster. dplyrist heutzutage in R-Workflows allgegenwärtig und wurde nur hinzugefügt, um die Antwort in sich geschlossen zu machen. Ich denke hier x!=""ist richtig, da weder "" noch "NA" leer sind. Darüber hinaus schlägt die Antwort von @ sclarky für Datenrahmen mit Zahlen fehl, und @ Badoe's löst das Problem für vorhandene Datenrahmen nicht wirklich, sodass keine andere Antwort die Frage noch generisch zu beantworten scheint. Ich freue mich über bessere Lösungen.
Holger Brandl
1
dplyr ist heutzutage in R-Workflows allgegenwärtig - nein, nicht. Und was bedeutet " und @ Badoe's löst das Problem für vorhandene data.frames nicht wirklich " überhaupt? Können Sie diese Aussage etwas erweitern?
David Arenburg
10
Badoe erklärt, wie man konfiguriert, read.csvum leere Zellen beim Lesen einer Tabelle aus einer Datei in NA umzuwandeln. Da der Titel der Frage jedoch "Ändern Sie die leeren Zellen in" NA "" lautet, sollte eine vollständige Antwort die Situation abdecken, in der sich ein data.frame bereits in der Umgebung befindet und der Benutzer leere Zellen entfernen möchte.
Holger Brandl
1
Dies war möglicherweise nicht das, wonach das OP gesucht hatte, aber es half mir, fehlende Werte einschließlich leerer Zeichenfolgen und NAs zu zählen. df %>% mutate_all(funs(empty_as_na)) %>% summarize_all(funs(sum(is.na(.))))Während dplyr in der Akzeptanz weit verbreitet ist oder nicht, erfreut es sich großer Beliebtheit bei einer großen Untergruppe von R-Benutzern, einschließlich mir. Vielen Dank für diese Lösung.
Dannid
22

Dies sollte den Trick tun

dat <- dat %>% mutate_all(na_if,"")
Jonathan
quelle
1
Ich habe das bei einem sf-Objekt versucht und es wurde ein Analysefehler ausgegeben: unbekannter WKB-Typ 12. Scheint, als ob mutiert versucht hat, etwas in den Geometrien zu ersetzen.
aae
15

Ich bin kürzlich auf ähnliche Probleme gestoßen, und das hat bei mir funktioniert.

Wenn die Variable numerisch ist, sollte eine einfache Variable df$Var[df$Var == ""] <- NAausreichen. Wenn die Variable jedoch ein Faktor ist, müssen Sie sie zuerst in das Zeichen konvertieren, dann die ""Zellen durch den gewünschten Wert ersetzen und sie wieder in den Faktor konvertieren. In diesem Fall, Ihrer SexVariablen, gehe ich davon aus, dass dies ein Faktor ist, und wenn Sie die leere Zelle ersetzen möchten, würde ich Folgendes tun:

df$Var <- as.character(df$Var)
df$Var[df$Var==""] <- NA
df$Var <- as.factor(df$Var)
ZKH
quelle
3

Meine Funktion berücksichtigt Faktor, Zeichenvektor und mögliche Attribute, wenn Sie zum Lesen externer Dateien einen Port oder ein Fremdpaket verwenden. Außerdem können verschiedene selbst definierte na.strings abgeglichen werden. Um alle Spalten zu transformieren, verwenden Sie einfach lappy:df[] = lapply(df, blank2na, na.strings=c('','NA','na','N/A','n/a','NaN','nan'))

Weitere Kommentare:

#' Replaces blank-ish elements of a factor or character vector to NA
#' @description Replaces blank-ish elements of a factor or character vector to NA
#' @param x a vector of factor or character or any type
#' @param na.strings case sensitive strings that will be coverted to NA. The function will do a trimws(x,'both') before conversion. If NULL, do only trimws, no conversion to NA.
#' @return Returns a vector trimws (always for factor, character) and NA converted (if matching na.strings). Attributes will also be kept ('label','labels', 'value.labels').
#' @seealso \code{\link{ez.nan2na}}
#' @export
blank2na = function(x,na.strings=c('','.','NA','na','N/A','n/a','NaN','nan')) {
    if (is.factor(x)) {
        lab = attr(x, 'label', exact = T)
        labs1 <- attr(x, 'labels', exact = T)
        labs2 <- attr(x, 'value.labels', exact = T)

        # trimws will convert factor to character
        x = trimws(x,'both')
        if (! is.null(lab)) lab = trimws(lab,'both')
        if (! is.null(labs1)) labs1 = trimws(labs1,'both')
        if (! is.null(labs2)) labs2 = trimws(labs2,'both')

        if (!is.null(na.strings)) {
            # convert to NA
            x[x %in% na.strings] = NA
            # also remember to remove na.strings from value labels 
            labs1 = labs1[! labs1 %in% na.strings]
            labs2 = labs2[! labs2 %in% na.strings]
        }

        # the levels will be reset here
        x = factor(x)

        if (! is.null(lab)) attr(x, 'label') <- lab
        if (! is.null(labs1)) attr(x, 'labels') <- labs1
        if (! is.null(labs2)) attr(x, 'value.labels') <- labs2
    } else if (is.character(x)) {
        lab = attr(x, 'label', exact = T)
        labs1 <- attr(x, 'labels', exact = T)
        labs2 <- attr(x, 'value.labels', exact = T)

        # trimws will convert factor to character
        x = trimws(x,'both')
        if (! is.null(lab)) lab = trimws(lab,'both')
        if (! is.null(labs1)) labs1 = trimws(labs1,'both')
        if (! is.null(labs2)) labs2 = trimws(labs2,'both')

        if (!is.null(na.strings)) {
            # convert to NA
            x[x %in% na.strings] = NA
            # also remember to remove na.strings from value labels 
            labs1 = labs1[! labs1 %in% na.strings]
            labs2 = labs2[! labs2 %in% na.strings]
        }

        if (! is.null(lab)) attr(x, 'label') <- lab
        if (! is.null(labs1)) attr(x, 'labels') <- labs1
        if (! is.null(labs2)) attr(x, 'value.labels') <- labs2
    } else {
        x = x
    }
    return(x)
}
Jerry T.
quelle
3

Sie können auch mutate_atin verwendendplyr

dat <- dat %>%
mutate_at(vars(colnames(.)),
        .funs = funs(ifelse(.=="", NA, as.character(.))))

Wählen Sie einzelne Spalten aus, die geändert werden sollen:

dat <- dat %>%
mutate_at(vars(colnames(.)[names(.) %in% c("Age","Gender")]),
        .funs = funs(ifelse(.=="", NA, as.character(.))))

Ab (dplyr 0.8.0 oben) hat sich die Art und Weise, wie dies geschrieben werden soll, geändert. Bevor es war, funs()in .funs (funs(name = f(.)). Stattdessen verwenden funswir jetztlist (list(name = ~f(.)))

Beachten Sie, dass es auch eine viel einfachere Möglichkeit gibt, die Spaltennamen aufzulisten! (Sowohl der Name der Spalte als auch der Spaltenindex funktionieren)

dat <- dat %>%
mutate_at(.vars = c("Age","Gender"),
    .funs = list(~ifelse(.=="", NA, as.character(.))))
Kamnesie
quelle
2

Während viele der oben genannten Optionen gut funktionieren, fand ich das Erzwingen von Nicht-Zielvariablen chrproblematisch. Die Verwendung von ifelseund greplinnerhalb lapplylöst diesen Off-Target-Effekt auf (in begrenzten Tests). Verwenden des regulären Ausdrucks von Slarky in grepl:

set.seed(42)
x1 <- sample(c("a","b"," ", "a a", NA), 10, TRUE)
x2 <- sample(c(rnorm(length(x1),0, 1), NA), length(x1), TRUE)

df <- data.frame(x1, x2, stringsAsFactors = FALSE)

Das Problem des Zwangs zur Charakterklasse:

df2 <- lapply(df, function(x) gsub("^$|^ $", NA, x))
lapply(df2, class)

$ x1 [1] "Zeichen"

$ x2 [1] "Zeichen"

Auflösung unter Verwendung von ifelse:

df3 <- lapply(df, function(x) ifelse(grepl("^$|^ $", x)==TRUE, NA, x))
lapply(df3, class)

$ x1 [1] "Zeichen"

$ x2 [1] "numerisch"

Todd D.
quelle
2

Ich vermute, jeder hat bereits eine Antwort, obwohl dplyr na_if () für den Fall, dass jemand auf der Suche ist, (aus meiner Sicht) die effizientere der genannten ist:

# Import CSV, convert all 'blank' cells to NA
dat <- read.csv("data2.csv") %>% na_if("")

Hier ist ein zusätzlicher Ansatz, der die Funktion read_delim von readr nutzt. Ich habe gerade abgeholt (wahrscheinlich allgemein bekannt, aber ich werde hier für zukünftige Benutzer archivieren). Dies ist sehr einfach und vielseitiger als die oben genannten, da Sie alle Arten von leeren und NA-bezogenen Werten in Ihrer CSV-Datei erfassen können:

dat <- read_csv("data2.csv", na = c("", "NA", "N/A"))

Beachten Sie den Unterstrich in der Version von readr gegenüber Base R "." in read_csv.

Hoffentlich hilft das jemandem, der auf dem Posten wandert!

Glenn in Boston
quelle
0

Könnten Sie nicht einfach verwenden

dat <- read.csv("data2.csv",na.strings=" ",header=TRUE)

Wenn Sie beim Einlesen der Daten alle Leerzeichen in NA konvertieren, müssen Sie zwischen Ihrem Angebot ein Leerzeichen einfügen

user8333183
quelle
Was passiert, wenn Sie den Abstand zwischen den Zitaten nicht einfügen?
Nneka
0

Für diejenigen, die sich über eine Lösung mit der Methode data.table wundern , ist hier eine, für die ich eine Funktion geschrieben habe, die auf meinem Github verfügbar ist:

library(devtools)
source_url("https://github.com/YoannPa/Miscellaneous/blob/master/datatable_pattern_substitution.R?raw=TRUE")
dt.sub(DT = dat2, pattern = "^$|^ $",replacement = NA)
dat2

Die Funktion durchläuft jede Spalte, um festzustellen, welche Spalte Musterübereinstimmungen enthält. Dann gsub()wird nur auf Spalten angewendet, die Übereinstimmungen für das Muster enthalten "^$|^ $", um Übereinstimmungen durch NAs zu ersetzen .

Ich werde diese Funktion weiter verbessern, um sie schneller zu machen.

Yoann Pageaud
quelle
-3

Rufen Sie das dplyrPaket auf, indem Sie es cranin r installieren

library(dplyr)

(file)$(colname)<-sub("-",NA,file$colname) 

Es werden alle leeren Zellen in einer bestimmten Spalte als NA konvertiert

Wenn die Spalte "-", "", 0 enthält, ändern Sie den Code entsprechend dem Typ der leeren Zelle

Wenn ich beispielsweise eine leere Zelle wie "" anstelle von "-" erhalte, verwenden Sie diesen Code:

(file)$(colname)<-sub("", NA, file$colname)
Guna Baskar
quelle
1
Diese Antwort wird dplyrnach dem Laden nicht verwendet und lässt sich nicht gut auf "alle Spalten" skalieren, nach denen OP sucht.
Gregor Thomas