Как рассчитать соотношение двух фреймов данных с неравномерно распределенными значениями в R? - PullRequest
0 голосов
/ 15 мая 2019

У меня есть два набора данных, в которых в нескольких временных точках измеряется определенное значение. Я хотел бы визуализировать соотношение между двумя наборами данных с помощью линейного графика. Однако временные точки измерений не полностью перекрываются, и некоторые эксперименты содержат больше значений, чем другие.

Данные

df_1 <- as.data.frame(cbind(c(1,2,3,4,5,6,7,8,9,10), c(1,4,7,8,9.5,17,41,27, 26, 10)))
df_2 <- as.data.frame(cbind(c(0.1, 0.5, 2, 3, 4.4,5.3,6,7,8,10,12,15,16,20), c(0.1,2,4,6,7.5,6.3,9,19,22,23,24,51,31,23)))

Графики

library(tidyverse)

ggplot()+
   geom_line(data = df_1, aes(x=V1, y=V2), col = "black") + 
   geom_line(data = df_2, aes(x=V1, y=V2), col = "red")

Далее я хотел бы построить соотношение между двумя кривыми. Однако, поскольку измеренные точки данных не распределены равномерно (и измерены в несколько разное время), я не могу просто разделить значение для каждой временной точки и отобразить результат.

Вопрос

Как вы рассчитываете соотношение между двумя неравномерно расположенными фреймами данных (которые могут быть разной длины) в R?

Дополнительный пример

У меня есть два (пример) набора данных. Третий набор данных - это ожидаемый результат (df_3). Зеленая линия представляет ожидаемый результат: соотношение между df_2 / df_1.

df_1 <- as.data.frame(cbind(time = c(1:5), value = c(1:5)))
df_2 <- as.data.frame(cbind(time = c(1.5, 2, 3,4), value = c(2,2,2.5,3.5)))
df_3 <- as.data.frame(cbind(time = c(1.5, 2, 3,4), value = c(1.33, 1, 0.83, 0.875)))

ggplot() + 
  geom_point(data = df_1, aes(x=time, y=value), col = "black", size = 3) + 
  geom_point(data = df_2, aes(x=time, y=value), col = "red", size =3) +
  geom_line(data = df_1, aes(x=time, y = value), col = "black") + 
  geom_line(data = df_2, aes(x = time, y = value), col = "red") + 
  geom_point(data =df_3, aes(x = time, y = value), col = "green", size = 3) +
  geom_line(data=df_3, aes(x=time, y = value), col = "green")

1 Ответ

1 голос
/ 15 мая 2019

Вы можете сделать полное соединение, используя пакет dplyr.Обратите внимание, что фреймы данных, которые я использую, такие же, как у вас, но столбцы имеют имена time и value.

Линейная интерполяция в соотношении

df_1 <- as.data.frame(cbind(time = c(1,2,3,4,5,6,7,8,9,10), value = c(1,4,7,8,9.5,17,41,27, 26, 10)))
df_2 <- as.data.frame(cbind(time = c(0.1, 0.5,2,3,4.4,5.3,6,7,8,10,12,15,16,20), value = c(0.1,2,4,6,7.5,6.3,9,19,22,23,24,51,31,23)))

library(dplyr)
df_1 %>% full_join(df_2, by = "time", suffix = c("_1", "_2")) %>%
  arrange(time) %>% 
  mutate(ratio = value_1/value_2,
         ratio = approx(time, ratio, xout = time, rule = 2:2)$y)

   time value_1 value_2     ratio
1   0.1      NA     0.1 1.0000000
2   0.5      NA     2.0 1.0000000
3   1.0     1.0      NA 1.0000000
4   2.0     4.0     4.0 1.0000000
5   3.0     7.0     6.0 1.1666667
6   4.0     8.0      NA 1.4074074
7   4.4      NA     7.5 1.5037037
8   5.0     9.5      NA 1.6481481
9   5.3      NA     6.3 1.7203704
10  6.0    17.0     9.0 1.8888889
11  7.0    41.0    19.0 2.1578947
12  8.0    27.0    22.0 1.2272727
13  9.0    26.0      NA 0.8310277
14 10.0    10.0    23.0 0.4347826
15 12.0      NA    24.0 0.4347826
16 15.0      NA    51.0 0.4347826
17 16.0      NA    31.0 0.4347826
18 20.0      NA    23.0 0.4347826

Линейная интерполяция значения_1 по df_2

# Interpolated dataframe 1
# Interpolation ensures that for every time point in df_2, a value_1 is calculated. 
# Next, the ratio of value_2 / value_1 is calculated. 

int_df_1 <- as.data.frame(approx(df_1$time, df_1$value, xout = df_2$time, rule = 1:1))
names(int_df_1) <- c("time", "value")

# Again full join + division of df_2 by interpolated df_1

int_df_1 %>% 
   full_join(df_2, by = "time", suffix = c("_1", "_2")) %>%
   arrange(time) %>% 
   mutate(ratio = value_2/value_1)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...