2016-05-17 1 views
1

OK, so habe ich das soentfernen NAs in Reihe und die Zelle auf der rechten Seite bewegen wurden die NA in R in R auch wie einen Datenrahmen eindeutige Werte

ID <- c(1, 2, 3) 
c1 <- c(1, 1, NA) 
c2 <- c(NA, NA, 5) 
c3 <- c(NA, NA, NA) 
c4 <- c(2, NA, 5) 
c5 <- c(5, 7, 3) 

df <- data.frame(ID, c1, c2, c3, c4, c5) 

entfernt wurde, ist das, was ich ist auf der Suche nach

1. Treat every row as a vector 
2. Be able to remove all NAs in every row/vector 
3. In a given row there can't be repeated values (expect for ID vs a number in other cell) 
4. I'm looking to "cut" this row/vector. I don't need 5 values just 2. 

ich diese Metrik für ein [email protected] k tun, so dass die Reihenfolge der Zahlen (der auf der linken Seite ist mehr importante als der nächste) Sohn es wichtig ist, um die Reihenfolge zu halten .

Dies ist die Ausgabe, die ich für

ID <- c(1, 2, 3) 
c1 <- c(1, 1, 5) 
c2 <- c(2, 7, 3) 

df2 <- data.frame(ID, c1, c2) 

Vielen Dank für Ihre Hilfe

Antwort

2

Wir Schleife durch die Reihen der ‚df‘ (mit apply mit MARGIN als 1) suchen, entfernen Sie die NA Elemente (!is.na(x)) und erhalten Sie die unique Werte. Wenn dann die Länge der Elemente nicht gleich ist, wird die Ausgabe ein list ('lst') sein. Wir verwenden lengths, um die length von jedem Element , get the min Liste elements and cbind` mit der ersten Spalte 'ID' zu erhalten.

lst <- apply(df[-1], 1, function(x) unique(x[!is.na(x)])) 
dfN <- cbind(df[1], do.call(rbind,lapply(lst, function(x) x[seq(min(lengths(lst)))]))) 
colnames(dfN)[-1] <- paste0("c", colnames(dfN)[-1]) 
dfN 
# ID c1 c2 
#1 1 1 2 
#2 2 1 7 
#3 3 5 3 

HINWEIS: Wenn die length von unique Elemente die gleichen in jeder Reihe sind (nach dem NA entfernen), wird die Ausgabe ein matrix sein. Transponieren Sie einfach den Ausgang und cbind mit der ersten Spalte.


Oder eine andere Option ist data.table, die sehr effizient sein sollte.

library(data.table) 
dM <- melt(setDT(df), id.var="ID", na.rm=TRUE)[, 
      .(value = unique(value), n = seq(uniqueN(value))), ID] 
dcast(dM[dM[, n1 := min(tabulate(ID))][, .I[1:.N <=n1] , ID]$V1], 
      ID~paste0("c", n), value.var="value") 
# ID c1 c2 
#1: 1 1 2 
#2: 2 1 7 
#3: 3 5 3 
+1

Ich bin dabei, es meinen tatsächlichen Code zu versuchen, Danke! Du bist fantastisch! –

+1

Ich denke, das seit langem bestehende Paradigma ist der Weg für diese Art von Problem. Es skaliert gut und kann relativ einfach in dplyr/data.table/base R/sql konvertiert werden. – thelatemail

+1

Ich habe die data.table-Idee benutzt und sie in dplyr/tidyr übersetzt. Es klappt! Ich danke dir sehr! –

1

hässlich, aber sollte effizient sein (in etwa 20secs und 300K in < 2 Sekunden durch 3M Aufzeichnungen gekaut):

sel <- !is.na(df[-1]) 
tmp <- unique(data.frame(ID=df$ID[row(df[-1])[sel]], c=df[-1][sel])) 
tmp$time <- ave(tmp$ID, tmp$ID, FUN=seq_along) 

reshape(tmp[tmp$time <= 2,], idvar="ID", direction="wide", sep="") 

# ID c1 c2 
#1 1 1 2 
#2 2 1 7 
#3 3 5 3 
1

Basierend auf akrun data.table Idee, übersetzte ich den data.table Code zu dplyr/tidyr (ist leichter für mich zu lesen, das ist alles). Hier ist der Code

library(dplyr) 
library(tidyr) 

df_tidy <- df %>% 
gather(importance, val, c1:c5) %>% 
na.omit %>% 
arrange(ID, importance) %>% 
group_by(ID) %>% 
distinct(ID, val) %>% 
mutate(place = seq_len(n())) %>% 
filter(place <= 2) %>% 
mutate(place = paste("c", place, sep="")) %>% 
select(-importance) %>% 
spread(place, val) 

Vielen Dank akrun und thelatemail!

Verwandte Themen