2016-07-28 15 views
0

Ich möchte grundsätzlich das Gegenteil von ddply(df, columns.to.preserve, numcolwise(FUNCTION) tun.Zeilenweise Erweiterung von data.frame

Angenommen, ich habe

d <- data.frame(
    count=c(2,1,3), 
    summed.value=c(50,20,30), 
    averaged.value=c(35,80,20) 
) 

     count summed.value averaged.value 
1  2   50    35 
2  1   20    80 
3  3   30    20 

ich eine Reihe Erweiterung dieser data.frame auf der count Spalte basiert tun wollen, während die Angabe, welche Art von Operation ich zu den anderen Spalten anwenden möchten. Hier ist die Art von Ergebnis ich suche:

> d2 
    count summed.value averaged.value 
1  1   25    35 
2  1   25    35 
3  1   20    80 
4  1   10    20 
5  1   10    20 
6  1   10    20 

Alle dort innerhalb dplyr oder anderen Pakete in Funktionen eingebaut, die diese Art von Operation tun?

Bearbeiten: Das ist anders als die De-aggregate/reverse-summarise/expand a dataset in R Frage, weil ich weiter gehen und tatsächlich verschiedene Funktionen auf Spalten innerhalb der Tabelle anwenden möchte, die ich erweitern möchte. Es gibt auch nützlichere und Antworten auf diesen Beitrag.

+4

einige Orten auf dem Ausbau die data.frame starten [hier] (http : //stackoverflow.com/questions/38208529/de-aggregate-reverse-summarise-expand-a-dataset-in-r). Sobald dies geschehen ist, teilen Sie einfach "summed.value" und "count" durch "count". – aosmith

Antwort

2

Verwenden dplyr und tidyr können Sie eine rowwise Transformation für die summed.value tun, die für jede Zelle eine Liste erzeugt und dann unnest die Spalte sollten Sie geben, was Sie brauchen:

library(dplyr); library(tidyr) 
d %>% rowwise() %>% summarise(summed.value = list(rep(summed.value/count, count)), 
           averaged.value = averaged.value, count = 1) %>% unnest() 

# Source: local data frame [6 x 3] 

# averaged.value count summed.value 
#   <dbl> <dbl>  <dbl> 
# 1    35  1   25 
# 2    35  1   25 
# 3    80  1   20 
# 4    20  1   10 
# 5    20  1   10 
# 6    20  1   10 

Ein anderer Weg ist data.table zu verwenden , wo Sie die Zeilennummer als Gruppenvariable angeben, und die Datentabelle wird es automatisch erweitern:

library(data.table) 
setDT(d) 
d[, .(summed.value = rep(summed.value/count, count), averaged.value, count = 1), .(1:nrow(d))] 
[, nrow := NULL][] 

# summed.value averaged.value count 
#1:   25    35  1 
#2:   25    35  1 
#3:   20    80  1 
#4:   10    20  1 
#5:   10    20  1 
#6:   10    20  1 
2

es gibt eine Funktion untable im Paket Umformen um das Inverse einer Tabelle zu erhalten. Teilen Sie dann die Variablen, die durch count geteilt werden müssen, durch mutate_at (oder mutate_each). mutate_at wurde in dplyr_0.5.0 eingeführt.

Zuerst wird die untable:

library(reshape) 
untable(d, num = d$count) 

    count summed.value averaged.value 
1  2   50    35 
1.1  2   50    35 
2  1   20    80 
3  3   30    20 
3.1  3   30    20 
3.2  3   30    20 

Dann wird die mutate_at zum Dividieren summed.value und count durch count:

library(dplyr) 

untable(d, num = d$count) %>% 
    mutate_at(vars(summed.value, count), funs(./count)) 

    count summed.value averaged.value 
1  1   25    35 
2  1   25    35 
3  1   20    80 
4  1   10    20 
5  1   10    20 
6  1   10    20 
+0

Woher kommt 'mutate_at'? Es scheint nicht in "plyr" oder "dplyr" zu sein.Wissen Sie auch, warum 'untable' nicht in' reshape2' ist? – Warner

+0

'mutate_at' ist in der aktuellen Version von dplyr. Ich weiß nicht, warum 'untable' nicht umgestaltet wurde2. – aosmith

0

Eine Basis R Lösung: Es wird versucht, jede Zeile durch den Wert des count nachzubilden Spalte und dann teilen count und Spalten von count.

mytext <- 'count,summed.value,averaged.value 
2,50,35 
1,20,80 
3,30,20' 

mydf <- read.table(text=mytext,header=T,sep = ",") 

mydf <- do.call(rbind,apply(mydf, 1, function(x) { 
    tempdf <- t(replicate(x[1],x,simplify = T)) 
    tempdf[,1] <- tempdf[,1]/x[1] 
    tempdf[,2] <- tempdf[,2]/x[1] 
    return(data.frame(tempdf)) 
})) 

count summed.value averaged.value 
    1   25    35 
    1   25    35 
    1   20    80 
    1   10    20 
    1   10    20 
    1   10    20 
1

Hier ist ein einfacher und voll vecotrized Basis R Ansatz

transform(d[rep(1:nrow(d), d$count), ], 
      count = 1, 
      summed.value = summed.value/count) 
#  count summed.value averaged.value 
# 1  1   25    35 
# 1.1  1   25    35 
# 2  1   20    80 
# 3  1   10    20 
# 3.1  1   10    20 
# 3.2  1   10    20 

Oder ähnlich, mit data.table

library(data.table) 
res <- setDT(d)[rep(1:.N, count)][, `:=`(count = 1, summed.value = summed.value/count)] 
res 
# count summed.value averaged.value 
# 1:  1   25    35 
# 2:  1   25    35 
# 3:  1   20    80 
# 4:  1   10    20 
# 5:  1   10    20 
# 6:  1   10    20 
Verwandte Themen