2017-03-14 1 views
2

Ich habe mehrere große Datentabellen in R. Einige Spaltennamen erscheinen zweimal mit einem fast doppelten Namen: Sie sind bis auf das letzte Zeichen gleich.R - Fügen Sie Spalten mit fast demselben Namen hinzu und speichern Sie sie mit dem richtigen Spaltennamen

Zum Beispiel:

[1] "Genre_Romance" (correct) 
[2] "Genre_Sciencefiction" (correct) 
[3] "Genre_Sciencefictio" (wrong) 
[4] "Genre_Fables" (correct) 
[5] "Genre_Fable" (wrong) 

Genre_Romance <- c(1, 0, 1, 0, 1) 
Genre_Sciencefiction <- c(0, 1, 0, 0, 0) 
Genre_Sciencefictio <- c(1, 0, 1, 1, 0) 
Genre_Fables <- c(0, 0, 1, 0, 0) 
Genre_Fable <- c(0, 0, 0, 0, 1) 
dt <- data.table(Genre_Romance, Genre_Sciencefiction, Genre_Sciencefictio, Genre_Fables, Genre_Fable) 

Jetzt möchte ich mit fast der gleichen Spaltennamen die Spaltenwerte hinzuzufügen. Ich möchte diese Summe unter dem richtigen Spaltennamen speichern, während die falsche Spalte entfernt wird. Die Lösung wäre hier:

dt[,"Genre_Sciencefiction"] <- dt[,2] + dt[, 3] 
dt[,"Genre_Fables"] <- dt[,4] + dt[, 5] 
dt[,"Genre_Sciencefictio"] <- NULL 
dt[,"Genre_Fable"] <- NULL 
dt 

Genre_Romance Genre_Sciencefiction Genre_Fables 
    1     1     0  
    0     1     0  
    1     1     1  
    0     1     0  
    1     0     1 

Wie Sie sehen können, nicht jeder Spaltenname hat eine fast ein Duplikat (wie „Genre_Romance“). Also behalten wir einfach die erste Spalte so.

Ich versuchte, dieses Problem mit einer for-Schleife zu lösen, um die Spaltennamen einzeln zu vergleichen und die Funktion substr() zu verwenden, um den längsten Spaltennamen mit dem kürzeren Spaltennamen zu vergleichen und die Summe zu übernehmen. Aber es funktioniert nicht richtig und ist nicht sehr R-freundlich.

Der Beitrag unten half mir auch ein bisschen weiter, aber ich kann nicht 'dupliziert' verwenden, da die Spaltennamen nicht genau gleich sind. how do I search for columns with same name, add the column values and replace these columns with same name by their sum? Using R

Vielen Dank im Voraus.

+0

Es verwenden könnte könnte helfen, wenn Sie einen konkreteren e geben Beispiel, mit Code, um es zu reproduzieren und (obwohl es ziemlich offensichtlich ist) die entsprechende gewünschte Ausgabe. Weitere Informationen finden Sie unter http://stackoverflow.com/a/28481250. – Frank

+0

Danke für deinen Kommentar @Frank. Ich habe meinen Beitrag bearbeitet. – equuz

+0

Würde das Maximum der beiden Spalten immer dasselbe Ergebnis liefern wie die Summe? Das heißt, könnte es jemals 1 in Sciencefiction und Science Fiction haben? Es scheint nicht sinnvoll zu sein, mit einer 2 für diese (scheinbar 1/0 Spalte) zu enden. – Frank

Antwort

2

Hier ist eine mehr oder weniger Basis R-Lösung, die auf agrep zu ähnlichen Namen finden. agrep ermöglicht enge String-Übereinstimmungen, basierend auf der "verallgemeinerten Levenshtein-Bearbeitungsdistanz".

# find groups of similar names 
groups <- unique(lapply(names(dt), function(i) agrep(i, names(dt), fixed=TRUE, value=TRUE))) 
# choose the final names as those that are longest 
finalNames <- sapply(groups, function(i) i[which.max(nchar(i))]) 

ich die längste Variablennamen in den einzelnen Gruppen zu halten, entschied sich, dass das Beispiel angepasst, Sie leicht auf die kürzeste mit which.min wechseln könnten oder könnten Sie einige Hartcodierung je nach vielleicht tun, was Sie wollen.

Als nächstes wird Reduce"+" Operator gegeben und erhält passende Gruppen mit lapply. Um stattdessen das Maximum zu berechnen, verwenden Sie max anstelle von "+". Die Variablen werden unter Verwendung von .SDcols von data.table mit einem data.frame ausgewählt, Sie könnten die Gruppenvektoren direkt einspeisen.

# produce a new data frame 
setNames(data.frame(lapply(groups, function(x) Reduce("+", dt[, .SD, .SDcols=x]))), 
     finalNames) 

@ Frank Kommentar stellt fest, dass dies in neueren vereinfacht werden kann (1.10+, glaube ich) Versionen von data.table.SD, .SDcols mit

, ersetzen Sie einfach data.frame dies ein data.table machen
# produce a new data frame 
setNames(data.frame(lapply(groups, function(x) Reduce("+", dt[, ..x]))), finalNames) 

zu vermeiden mit as.data.table oder wickeln Sie die Ausgabe in setDT.


Um die letzte Zeile in eine data.table Lösung wenden Sie

dtFinal <- setnames(dt[, lapply(groups, function(x) Reduce("+", dt[, .SD, .SDcols=x]))], 
        finalNames) 

oder nach @ Frank Kommentar

dtFinal <- setnames(dt[, lapply(groups, function(x) Reduce("+", dt[, ..x]))], finalNames) 

die beide Rück

dtFinal 
    Genre_Romance Genre_Sciencefiction Genre_Fables 
1:    1     1   0 
2:    0     1   0 
3:    1     1   1 
4:    0     1   0 
5:    1     0   1 
+1

Danke für den Tipp, @Frank. Ich habe diese Syntax in den Update-Hinweisen gesehen, dachte aber, dass es mit direktem Bezug auf Objekte außerhalb der data.table zu tun hat. Ich muss zurück und wieder lesen. – lmo

+0

Vielen Dank für Ihre Antwort @lmo! Es ist mehr oder weniger das, was ich suchte, aber es gibt immer noch ein paar Probleme. Wenn ich zum Beispiel den kompletten Datensatz ausprobiere, wird "Genre_Sciencefiction" weggelassen, aber die Spalte "Genre_Sciencefictionfilms" ist zweimal im neuen Datenrahmen. Viele Genres fehlen auch (wahrscheinlich, weil viele Genres ähnliche Strings enthalten wie "Genre_Detective" und "Genre_Detectivefilms"). Wie können wir das lösen? – equuz

+0

Eine einfache Lösung, die funktioniert, ist, das 'max.distance' Argument für die' agrep' Funktion zu tweefen. Es ist derzeit auf 0,1 eingestellt, was bedeutet, dass weniger als ein Zehntel der Buchstaben umgewandelt werden müssen. Sie könnten diesen Wert erhöhen. Eine bessere Lösung wäre wahrscheinlich die Beseitigung langwieriger Unterschiede wie "Filme". So etwas wie 'setnames (dt, names (dt), gsub (" filme? $ "," ", Names (dt)))', um "Film" und "Filme" vom Ende des Variablennamens zu entfernen. Es gibt viele SO-Posts, die dieses Beispiel erweitern. – lmo

Verwandte Themen