2017-01-12 2 views
6

ich einen Datenrahmen mit einer Sequenz in ‚col1‘ und Werten in ‚col2‘ haben:Extend eine unregelmäßige Abfolge und fügen Nullen zu fehlenden Werten

col1 col2 
2  0.02 
5  0.12 
9  0.91 
13 1.13 

Ich möchte ‚col1‘ die unregelmäßige Abfolge erweitern mit einer regelmäßigen Abfolge von 1 bis 13 für die Werte in ‚col1‘, die in den ursprünglichen Daten fehlen, mag ich ‚col2‘ um den Wert haben 0 in der letzten Ausgabe:

col1 col2 
1  0 
2  0.02 
3  0 
4  0 
5  0.12 
6  0 
7  0 
8  0 
9  0.91 
10 0 
11 0 
12 0 
13 1.13 

Wie kann ich tun das in R?

+3

Kann nur, dass Ich mag diesen Thread wirklich für all die verschiedenen Arten, wie Menschen gezeigt haben, das Problem anzugehen? – LAP

+0

Ich denke, es könnte sich lohnen, diese Frage (mit vielen sehr schönen Antworten!) Auf eine ähnliche Frage basierend auf gruppierten Daten zu beziehen: [Schnellste Möglichkeit, Zeilen für fehlende Werte in einem dat.frame hinzuzufügen] (http: // stackoverflow .com/questions/10438969/Schnellster Weg zum Hinzufügen von Zeilen für fehlende Werte in einem Datenrahmen) – Henrik

Antwort

6
library(tidyr) 

complete(d, col1 = 1:13, fill = list(col2 = 0)) 

oder

complete(d, col1 = seq(max(col1))), fill = list(col2 = 0)) 
# A tibble: 13 × 2 
    col1 col2 
    <int> <dbl> 
1  1 0.00 
2  2 0.02 
3  3 0.00 
4  4 0.00 
5  5 0.12 
6  6 0.00 
7  7 0.00 
8  8 0.00 
9  9 0.91 
10 10 0.00 
11 11 0.00 
12 12 0.00 
13 13 1.13 

oder

library(dplyr) 

left_join(data.frame(col1 = seq(max(d$col1)))), d) 

Aber diese NA s statt Nullen verlassen wird.

4

Ein anderer Weg wäre der folgende. Ihre Daten werden hier mydf genannt. Sie erstellen einen Datenrahmen mit einer Spalte einschließlich 1 bis zum Maximalwert col1. Dann verwenden Sie die Werte col2 in mydf zu einer neuen Spalte namens col2 in foo. Sie verwenden die Zahlen in col1 in mydf als Index, wenn Sie diesen Prozess ausführen. Zu diesem Zeitpunkt haben Sie NA in col2 in foo. Sie wollen NA auf 0 ändern. Der letzte Schritt ist, dies zu tun. Sie suchen nach der Position von NA in col2 in foo mit is.na() und vergeben Nullen zu den Positionen.

foo <- data.frame(col1 = 1:max(mydf$col1)) 
foo$col2[mydf$col1] <- mydf$col2 
foo$col2[is.na(foo$col2)] <- 0 

Unter lmo Idee auf ein Konto, können Sie einen Datenrahmen mit 0 zunächst erstellen und den dritten Schritt vermeiden.

foo <- data.frame(col1 = 1:max(mydf$col1), col2 = 0) 
foo$col2[mydf$col1] <- mydf$col2 


# col1 col2 
#1  1 0.00 
#2  2 0.02 
#3  3 0.00 
#4  4 0.00 
#5  5 0.12 
#6  6 0.00 
#7  7 0.00 
#8  8 0.00 
#9  9 0.91 
#10 10 0.00 
#11 11 0.00 
#12 12 0.00 
#13 13 1.13 

DATA

mydf <- structure(list(col1 = c(2L, 5L, 9L, 13L), col2 = c(0.02, 0.12, 
0.91, 1.13)), .Names = c("col1", "col2"), class = "data.frame", row.names = c(NA, 
-4L)) 
+2

oder 'foo <- data.frame (col1 = 1: max (mydf $ col1), col2 = 0) 'in der ersten Zeile. Du musst also nicht die dritte Zeile machen. – lmo

+0

@Imo Ja, das stimmt. Lass mich meinen Beitrag revidieren. Vielen Dank. – jazzurro

+2

@jazzurro Ich denke, Ihre ursprüngliche Lösung verallgemeinert besser für mehr Spalten. Wenn zum Beispiel 10 Spalten im ursprünglichen Datensatz vorhanden sind, könnten Sie 'foo [Namen (mydf) [- 1]] [mydf $ col1] <- mydf [-1]' oder etwas Ähnliches (ungetestet) verwenden. Dann ist das Ändern von Nullen bei Einsen auch ziemlich einfach. –

0

Eine andere Möglichkeit wäre:

for (i in 1:max(test$col1)) { 
    if(!(i %in% test$col1)) (test <- rbind(test, c(i, 0))) 
} 
test <- test[order(test$col1),] 

Axeman Antwort wirklich süß ist, though.

Edit: Verwendete Daten -

test <- structure(list(col1 = c(2, 5, 9, 13), col2 = c(0.02, 0.12, 0.91, 
1.13)), .Names = c("col1", "col2"), row.names = c(NA, -4L), class = "data.frame") 

HAFTUNGSAUSSCHLUSS: Das sollte eigentlich nicht für große Datenmengen verwendet werden. Ich habe es mit 1k-Reihen versucht und es wurde innerhalb eines Herzschlags gemacht, aber mein zweiter Test mit 100k-Reihen läuft jetzt für Minuten, was Axemans Bedenken in seinem Kommentar wirklich betont.

+2

Für den Fall, dass Leistung zählt, ist eine Schleife mit einem, in dem Sie ein Objekt wachsen, ziemlich Worst-Case-Szenario. Eine vektorisierte Lösung ist viel besser. – Axeman

+1

Ja, ich stimme dem zu. Das OP erklärte "meine Daten sind", daher habe ich nicht wirklich über Rechenzeit nachgedacht. // Edit: Für Spaß und Kichern habe ich den Code einfach mit 100k Zeilen ausgeführt ... sagen wir mal, es läuft noch ... – LAP

8

Nur der Vollständigkeit halber, ein selbst binäre beitreten data.table mit (Sie NA s anstelle von Nullen erhalten werden, aber das kann leicht geändert werden könnte, wenn erforderlich)

library(data.table) 
setDT(df)[.(seq(max(col1))), on = .(col1)] 
#  col1 col2 
# 1: 1 NA 
# 2: 2 0.02 
# 3: 3 NA 
# 4: 4 NA 
# 5: 5 0.12 
# 6: 6 NA 
# 7: 7 NA 
# 8: 8 NA 
# 9: 9 0.91 
# 10: 10 NA 
# 11: 11 NA 
# 12: 12 NA 
# 13: 13 1.13 
3

einfach einen anderen Blickwinkel hinzuzufügen, betrachten das, was Sie haben, kann als spärlicher Vektor gesehen werden, dh als ein Vektor, dessen einzige Nicht-Null-Werte definiert sind. Sparse Vektoren durch das Matrix Paket in R. implementiert Wenn df Ihre ersten data.frame ist, versuchen:

require(Matrix) 
data.frame(col1=seq_len(max(df$col1)), 
     col2=as.vector(sparseVector(df$col2,df$col1,max(df$col1)))) 
# col1 col2 
#1  1 0.00 
#2  2 0.02 
#3  3 0.00 
#4  4 0.00 
#5  5 0.12 
#6  6 0.00 
#7  7 0.00 
#8  8 0.00 
#9  9 0.91 
#10 10 0.00 
#11 11 0.00 
#12 12 0.00 
#13 13 1.13 

Das gleiche Ergebnis in einem Einzeiler base R:

data.frame(col1=seq_len(max(df$col1)), 
    col2=`[<-`(numeric(max(df$col1)),df$col1,df$col2)) 
+0

Alles sortiert! Vielen Dank! – user2808642

3

Hier ist eine Funktion, die verwendet expandRows von splitstackshape Paket

expand_seq <- function(x){ 
    x$new <- c(x$col1[1], diff(x$col1)) 
    new_df <- splitstackshape::expandRows(x, 'new') 
    new_df$col1 <- seq(max(new_df$col1)) 
    new_df$col2[!new_df$col1 %in% x$col1] <- 0 
    rownames(new_df) <- NULL 
    return(new_df) 
} 

expand_seq(df) 
# col1 col2 
#1  1 0.00 
#2  2 0.02 
#3  3 0.00 
#4  4 0.00 
#5  5 0.12 
#6  6 0.00 
#7  7 0.00 
#8  8 0.00 
#9  9 0.91 
#10 10 0.00 
#11 11 0.00 
#12 12 0.00 
#13 13 1.13 
+1

Eine neue Funktion, die Sie für das Paket vorschlagen können? :) – jazzurro

+0

@jazzurro Sicher. Es wäre wirklich hilfreich :) – Sotos

+0

Sie können Ananda fragen, ob er daran interessiert ist. – jazzurro

2

Es gibt bereits einige Interesse Antworten hier.

Gerade hüpfen, können wir eine Folge von Zahlen 1-max(col1) erstellen und erhalten dann den entsprechenden Wert von col2match

col1 = seq(1, max(df$col1)) 
data.frame(col1, col2 = df$col2[match(col1, df$col1)]) 

# col1 col2 
#1  1 NA 
#2  2 0.02 
#3  3 NA 
#4  4 NA 
#5  5 0.12 
#6  6 NA 
#7  7 NA 
#8  8 NA 
#9  9 0.91 
#10 10 NA 
#11 11 NA 
#12 12 NA 
#13 13 1.13 

mit diesem NA s geben statt 0. Wenn wir 0s brauchen ,

data.frame(col1,col2 = ifelse(is.na(match(col1,df$col1)), 0, 
              df$col2[match(col1,df$col1)])) 

# col1 col2 
#1  1 0.00 
#2  2 0.02 
#3  3 0.00 
#4  4 0.00 
#5  5 0.12 
#6  6 0.00 
#7  7 0.00 
#8  8 0.00 
#9  9 0.91 
#10 10 0.00 
#11 11 0.00 
#12 12 0.00 
#13 13 1.13 
1

ich habe nicht eine einfache merge Lösung finden Sie hier so ist ein:

res <- merge(data.frame(col1=1:max(df$col1)),df,by="col1",all.x=TRUE) 
res$col2 <- ifelse(is.na(res$col2),0,res$col2) 

Die zweite Zeile ersetzt die NA aus der merge (linke äußere Verbindung) mit Nullen.

ist
res$col2[is.na(res$col2)] <- 0 

Das Ergebnis: Wie @Axeman weist darauf hin, kann dies auch erreicht werden durch

res 
## col1 col2 
##1  1 0.00 
##2  2 0.02 
##3  3 0.00 
##4  4 0.00 
##5  5 0.12 
##6  6 0.00 
##7  7 0.00 
##8  8 0.00 
##9  9 0.91 
##10 10 0.00 
##11 11 0.00 
##12 12 0.00 
##13 13 1.13 
+3

Die zweite Zeile kann 'res $ col2 [is.na (res $ col2)] <- 0' sein. – Axeman

2

Wir ich sagen können base R mit merge und replace

transform(merge(data.frame(col1= 1:13), df, all.x=TRUE), 
         col2 = replace(col2, is.na(col2), 0)) 
# col1 col2 
#1  1 0.00 
#2  2 0.02 
#3  3 0.00 
#4  4 0.00 
#5  5 0.12 
#6  6 0.00 
#7  7 0.00 
#8  8 0.00 
#9  9 0.91 
#10 10 0.00 
#11 11 0.00 
#12 12 0.00 
#13 13 1.13 
Verwandte Themen