2017-01-03 2 views
2

кадров:матче ID и разделить значения столбцов между двумя dataframes

DF 1: содержит несколько строк одного и того же идентификатора с 500 столбца значений

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: содержит только один уникальный идентификатор (строка), что соответствует DF-1 идентификатор столбца с 500 значениями столбца

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

Я хотел бы разделить DF 1 значений столбца по соответствующему значению столбца в DF 2 на основе их идентификатора, чтобы в конечном итоге с DF 3:

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 

В основном взвешивание значений df 1 по df 2 в зависимости от их значения id и столбца. Некоторое время я немного почесывал себе голову о лучшем способе этого, и не добился большого прогресса. любое руководство будет с благодарностью оценено. Спасибо

ответ

2

два возможных подхода:

1: «wide'-подход

С пакетами dplyr и purrr:

library(dplyr) 
library(purrr) 

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

С data.table пакета (метод заимствованные из here):

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] 

, которые оба дают:

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'-подход

Другой вариант, чтобы изменить ваш dataframes в длинный формат, затем merge/join их и выполните расчет.

С 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][] 

С пакетами dplyr и tidyr:

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) 

, которые оба дают:

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 

Us ed data:

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

Великие подходы. Плюз один – akrun

+0

Спасибо Maximus! Я использовал формат data.table, поскольку я мог следовать коду (едва). Вся серьезность, как я могу увеличить свои навыки кодирования до 50% от вашего? –

+0

@AnandRoopsind thx :-) Просто продолжайте участвовать в SO: прочитайте и запустите код хороших ответов (начните с вопроса о теге [r-faq] (http://stackoverflow.com/questions/tagged/r+ г-задаваемые вопросы)). Попытайтесь решить вопросы: в начале это может расстраивать, но вы поправитесь. Также см. [Info-page R-tag] (http://stackoverflow.com/tags/r/info), на котором перечислены многие большие ресурсы. Что касается 'data.table' в частности, см. [Начало работы wiki на GitHub] (https://github.com/Rdatatable/data.table/wiki/Getting-started) – Jaap

0

Пока кадры data.frames упорядочены по столбцу, и оба имеют одинаковые столбцы, тогда я думаю, что следующий базовый код R выполнит то, что вы хотите.

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 

Здесь match(df1$id, df2$id) будет возвращать индексы ряда df1, которые соответствуют идентификаторам из df2, поэтому df2[match(df1$id, df2$id), -1] будет возвращать соответствующие строки df2 как data.frame с переменным идентификатором удален. Затем этот data.frame соответствует df1 в форме, когда переменная id удаляется, а df1[-1]/df2[match(df1$id, df2$id), -1] выполняет деление. Наконец cbind добавляет переменную id к окончательному кадру данных.

данные

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))