Den Schuldigen finden - wenn sich Zahlen nicht einlesen lassen.

Wiederkehrende Fragen zum Forum

Moderator: EDi

Antworten
bigben
Beiträge: 2771
Registriert: Mi Okt 12, 2016 9:09 am

Den Schuldigen finden - wenn sich Zahlen nicht einlesen lassen.

Beitrag von bigben »

Hallo!

Manchmal will man einfach ein paar Zahlen in R einlesen und wenn dann eine einzige Zahl in der Reihe falsch geschrieben ist, hält R die ganze Zahlenreihe für Buchstaben anstelle von Zahlen. Wenn Du auf diesen Thread verwiesen worden bist, dann vermutet der Ratschlagende wahrscheinlich genau das. Je nach Länge der Zahlenkolonne kann es aufwändig sein, nach dem schuldigen Eintrag zu suchen. Dabei kann Dir die folgende Funktion helfen. Du kannst Sie mit "Alles markieren" markieren und dann einfach mit Strg-C Strg-V in Deine R Sitzung copypasten.

Code: Alles auswählen

find_culprit <- function(vec, max = 12, silent = FALSE){
  if(max < 1)   # call with max = FALSE for no max
    max <- Inf
  if(!is.null(dim(vec))){
    warning("This is not a vector.")
  }
  if(is.numeric(vec)){
    warning("This vector is of a numeric type.")
    return()
  }
  if(!is.factor(vec) & !is.character(vec)) {
    warning("find_culprit expects either a vector of type factor or character.")
    return()
  }
  suppressWarnings(numeric <- as.numeric(as.character(vec)))
  position <- which(is.na(numeric) & !is.na(vec))
  if(length(position) == 0){
    cat("No culprits found.\n")
    return()
  }
  if(!silent) {
    cat("Found "); cat(length(position)); 
    cat(" entries that could not be coerced to numeric.\nReporting ");
    cat(min(length(position), max)); cat(".\n")
  }
  return(data.frame(position = head(position, max), 
                    culprits = head(vec[position], max)))
}

find_culprit_tests <- function(){
  library(testthat)
  # warnings for wrong input
  expect_warning(find_culprit(1:10))
  expect_warning(find_culprit(matrix(1:4, nrow=2)))
  expect_warning(find_culprit(iris))

  # wrong results
  expect_equal(find_culprit(c(1, 2, 3, "a", NA, 6, "b", NaN, "c"), silent = TRUE),
               structure(list(position = c(4L, 7L, 8L, 9L), 
                              culprits = c("a", "b", "NaN", "c")), 
                         class = "data.frame", row.names = c(NA, -4L)))
  expect_silent(find_culprit(iris[,5], silent = TRUE))
  
  # test silent option
  expect_output(find_culprit(c(1, 2, 3, "a", NA, 6, "b", NaN, "c"), silent = FALSE))
  expect_silent(find_culprit(c(1, 2, 3, "a", NA, 6, "b", NaN, "c"), silent = TRUE))
}
Danach steht Dir dann die Funktion find_culprit zur Verfügung, mit der sich der "schuldige" Eintrag in einem Vektor finden lässt, der eine Umwandlung des ganzen Vektors in eine Zahlenfolge verhindert:

Code: Alles auswählen

> test <- c("3.23", "5.90", "4.02", "4,02", "5.32", "4.OO")
> find_culprit(test)
Found 2 entries that could not be coerced to numeric.
Reporting 2.
  position culprits
1        4     4,02
2        6     4.OO
Der vierte Eintrag im Vektor benutzt ein Komma anstelle des Dezimalpunkts, der sechste enthält den Buchstaben "o" anstelle der Null. Mit diesem Wissen kann man sich an die Korrektur machen.

So, und nun viel Erfolg beim Einlesen Deiner Daten.

LG,
Bernhard
---
Programmiere stets so, dass die Maxime Deines Programmierstils Grundlage allgemeiner Gesetzgebung sein könnte
Benutzeravatar
student
Beiträge: 674
Registriert: Fr Okt 07, 2016 9:52 am

Re: Den Schuldigen finden - wenn sich Zahlen nicht einlesen lassen.

Beitrag von student »

Sehr schön! Ich habe bisher, wenn es die Größe des Datensatzes zuließ, Excel oder meinen Lieblingseditor genommen.
Viele Grüße,
Student
-----------------------------------------------------------------------------------------------------------------------
faes.de, Datenanalyse mit R & das Ad-Oculos-Projekt
Das Ad-Oculos-Projekt auf YouTube

Habe Mut, dich deines eigenen Verstandes zu bedienen! (Kant)
jogo
Beiträge: 2085
Registriert: Fr Okt 07, 2016 8:25 am

Re: Den Schuldigen finden - wenn sich Zahlen nicht einlesen lassen.

Beitrag von jogo »

ja, schöne Komfortversion. Bei mir sah das sonst so aus:

Code: Alles auswählen

test <- c("3.23", "5.90", "4.02", "4,02", "5.32", "4.OO")
is.na(as.numeric(test))
i <- is.na(as.numeric(test))
test[i] ### ggf. noch which(i)
Gruß, Jörg
bigben
Beiträge: 2771
Registriert: Mi Okt 12, 2016 9:09 am

Re: Den Schuldigen finden - wenn sich Zahlen nicht einlesen lassen.

Beitrag von bigben »

Hallo Jörg,

danke. Es ist ja immer die Frage ob es sich lohnt, eine "Komfortversion" zu schreiben, oder ob es die adhoc-Lösung nicht auch tut. Natürlich tut es die adhoc-Version auch, aber in Deiner Version fehlt mit dann der as.character-Schritt, falls die Daten als factor eingelesen wurden und sie funktioniert auch nicht wirklich gut, wenn die Daten von Haus aus viele NA mitbringen. Drum habe ich mich für diesen Variante entschieden, bei der man über sowas nicht immer neu nachdenken muss. Wenn keiner in den nächste 6 - 12 Monaten darauf verlinkt, können wir den Thread von mir aus auch wieder löschen. Dann hat sich die "Komfortversion" nicht gelohnt :)

Viele Grüße,
Bernhard
---
Programmiere stets so, dass die Maxime Deines Programmierstils Grundlage allgemeiner Gesetzgebung sein könnte
jogo
Beiträge: 2085
Registriert: Fr Okt 07, 2016 8:25 am

Re: Den Schuldigen finden - wenn sich Zahlen nicht einlesen lassen.

Beitrag von jogo »

Hallo Bernhard,

warum willst Du den den Thread löschen wollen, wenn doch Arbeit in der Funktion drinne steckt? (Früher sagte man: das frisst doch kein Brot, wenn der Beitrag hier im Forum steht.)
Mein Geschriebsel ist nur das, was man üblicherweise bei den gegebenen Daten aus dem Handgelenk schüttelt.
Deine Komfortversion ist gut und deckt einige Fälle an, in denen das kurze Geschriebsel nicht mehr ausreicht.

Gruß, Jörg
Antworten