【问题标题】:Quickly interpolate missing values in R plot在 R 图中快速插入缺失值
【发布时间】:2018-12-05 11:01:32
【问题描述】:

我想要一种有效的方法,将缺失值的数据框绘制为 R 中的线图,其原理如下;

  • 第一个和最后一个值中的 NA 被完全省略(没有线/点)
  • 实际值中的 NA 被替换为用于线图的中间值(不出现点)

这是我的数据框示例(已编辑

df <- data.frame("time" = c(1,2,3,4,5),
             "case1" = c(NA,2,3,4,NA),
             "case2" = c(5,4,3,2,NA),
             "case3" = c(4,NA,NA,NA,2))

这仅适用于第一种情况

library(pracma)
df$case1.i <- with(df, interp1(time, case1, time, 'linear'))
library(ggplot2)
ggplot(df, aes(time)) + geom_point(aes(case1 = case1)) + geom_line(aes(case1 = case1.i))

我正在努力解决一些问题,使其适用于我实际数据框中的大约 200 列。到目前为止,这段代码似乎不起作用

for (i in colnames(df)){
  argument <- paste("df$case",i,".i <- with(df, interp1(time, case",i,", time, 'linear'))")
  eval(parse(text=argument))
}

【问题讨论】:

  • 您希望将这些全部绘制在一个图中,还是为每个案例绘制一个单独的图?
  • 我想将它们绘制在一起。

标签: r dataframe ggplot2


【解决方案1】:

将数据读入一个新的动物园对象z,对其应用na.approx以填充数据主体内的NA值,然后使用ggplot2绘图。如果需要单独的面板,请忽略 facet = NULL。请注意,fortify.zoomelt = TRUE 将数据转换为带有 IndexSeriesValue 列的长格式,并在 geom_point 中使用。如果您只想要线条,请省略 geom_point(...) 部分。请参阅此答案末尾的图片。此处显示的方法相对紧凑,避免了粘贴在一起然后评估代码。

library(ggplot2)
library(zoo)

z <- read.zoo(df)
autoplot(na.approx(z), facet = NULL) + 
  geom_point(aes(Index, Value, group = Series), fortify(z, melt = TRUE))

或者如果你想为每列单独绘制一个图,试试这个:

pdf("civy.pdf")

for(i in 1:ncol(z)) {
  p <- autoplot(na.approx(z[, i])) + 
    ylab(names(z)[i]) +
    geom_point(aes(Index, Value), fortify(z[, i], melt = TRUE))
  plot(p)
}

dev.off()

【讨论】:

  • 太完美了。你知道我怎样才能绘制非 NA 点的点吗?以便有人能够区分哪里有真正的价值,哪些没有缺失。
【解决方案2】:

这里有两种解决方案:一种是将所有数据绘制在一起,按颜色区分;另一种是按不同方面的情况分别绘制它们。原理大致相同:我使用approx 进行线性插值,将数据从宽到长重新格式化,以便在ggplot2 中绘制,然后绘制它。在第二个解决方案中,我还创建了一个名为 type 的新变量来区分插值数据和原始数据。

一起绘制

# Create data frame
df <- data.frame("time" = c(1,2,3,4,5),
                 "case1" = c(NA,2,3,4,NA),
                 "case2" = c(1,2,3,4,NA),
                 "case3" = c(1,NA,NA,NA,5)) 

# Perform interpolation on all columns
# Switch from wide to long format
df %<>% 
  mutate_at(vars(contains("case")), funs(interp = approx(time, ., xout = time)$y)) %>% 
  gather(var, val, -time)

# Plot results all in one figure
g <- ggplot() 
g <- g + geom_point(data = df %>% filter(!grepl("interp", var)), aes(x = time, y = val, colour = var))
g <- g + geom_line(data = df %>% filter(grepl("interp", var)), aes(x = time, y = val, colour = var))
print(g)

单独绘制

# Create data frame
df <- data.frame("time" = c(1,2,3,4,5),
                 "case1" = c(NA,2,3,4,NA),
                 "case2" = c(1,2,3,4,NA),
                 "case3" = c(1,NA,NA,NA,5)) 

# Perform interpolation on all columns
# Switch from wide to long format
# Create column to indicate whether raw or interpolated
# Strip "_interp" from var
df %<>% 
  mutate_at(vars(contains("case")), funs(interp = approx(time, ., xout = time)$y)) %>% 
  gather(var, val, -time) %>% 
  mutate(type = ifelse(grepl("interp", var), "interp", "raw"),
         var = gsub("_.*", "", var))

# Plot results all separate figures
g <- ggplot() 
g <- g + geom_point(data = df %>% filter(type == "raw"), aes(x = time, y = val))
g <- g + geom_line(data = df %>% filter(type == "interp"), aes(x = time, y = val))
g <- g + facet_grid(var ~.)
print(g)


用新的数据框编辑

df <- data.frame("time" = c(1,2,3,4,5),
                 "case1" = c(NA,2,3,4,NA),
                 "case2" = c(5,4,3,2,NA),
                 "case3" = c(4,NA,NA,NA,2))

df %<>% 
  mutate_at(vars(contains("case")), funs(interp = approx(time, ., xout = time)$y)) %>% 
  gather(var, val, -time) %>% 
  mutate(type = ifelse(grepl("interp", var), "interp", "raw"),
         var = gsub("_.*", "", var))

g <- ggplot() 
g <- g + geom_point(data = df %>% filter(type == "raw"), aes(x = time, y = val, colour = var))
g <- g + geom_line(data = df %>% filter(type == "interp"), aes(x = time, y = val, colour = var))
print(g)

【讨论】:

  • 感谢您的回答,请花点时间根据我的新示例 df 进行编辑。我没有注意到绘制在一起时值重叠。
【解决方案3】:

尽管您在粘贴要评估的论点时出现了一些错误,但您走在正确的道路上,但在我脑海中的是:

  • 您应该使用paste0() 删除空格
  • 您正在遍历列名,但使用 i 作为数字
  • 我会循环遍历我只想插入的列而不是所有列

这是我上面提到的更改的代码:

cols_to_interpolate <- setdiff(colnames(df), 'time')

for (col in cols_to_interpolate){
  #print(col)
  argument <- paste0("df$", col,"_i <- with(df, interp1(time, ", col,", time , 'linear'))")
  #print(argument)
  eval(parse(text=argument))
}

p <- ggplot (df, aes(x = time))
for (col in cols_to_interpolate){
    p <- p + 
      geom_point(aes_string(y = col, color = shQuote(col)),  na.rm = TRUE) + 
      geom_line(aes_string(y = paste0(col,"_i"), color = shQuote(col)), na.rm = TRUE)
  }
p + ylab('Y Label') + xlab('X Label')

注意:我选择这种方法是因为它最接近您想要做的事情,但是我确信有很多更有效的方法可以获得最终结果。 (更少的 for 循环当然是加分项)

【讨论】:

  • 效果很好,但只绘制了案例 3​​。介意复习一下吗?
  • 当然!好了,希望对你有帮助
猜你喜欢
  • 2020-01-15
  • 2021-07-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-06
  • 1970-01-01
  • 2014-09-14
  • 2023-01-25
相关资源
最近更新 更多