收集对三个不同变量的3种不同检测结果

时间:2019-09-26 07:43:08

标签: r tidyr

我的数据框为96074 obs。 31个变量。 前两个变量是id和date,然后我有9列要测量的值(三种具有不同时间属性的KPI),然后是各种技术和地理变量。

df <- data.frame(
  id = rep(1:3, 3),
  time = rep(as.Date('2009-01-01') + 0:2, each = 3),
  sum_d_1day_old = rnorm(9, 2, 1),
  sum_i_1day_old = rnorm(9, 2, 1),
  per_i_d_1day_old = rnorm(9, 0, 1),
  sum_d_5days_old = rnorm(9, 0, 1),
  sum_i_5days_old = rnorm(9, 0, 1),
  per_i_d_5days_old = rnorm(9, 0, 1),
  sum_d_15days_old = rnorm(9, 0, 1),
  sum_i_15days_old = rnorm(9, 0, 1),
  per_i_d_15days_old = rnorm(9, 0, 1)
) 

我想从宽到长转换,例如使用facet用ggplot绘制图形。 如果我的df进行了三次扫描,只有一个变量,那么在使用collect时将没有问题:

plotdf <- df %>% 
          gather(sum_d, value, 
                 c(sum_d_1day_old, sum_d_5days_old, sum_d_15days_old), 
                   factor_key = TRUE)

但是拥有三个不同的变量会让我震惊。 我想要这个输出:

plotdf <- data.frame(
  id = rep(1:3, 3),
  time = rep(as.Date('2009-01-01') + 0:2, each = 3),
  sum_d = rep(c("sum_d_1day_old", "sum_d_5days_old", "sum_d_15days_old"), 3),
  values_sum_d = rnorm(9, 2, 1),
  sum_i = rep(c("sum_i_1day_old", "sum_i_5days_old", "sum_i_15days_old"), 3),
  values_sum_i = rnorm(9, 2, 1),
  per_i_d = rep(c("per_i_d_1day_old", "per_i_d_5days_old", "per_i_d_15days_old"), 3),
  values_per_i_d = rnorm(9, 2, 1)
)

带有日期类的类因子时间的idsum_dsum_iper_i_d和数值类的值(我必须补充一点,我没有在这些变量中使用负度量。

我尝试做的事情:

plotdf <- gather(df, key, value, sum_d_1day_old:per_i_d_15days_old, factor_key = TRUE)

在一个列中收集所有变量

plotdf$KPI <- paste(sapply(strsplit(as.character(plotdf$key), "_"), "[[", 1),
      sapply(strsplit(as.character(plotdf$key), "_"), "[[", 2), sep = "_")

使用KPI名称创建一个新列,但不指定时间

plotdf %>% unite(value2, key, value) %>%
#creating a new variable with the full name of the KPI attaching the value at the end
mutate(i = row_number()) %>% spread(KPI, value2) %>% select(-i)
#spreading

但是传播会产生带有NA的行。 首先我要替换掉

group_by(id, date) %>% 
  fill(c(sum_d, sum_i, per_i_d), .direction = "down") %>%
  fill(c(sum_d, sum_i, per_i_d), .direction = "up") %>%

但是问题在于,原始df中已经有一些测量值包含变量per_i_d(总共44个)中的NA,因此我丢失了该信息。

我认为我可以用一个虚拟值替换原始df中的NA,然后再替换回NA,但后来我认为可以为所有问题提供一个更有效的解决方案。

替换了NA之后,我的想法是使用slice(1)仅选择每个对ID /日期的第一行,然后对单独的/统一的进行一些操作以获得所需的输出。 我实际上是这样做的,但是后来我想起了我在原始df中有上述NA。

1 个答案:

答案 0 :(得分:0)

df %>%
  gather(key,value,-id,-time) %>%
  mutate(type = str_extract(key,'[a-z]+_[a-z]'),
         age = str_extract(key, '[0-9]+[a-z]+_[a-z]+')) %>%
  select(-key) %>%
  spread(type,value)

给予

   id       time        age      per_i      sum_d        sum_i
1   1 2009-01-01 15days_old  0.8132301  0.8888928  0.077532040
2   1 2009-01-01   1day_old -2.0993199  2.8817133  3.047894196
3   1 2009-01-01  5days_old -0.4626151 -1.0002926  0.327102000
4   1 2009-01-02 15days_old  0.4089618 -1.6868523  0.866412133
5   1 2009-01-02   1day_old  0.8181313  3.7118065  3.701018419
...

编辑:

将非值列添加到数据框:

df %>%
  gather(key,value,-id,-time) %>%
  mutate(type = str_extract(key,'[a-z]+_[a-z]'),
         age = str_extract(key, '[0-9]+[a-z]+_[a-z]+'),
         info = paste(age,type,sep = "_")) %>%
  select(-key) %>%
  gather(key,value,-id,-time,-age,-type) %>%
  unite(dummy,type,key) %>%
  spread(dummy,value)