2017-05-17 4 views
1

Angenommen, ich habe folgende Daten, die die Mischung aus 2 Bestandteilen aus der Menge der Zutaten zu bewegen A, B, C:tidyr Ausbreitung Verwendung von lang auf breit

(dat <- structure(list(var1 = c("A", "A", "A", "A", "A", "B", "B", "B", "C"), 
         var2 = c("-", "B", "B", "C", "C", "-", "C", "C", "-"), 
         val1 = c(100, 25, 50, 25, 50, 100, 25, 50, 100), 
         val2 = c(0, 75, 50, 75, 50, 0, 75, 50, 0)), 
        .Names = c("var1", "var2", "val1", "val2"), 
        row.names = c(NA, -9L), class = "data.frame")) 

# var1 var2 val1 val2 
# 1 A - 100 0 
# 2 A B 25 75 
# 3 A B 50 50 
# 4 A C 25 75 
# 5 A C 50 50 
# 6 B - 100 0 
# 7 B C 25 75 
# 8 B C 50 50 
# 9 C - 100 0 

ich jetzt möchte diese Daten zu transformieren: Ich würde gern haben Spalten mit der Bezeichnung A, B, C den Inhalt der einzelnen Inhaltsstoffe geben:

#  A B C 
# 1 100 0 0 
# 2 25 75 0 
# 3 50 50 0 
# 4 25 0 75 
# 5 75 0 25 
# 6 0 100 0 
# 7 0 25 75 
# 8 0 50 25 
# 9 0 0 100 

Wie würde ich lösen, dass tidyr mit? Beliebige Kombination von spread & unite?

+0

Bitte geben Sie an, was Sie bisher versucht haben und doesn Es scheint nicht zu funktionieren. –

+0

Nun, es ist eine konzeptionelle Frage. Ich versuchte 'spread (var1, val1, drop = FALSE)' was irgendwie in die richtige Richtung ging (bekam die Spalten, die ich wollte), aber ich sehe nicht, ob ich überhaupt auf dem richtigen Weg bin. Ich würde konzeptionell dasselbe mit '(var2, val2) tun müssen und dann die Ergebnisse irgendwie kombinieren. Aber ist das überhaupt richtig? – thothal

+1

Bitte verwenden Sie nicht den Kommentarbereich, um den Code zu teilen. Bearbeiten Sie Ihre ursprüngliche Frage. –

Antwort

2

Ich bin sicher, dass es eine elegantere Art und Weise, dies zu tun, aber man könnte folgendes tun:

library(dplyr) 
library(tidyr) 
wideDf <- data.frame(id = rep(1:nrow(dat),2), 
       var = c(dat$var1, dat$var2), val = c(dat$val1, dat$val2)) %>% 
     filter(var != "-") %>% tidyr::spread(key = var, value = val, fill = 0) 

, die Sie gibt:

> longDf 
# id A B C 
# 1 1 100 0 0 
# 2 2 25 75 0 
# 3 3 50 50 0 
# 4 4 25 0 75 
# 5 5 50 0 50 
# 6 6 0 100 0 
# 7 7 0 25 75 
# 8 8 0 50 50 
# 9 9 0 0 100 
+0

Sie können das 'fill' Argument in Spread verwenden, um dies zu vereinfachen –

+0

@RichardTelford danke, ich weiß nicht, warum ich das' fill' Argument vergessen habe. Habe meine Antwort bearbeitet. – ikop

0

Hier ist ein Ansatz, der nicht genau robust, scheint aber an Ihrem Beispiel zu arbeiten. Vielleicht können Sie es als Inspiration für bessere Lösungen verwenden.

t(apply(dat, MARGIN = 1, FUN = function(x) { 
    # "split" the data into names and values. works only for two columns, obviously 
    xval <- as.numeric(x[3:4]) 
    names(xval) <- x[1:2] 
    # make sure it's sorted for reasons that will become apparent later 
    xval <- xval[order(names(xval))] 
    # prepare an empty vector 
    out <- c(A = 0, B = 0, C = 0) 
    # and insert values from columns which appear in xval 
    find.index <- names(out) %in% names(xval) 
    out[find.index] <- xval[names(xval) %in% names(out)] 

    out 
})) 

     A B C 
[1,] 100 0 0 
[2,] 25 75 0 
[3,] 50 50 0 
[4,] 25 0 75 
[5,] 50 0 50 
[6,] 0 100 0 
[7,] 0 25 75 
[8,] 0 50 50 
[9,] 0 0 100 
1

ich tun würde, dies in zwei Teile sie dann fügen zusammen

library("tidyverse") 
v1 <- dat %>% rownames_to_column() %>% spread(key = var1, value = val1, fill = 0) %>% select(A, B, C) 
v2 <- dat %>% rownames_to_column() %>% spread(key = var2, value = val2, fill = 0) %>% select(A = `-`, B, C) 

v1 + v2 
1

Wenn Sie mit reshape2 hinwollen:

dat$id <- row.names(dat) 
dcast(rbind(dat[,c(5,1,3)], 
     setnames(dat[,c(5,2,4)],c("id","var1","val1"))), 
     id~var1, value.var = "val1", fill=0)[, -2] 

# id A B C 
# 1 1 100 0 0 
# 2 2 25 75 0 
# 3 3 50 50 0 
# 4 4 25 0 75 
# 5 5 50 0 50 
# 6 6 0 100 0 
# 7 7 0 25 75 
# 8 8 0 50 50 
# 9 9 0 0 100 
Verwandte Themen