【问题标题】:Plot time series with known error (ggplot2)绘制具有已知误差的时间序列 (ggplot2)
【发布时间】:2019-05-26 13:47:27
【问题描述】:

我正在与美国社区调查 (ACS) 合作,对特定位置的 1 年估计数进行了数年。例如,我试图绘制男性和女性骑自行车上班的比例如何随时间变化。从 ACS 中,我得到估计值和标准误差,然后我可以使用它们来计算估计值的上限和下限。

所以宽格式的简化数据结构是这样的:

| Year | EstimateM | MaxM | MinM | EstimateF | MaxF | MinF |
|------|-----------|------|------|-----------|------|------|
| 2005 | 3.0       | 3.5  | 2.5  | 2.0       | 2.3  | 1.7  |
| 2006 | 3.1       | 3.5  | 2.6  | 2.0       | 2.3  | 1.7  |
| 2007 | 5.0       | 4.2  | 5.8  | 2.5       | 3.0  | 2.0  |
| ...  | ...       | ...  | ...  | ...       | ...  | ...  |

如果我只想绘制估计值,我会 melt 将只有两个 Estimate 变量的数据设为 measure.vars

GenderModeCombined_long <- melt(GenderModeCombined,
                            id = "Year",
                            measure.vars = c("EstimateM",
                                             "EstimateF")

然后可以使用ggplot2 轻松绘制长数据

ggplot(data=GenderModeCombined_long,
  aes(x=year, y=value, colour=variable)) +
  geom_point() +
  geom_line()

这会产生一个像这样的图表

(抱歉,没有足够的代表来发布图片)

我遇到的困难是如何在两个估计图中添加误差线。我可以将它们作为measure vars 添加到融化的数据集中,但是我如何告诉ggplot 应该将什么绘制为值以及什么作为误差线?我是否必须只使用最小/最大数据创建一个单独的数据框,然后单独加载?

geom_errorbar(data = errordataMmax, aes(ymax = ??, ymin = ??)) 

我感觉我以错误的方式处理这个问题和/或我的数据设置错误。

【问题讨论】:

  • 如果你可以让这个问题可重现,你更有可能得到一个有用的答案..

标签: r dataframe ggplot2 time-series errorbar


【解决方案1】:

欢迎来到 SO。这里的问题是你有三个“显式”变量(估计, 最小和最大)和一个“隐式”(性别),它被编码在列名中。解决这个问题的一种方法是使“性别”成为一个明确的分组变量。转到长格式后,创建一个“性别”变量,从键列(变量)中删除性别指示,然后返回宽格式。 这样的事情会起作用:

library(ggplot2)
library(dplyr)
library(tidyr)
library(tibble)

GenderModeCombined <- tibble::tribble(
  ~Year,   ~EstimateM,   ~MaxM,   ~MinM,   ~EstimateF,   ~MaxF,   ~MinF,  
  2005,         3.0,    3.5,    2.5,         2.0,    2.3,    1.7,  
  2006,         3.1,    3.5,    2.6,         2.0,    2.3,    1.7,  
  2007,         5.0,    4.2,    5.8,         2.5,    3.0,    2.0
)

GenderModeCombined.long <- GenderModeCombined %>% 
  # switch to long format
  tidyr::gather(variable, value, -Year,  factor_key = TRUE) %>% 
  # add a gender variable
  dplyr::mutate(gender   = stringr::str_sub(variable, -1)) %>% 
  # remove gender indication from the key column `variable`
  dplyr::mutate(variable = stringr::str_sub(variable, end = -2)) %>%
  # back to wide format
  tidyr::spread(variable, value)

GenderModeCombined.long
#> # A tibble: 6 x 5
#>    Year gender Estimate   Max   Min
#>   <dbl> <chr>     <dbl> <dbl> <dbl>
#> 1  2005 F           2     2.3   1.7
#> 2  2005 M           3     3.5   2.5
#> 3  2006 F           2     2.3   1.7
#> 4  2006 M           3.1   3.5   2.6
#> 5  2007 F           2.5   3     2  
#> 6  2007 M           5     4.2   5.8

ggplot(data=GenderModeCombined.long,
       aes(x=Year, y=Estimate,colour = gender)) +
  geom_point() +
  geom_line() + 
  geom_errorbar(aes(ymax = Max, ymin = Min))  

reprex package (v0.2.1) 于 2018 年 12 月 29 日创建

【讨论】:

  • 图表中缺少线条,因为Year 是字符类型,ggplot2 将其视为离散变量。是否有特定原因将所有数字数据作为类型字符传递给tibble::tribble()
  • 完全没有理由。只是剪切和粘贴懒惰......我修改了答案。谢谢。
  • 谢谢!所以这个块确实在数据结构中——我只是想不通如何修复它。非常感谢!
【解决方案2】:

正如lbusett 所解释的那样,这个问题的答案不是关于绘图,而是关于将数据从宽格式重塑为长格式。这里的挑战是每个性别都有多个值列,即EstimateMaxMin

从 v1.9.6 版开始(CRAN 2015 年 9 月 19 日),melt() 函数的化身允许一次性融合,即从宽格式到长格式重塑为多个列:

library(data.table)
options(datatable.print.class = TRUE)
cols <- c("Estimate", "Max", "Min")
long <- melt(setDT(GenderModeCombined), id.vars = "Year", measure.vars = patterns(cols), 
             value.name = cols, variable.name = "Gender")[
               , Gender := forcats::lvls_revalue(Gender, c("M", "F"))][]
long
    Year Gender Estimate   Max   Min
   <int> <fctr>    <num> <num> <num>
1:  2005      M      3.0   3.5   2.5
2:  2006      M      3.1   3.5   2.6
3:  2007      M      5.0   4.2   5.8
4:  2005      F      2.0   2.3   1.7
5:  2006      F      2.0   2.3   1.7
6:  2007      F      2.5   3.0   2.0

现在,每个YearGender 都有三个观察值,可以根据需要绘制:

library(ggplot2)
ggplot(long, aes(x = Year, y = Estimate, colour = Gender)) +
  geom_point() +
  geom_line() +
  geom_errorbar(aes(ymax = Max, ymin = Min), width = 0.1)

请注意,除了点和误差线之外,此图表还显示线。这是因为 Yearinteger 类型,ggplot2 将其识别为连续变量。

数据

fread() 函数非常方便读取各种数据格式。因此,我们只需稍作修改即可读取 OP 发布的数据:

library(data.table)
GenderModeCombined <- fread(
"| Year | EstimateM | MaxM | MinM | EstimateF | MaxF | MinF |
| 2005 | 3.0       | 3.5  | 2.5  | 2.0       | 2.3  | 1.7  |
| 2006 | 3.1       | 3.5  | 2.6  | 2.0       | 2.3  | 1.7  |
| 2007 | 5.0       | 4.2  | 5.8  | 2.5       | 3.0  | 2.0  |
", drop = c(1L, 9L))

GenderModeCombined
    Year EstimateM  MaxM  MinM EstimateF  MaxF  MinF
   <int>     <num> <num> <num>     <num> <num> <num>
1:  2005       3.0   3.5   2.5       2.0   2.3   1.7
2:  2006       3.1   3.5   2.6       2.0   2.3   1.7
3:  2007       5.0   4.2   5.8       2.5   3.0   2.0

【讨论】:

  • 谢谢。这个解决方案也适用于我。 @lbusett 的 tidyverse 代码对我来说更容易阅读,但很高兴知道它也可以使用 melt 完成
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-07-05
  • 2017-03-04
  • 2021-03-17
  • 1970-01-01
  • 2018-01-24
  • 2012-10-26
  • 2013-01-30
相关资源
最近更新 更多