2017-01-03 1 views
2

Frames:Spiel von id und dividieren Spaltenwerte über zwei Datenrahmen

df 1: mehrere Reihen von der gleichen ID enthält, mit 500 Spaltenwerte

id|val.1|val.2|...|val.500 
--------------------------------- 
    1 | 240 | 234 |...|228 
    1 | 224 | 222 |...|230 
    1 | 238 | 240 |...|240 
    2 | 277 | 270 |...|255 
    2 | 291 | 290 |...|265 
    2 | 284 | 282 |...|285 

df 2: enthält nur eine einzigartige ID (row), die DF-1-ID-Säule, die mit 500-Säule übereinstimmt Werte

id|val.1|val.2|...|val.500 
--------------------------------- 
    1 | 250 | 240 |...|245 
    2 | 280 | 282 |...|281 

I durch den entsprechenden Wert in Spalte 2 df basierend auf ihrer ID, um am Ende mit einem df 3 DF1 Spaltenwerten zu unterteilen würde:

id|val.1|val.2|...|val.500 
--------------------------------- 
    1 | 0.96| 0.98|...|0.93 
    1 | 0.90| 0.93|...|0.94 
    1 | 0.95| 1.00|...|0.98 
    2 | 0.99| 0.96|...|0.91 
    2 | 1.04| 1.03|...|0.94 
    2 | 1.01| 1.00|...|1.01 

Grundsätzlich gewichten df 1 Werte von DF 2 basierend auf ihrer ID und Spalte Wert. Ich habe mir schon seit einiger Zeit den Kopf über den besten Weg gekratzt und mache keine großen Fortschritte. jede Anleitung würde sehr geschätzt werden. Danke

Antwort

2

Zwei mögliche Ansätze:

1: ‚wide'-Ansatz

Mit den dplyr und purrr Pakete:

library(dplyr) 
library(purrr) 

df12 <- left_join(df1, df2, by = 'id') 
cbind(id=df12[,1], map2_df(df12[,2:4], df12[,5:7], `/`)) 

Mit dem data.table Paket (Methode von here entlehnt):

library(data.table) 

# convert to 'data.tables' 
setDT(df1) 
setDT(df2) 

# creates two vectors of matching columnnames 
xcols = names(df1)[-1] 
icols = paste0("i.", xcols) 

# join and do the calculation 
df1[df2, on = 'id', Map('/', mget(xcols), mget(icols)), by = .EACHI] 

, die beide geben:

id  val.1  val.2  val.3 
1: 1 0.9600000 0.9750000 0.9306122 
2: 1 0.8960000 0.9250000 0.9387755 
3: 1 0.9520000 1.0000000 0.9795918 
4: 2 0.9892857 0.9574468 0.9074733 
5: 2 1.0392857 1.0283688 0.9430605 
6: 2 1.0142857 1.0000000 1.0142349 

2: ‚long'-Ansatz

Eine weitere Option neu zu gestalten ist Ihr Datenrahmen in langes Format, dann merge/join sie und tun die Berechnung.

Mit dem data.table -package:

library(data.table) 

dt1 <- melt(setDT(df1), id = 1) 
dt2 <- melt(setDT(df2), id = 1) 

dt1[dt2, on = c('id','variable'), value := value/i.value][] 

Mit den dplyr und tidyr Pakete:

library(dplyr) 
library(tidyr) 

df1 %>% 
    gather(variable, value, -id) %>% 
    left_join(., df2 %>% gather(variable, value, -id), by = c('id','variable')) %>% 
    mutate(value = value.x/value.y) %>% 
    select(id, variable, value) 

, die beide geben:

id variable  value 
1: 1 val.1 0.9600000 
2: 1 val.1 0.8960000 
3: 1 val.1 0.9520000 
4: 2 val.1 0.9892857 
5: 2 val.1 1.0392857 
6: 2 val.1 1.0142857 
7: 1 val.2 0.9750000 
8: 1 val.2 0.9250000 
9: 1 val.2 1.0000000 
10: 2 val.2 0.9574468 
11: 2 val.2 1.0283688 
12: 2 val.2 1.0000000 
13: 1 val.3 0.9306122 
14: 1 val.3 0.9387755 
15: 1 val.3 0.9795918 
16: 2 val.3 0.9074733 
17: 2 val.3 0.9430605 
18: 2 val.3 1.0142349 

uns Ed-Daten:

df1 <- structure(list(id = c(1, 1, 1, 2, 2, 2), val.1 = c(240, 224, 238, 277, 291, 284), 
         val.2 = c(234, 222, 240, 270, 290, 282), val.3 = c(228, 230, 240, 255, 265, 285)), 
       .Names = c("id", "val.1", "val.2", "val.3"), class = "data.frame", row.names = c(NA, -6L)) 

df2 <- structure(list(id = c(1, 2), val.1 = c(250, 280), val.2 = c(240, 282), val.3 = c(245, 281)), 
       .Names = c("id", "val.1", "val.2", "val.3"), class = "data.frame", row.names = c(NA, -2L)) 
+1

Große Ansätze. Pluse one – akrun

+0

Danke Maximus! Ich benutzte das data.table-Format, da ich dem Code (kaum) folgen konnte. All seriousness, wie ziehe ich meine Programmierkenntnisse inkrementell auf 50% von Ihnen? –

+0

@AnandRoopsind thx :-) Einfach so weitermachen auf SO: lies den Code der guten Antworten (starte mit der Frage des [r-faq Tags] (http://stackoverflow.com/questions/tagged/r+) r-faq)). Versuche, Fragen zu lösen: Am Anfang mag das frustrierend sein, aber du wirst besser darin werden. Siehe auch die [Info-Seite des R-Tags] (http://stackoverflow.com/tags/r/info), auf der viele tolle Ressourcen aufgelistet sind. In Bezug auf "data.table" speziell, siehe [Erste Schritte Wiki auf GitHub] (https://github.com/Rdatatable/data.table/wiki/Getting-started) – Jaap

0

Solange die data.frames ordnungsgemäß nach Spalte geordnet sind und beide die gleichen Spalten haben, dann denke ich, dass der folgende Basis-R-Code erreichen wird, was Sie wollen.

cbind(df1[1], df1[-1]/df2[match(df1$id, df2$id), -1]) 

    id  val.1  val.2 val.500 
1 1 0.9600000 0.9750000 0.9306122 
2 1 0.8960000 0.9250000 0.9387755 
3 1 0.9520000 1.0000000 0.9795918 
4 2 0.9892857 0.9574468 0.9074733 
5 2 1.0392857 1.0283688 0.9430605 
6 2 1.0142857 1.0000000 1.0142349 

Hier match(df1$id, df2$id) werden die Zeilenindizes von df1 zurückzugeben, die an die IDs von DF2 entsprechen, so df2[match(df1$id, df2$id), -1] werden die entsprechenden Reihen von DF2 als data.frame mit der ID variabler entfernt zurückzukehren. Dieser data.frame passt dann df1 in Form an, wenn die ID-Variable entfernt wird und df1[-1]/df2[match(df1$id, df2$id), -1] die Division ausführt. Schließlich fügt cbind die ID-Variable dem finalen data.frame voran.

Daten

df1 <- structure(list(id = c(1L, 1L, 1L, 2L, 2L, 2L), val.1 = c(240L, 
224L, 238L, 277L, 291L, 284L), val.2 = c(234L, 222L, 240L, 270L, 
290L, 282L), val.500 = c(228L, 230L, 240L, 255L, 265L, 285L)), .Names = c("id", 
"val.1", "val.2", "val.500"), class = "data.frame", row.names = c(NA, 
-6L)) 

df2 <- structure(list(id = 1:2, val.1 = c(250L, 280L), val.2 = c(240L, 
282L), val.500 = c(245L, 281L)), .Names = c("id", "val.1", "val.2", 
"val.500"), class = "data.frame", row.names = c(NA, -2L)) 
Verwandte Themen