【问题标题】:R - Efficiently reshape time series variable columns into time series rows with columns as variables [duplicate]R - 有效地将时间序列变量列重塑为以列作为变量的时间序列行[重复]
【发布时间】:2017-08-22 20:51:31
【问题描述】:

我想这不一定是严格的时间序列数据,但我看不出还有什么方法可以解决这个问题......

我有一个数据表,其中行作为唯一的 XY 位置和 ID、X 和 Y 列,然后是几个气候变量的 12 个月列:

  • 1-12 个月的平均温度 (Tmean),命名为 Tmean01、Tmean02 ... Tmean12。
  • 1-12 个月的最高温度 (Tmax),命名为 Tmax01、Tmaxe02 ... Tmax12。
  • 1-12 个月的最低温度 (Tmax),命名为 Tmax01、Tmaxe02 ... Tmax12。

数据如下:

  ID   lat   long Tave01 Tave02 Tave03 Tave04 Tave05 Tave06 Tave07 Tave08 Tave09 Tave10 Tave11 Tave12 Tmax01 Tmax02 Tmax03 Tmax04 Tmax05 Tmax06 Tmax07 Tmax08 Tmax09 Tmax10 Tmax11 Tmax12 Tmin01 Tmin02 Tmin03 Tmin04 Tmin05 Tmin06 Tmin07 Tmin08 Tmin09 Tmin10 Tmin11 Tmin12
F102  51.5 -116.3  -12.8   -9.2   -4.6   -0.9    4.1    5.8    9.5    8.1    3.2   -1.1   -7.4  -12.0   -8.0   -2.8    0.4    5.2   10.5    9.9   15.0   14.3    8.1    2.5   -4.8   -7.6  -17.5  -15.6   -9.5   -6.9   -2.2    1.7    3.9    1.9   -1.7   -4.7  -10.0  -16.4
F103  51.5 -116.2  -13.0   -9.5   -4.9   -1.2    4.0    5.7    9.4    8.0    3.1   -1.1   -7.6  -12.3   -7.9   -2.9    0.2    5.0   10.3    9.8   15.0   14.3    8.1    2.7   -4.6   -7.6  -18.1  -16.1  -10.0   -7.3   -2.4    1.7    3.7    1.7   -1.9   -5.0  -10.6  -17.0
F105  51.5 -116.1  -13.7  -10.8   -6.5   -3.5    1.8    4.2    7.6    6.1    1.5   -2.7   -9.1  -13.5   -8.7   -4.7   -1.8    2.2    7.6    7.1   12.2   11.5    5.7    1.1   -6.9   -9.1  -18.8  -17.0  -11.2   -9.2   -3.9    1.2    2.9    0.7   -2.7   -6.5  -11.3  -18.0
F106  51.5 -116.0  -13.7  -10.8   -6.4   -3.3    1.8    4.2    7.7    6.2    1.7   -2.5   -9.0  -13.4   -8.5   -4.7   -1.9    2.6    7.8    7.3   12.5   11.9    6.0    1.7   -6.8   -8.9  -18.8  -16.9  -11.0   -9.3   -4.3    1.1    2.9    0.6   -2.7   -6.6  -11.2  -17.9
F116  51.5 -115.3  -11.3   -7.8   -2.8    1.2    5.9    7.6   11.6   10.1    5.4    2.4   -3.9  -10.2   -5.7   -0.7    2.4    8.4   13.4   12.7   18.3   17.3   11.4    9.0    0.8   -5.1  -17.0  -15.0   -8.1   -5.9   -1.5    2.4    4.9    2.9   -0.7   -4.2   -8.7  -15.3
F117  51.5 -115.2  -11.2   -7.7   -2.6    1.4    6.2    7.8   11.8   10.3    5.6    2.6   -3.7  -10.1   -5.6   -0.5    2.8    8.6   13.6   13.0   18.6   17.5   11.7    9.2    1.2   -4.9  -16.9  -14.9   -8.0   -5.8   -1.3    2.6    5.0    3.1   -0.5   -4.1   -8.6  -15.2
F118  51.5 -115.1  -11.1   -7.4   -2.4    1.6    6.4    8.1   12.0   10.6    5.9    2.7   -3.4   -9.9   -5.4   -0.1    3.2    8.9   13.9   13.3   18.9   17.7   11.9    9.4    1.8   -4.7  -16.8  -14.7   -8.0   -5.6   -1.0    2.8    5.2    3.6   -0.1   -3.9   -8.6  -15.0
F119  51.5 -115.0  -10.9   -7.2   -2.2    1.9    6.7    8.4   12.3   10.9    6.2    3.0   -2.9   -9.6   -5.2    0.3    3.6    9.3   14.2   13.7   19.3   18.1   12.3    9.7    2.6   -4.3  -16.7  -14.6   -8.0   -5.4   -0.8    3.0    5.4    3.8    0.1   -3.8   -8.4  -14.8
F120  51.5 -114.9  -10.6   -6.6   -1.7    2.4    7.0    8.6   12.6   11.0    6.3    3.3   -2.5   -9.0   -4.7    1.1    4.4    9.8   14.7   14.2   19.8   18.5   12.9   10.1    3.1   -3.4  -16.5  -14.3   -7.9   -5.0   -0.8    3.1    5.3    3.4   -0.2   -3.5   -8.2  -14.5
F121  51.5 -114.8  -10.3   -6.2   -1.3    2.7    7.2    8.9   12.7   11.2    6.5    3.5   -2.3   -8.5   -4.2    1.7    5.1   10.2   15.1   14.7   20.3   18.9   13.3   10.4    3.3   -2.8  -16.3  -14.0   -7.7   -4.7   -0.7    3.1    5.2    3.4   -0.4   -3.4   -7.8  -14.2
...

我想要的是一个时间序列布局,其中每一行代表每个离散 ID 的每月条目,变量(Tmean、Tmin、Tmax)作为列。所以我最终会为每个唯一 ID 提供 12 行。像这样的...

  ID Month  Tave Tmax  Tmin
F102     1 -12.8 -8.0 -17.5
F102     2  -9.2 -2.8 -15.6
F102     3  -4.6  0.4  -9.5
F102     4   4.1  5.2  -6.9
...
F102    12 -12.0 -7.6 -16.4
F103     1 -13.0 -7.9 -17.5
F103     2  -9.5 -2.9 -16.1
...

每个站点和每个月等等。

我可以通过循环或其他方式通过所有变量强制执行此操作并填充 expand.grid 表或其他内容,但必须有一个更优雅(即更快更容易)的解决方案。

我查看了 reshape 包,但似乎无法找到我需要的东西。

【问题讨论】:

标签: r time-series reshape


【解决方案1】:

这是一个data.table 解决方案。绝对不是最干净的解决方案。我只是喜欢这个问题的挑战......并且只是玩弄直到我做对了:

# Set to data.table
setDT(df)

# Melt to long form
dfl <- melt(df, id.vars = c("ID", "lat","long"))
dfl
       ID  lat   long variable value
  1: F102 51.5 -116.3   Tave01 -12.8
  2: F103 51.5 -116.2   Tave01 -13.0
  3: F105 51.5 -116.1   Tave01 -13.7
  4: F106 51.5 -116.0   Tave01 -13.7
  5: F116 51.5 -115.3   Tave01 -11.3
 ---                                
356: F117 51.5 -115.2   Tmin12 -15.2
357: F118 51.5 -115.1   Tmin12 -15.0
358: F119 51.5 -115.0   Tmin12 -14.8
359: F120 51.5 -114.9   Tmin12 -14.5
360: F121 51.5 -114.8   Tmin12 -14.2

# Add new variables, month and variable type using regex
dfl[, Month := gsub(".+([0-9]{2})$", "\\1", variable)]
dfl[, var_type := gsub("(.{4}).+$", "\\1", variable)]

# Take to final form
dfw <- reshape(dfl, idvar = c("ID", "lat","long", "Month"), timevar = "var_type", direction = "wide")

# Get rid of extra columns that are not needed anymore
dfw[, grep("variable\\.", names(dfw), value = TRUE) := NULL]
dfw[, c("lat", "long") := NULL]

# Cleaning the names a bit
names(dfw) <- gsub("value\\.", "", names(dfw)) 

# Print final product
dfw
       ID Month  Tave Tmax  Tmin
  1: F102    01 -12.8 -8.0 -17.5
  2: F103    01 -13.0 -7.9 -18.1
  3: F105    01 -13.7 -8.7 -18.8
  4: F106    01 -13.7 -8.5 -18.8
  5: F116    01 -11.3 -5.7 -17.0
 ---                            
116: F117    12 -10.1 -4.9 -15.2
117: F118    12  -9.9 -4.7 -15.0
118: F119    12  -9.6 -4.3 -14.8
119: F120    12  -9.0 -3.4 -14.5
120: F121    12  -8.5 -2.8 -14.2

编辑

根据 cmets 中提供的链接,我想出了另一个更短的版本来完成这项工作:

dfw <- reshape(df, idvar="ID", direction="long", 
               varying=list(ave=4:15, max=16:27, min=28:39),
               v.names = c("Tave", "Tmax", "Tmin"))
setnames(dfw, "time", "Month")
dfw[, c("lat", "long") := NULL]

【讨论】:

  • 感谢 snoram:按照您的描述工作。这是关于我开始做这一切的地方。我标记为答案,尽管 Henrik 在上面链接到的使用 reshape 的解决方案将编码降至最低!
  • 它绝对比循环更快更容易,但我很高兴有一个更短的解决方案,我会看看链接。
  • 根据链接更新了 much 更短的版本。我怀疑 R 中是否存在更快、更短的版本。
【解决方案2】:

使用dplyrtidyr 的解决方案。我们可以使用gather 将数据帧转换为长格式。使用separate 将列分隔为MeasureMonth。请注意,sep 参数可以指定分隔列的位置。 convert 可以确定我们是否要尽可能将列转换为数字。最后,使用 spread 将其转换为所需的输出 (dt2)。

library(dplyr)
library(tidyr)

dt2 <- dt %>%
  select(-lat, -long) %>%
  gather(Type, Value, -ID) %>%
  separate(Type, into = c("Measure", "Month"), sep = 4, convert = TRUE) %>%
  spread(Measure, Value)

数据:

dt <- read.table(text = "ID   lat   long Tave01 Tave02 Tave03 Tave04 Tave05 Tave06 Tave07 Tave08 Tave09 Tave10 Tave11 Tave12 Tmax01 Tmax02 Tmax03 Tmax04 Tmax05 Tmax06 Tmax07 Tmax08 Tmax09 Tmax10 Tmax11 Tmax12 Tmin01 Tmin02 Tmin03 Tmin04 Tmin05 Tmin06 Tmin07 Tmin08 Tmin09 Tmin10 Tmin11 Tmin12
F102  51.5 -116.3  -12.8   -9.2   -4.6   -0.9    4.1    5.8    9.5    8.1    3.2   -1.1   -7.4  -12.0   -8.0   -2.8    0.4    5.2   10.5    9.9   15.0   14.3    8.1    2.5   -4.8   -7.6  -17.5  -15.6   -9.5   -6.9   -2.2    1.7    3.9    1.9   -1.7   -4.7  -10.0  -16.4
                 F103  51.5 -116.2  -13.0   -9.5   -4.9   -1.2    4.0    5.7    9.4    8.0    3.1   -1.1   -7.6  -12.3   -7.9   -2.9    0.2    5.0   10.3    9.8   15.0   14.3    8.1    2.7   -4.6   -7.6  -18.1  -16.1  -10.0   -7.3   -2.4    1.7    3.7    1.7   -1.9   -5.0  -10.6  -17.0
                 F105  51.5 -116.1  -13.7  -10.8   -6.5   -3.5    1.8    4.2    7.6    6.1    1.5   -2.7   -9.1  -13.5   -8.7   -4.7   -1.8    2.2    7.6    7.1   12.2   11.5    5.7    1.1   -6.9   -9.1  -18.8  -17.0  -11.2   -9.2   -3.9    1.2    2.9    0.7   -2.7   -6.5  -11.3  -18.0
                 F106  51.5 -116.0  -13.7  -10.8   -6.4   -3.3    1.8    4.2    7.7    6.2    1.7   -2.5   -9.0  -13.4   -8.5   -4.7   -1.9    2.6    7.8    7.3   12.5   11.9    6.0    1.7   -6.8   -8.9  -18.8  -16.9  -11.0   -9.3   -4.3    1.1    2.9    0.6   -2.7   -6.6  -11.2  -17.9
                 F116  51.5 -115.3  -11.3   -7.8   -2.8    1.2    5.9    7.6   11.6   10.1    5.4    2.4   -3.9  -10.2   -5.7   -0.7    2.4    8.4   13.4   12.7   18.3   17.3   11.4    9.0    0.8   -5.1  -17.0  -15.0   -8.1   -5.9   -1.5    2.4    4.9    2.9   -0.7   -4.2   -8.7  -15.3
                 F117  51.5 -115.2  -11.2   -7.7   -2.6    1.4    6.2    7.8   11.8   10.3    5.6    2.6   -3.7  -10.1   -5.6   -0.5    2.8    8.6   13.6   13.0   18.6   17.5   11.7    9.2    1.2   -4.9  -16.9  -14.9   -8.0   -5.8   -1.3    2.6    5.0    3.1   -0.5   -4.1   -8.6  -15.2
                 F118  51.5 -115.1  -11.1   -7.4   -2.4    1.6    6.4    8.1   12.0   10.6    5.9    2.7   -3.4   -9.9   -5.4   -0.1    3.2    8.9   13.9   13.3   18.9   17.7   11.9    9.4    1.8   -4.7  -16.8  -14.7   -8.0   -5.6   -1.0    2.8    5.2    3.6   -0.1   -3.9   -8.6  -15.0
                 F119  51.5 -115.0  -10.9   -7.2   -2.2    1.9    6.7    8.4   12.3   10.9    6.2    3.0   -2.9   -9.6   -5.2    0.3    3.6    9.3   14.2   13.7   19.3   18.1   12.3    9.7    2.6   -4.3  -16.7  -14.6   -8.0   -5.4   -0.8    3.0    5.4    3.8    0.1   -3.8   -8.4  -14.8
                 F120  51.5 -114.9  -10.6   -6.6   -1.7    2.4    7.0    8.6   12.6   11.0    6.3    3.3   -2.5   -9.0   -4.7    1.1    4.4    9.8   14.7   14.2   19.8   18.5   12.9   10.1    3.1   -3.4  -16.5  -14.3   -7.9   -5.0   -0.8    3.1    5.3    3.4   -0.2   -3.5   -8.2  -14.5
                 F121  51.5 -114.8  -10.3   -6.2   -1.3    2.7    7.2    8.9   12.7   11.2    6.5    3.5   -2.3   -8.5   -4.2    1.7    5.1   10.2   15.1   14.7   20.3   18.9   13.3   10.4    3.3   -2.8  -16.3  -14.0   -7.7   -4.7   -0.7    3.1    5.2    3.4   -0.4   -3.4   -7.8  -14.2",
                 header = TRUE, stringsAsFactors = FALSE)

【讨论】:

    【解决方案3】:

    为了给 reshape 解决方案添加一些有用的东西(以弥补提出重复的问题),我将在此处包含一个快速的 for 循环脚本来使变化 reshape 命令中的列表(这对大型数据集很有用)。

    您可以先使用 ycw 的 read.table 行来构建数据(这里不再赘述)。

    foo <- read.table...
    
    # Make a list of the variable names (minus month or time numbers)
    foo.vars <- c("Tave","Tmax","Tmin")
    
    # Loop to make a list of variable column numbers
    for(i in 1:length(foo.vars)){
      if(i==1) reshape.list <- list()
      reshape.list[[i]] <- grep(foo.vars[i],names(foo))
    }
    

    这会为每个变量创建列号列表,在 reshape 命令的 varying 选项中进行标识:

    reshape.list
    [[1]]
     [1]  4  5  6  7  8  9 10 11 12 13 14 15
    
    [[2]]
     [1] 16 17 18 19 20 21 22 23 24 25 26 27
    
    [[3]]
     [1] 28 29 30 31 32 33 34 35 36 37 38 39
    

    然后是实际的reshape命令:

    # Reshape command to make a ling table from the wide table
    foo.long <- reshape(foo, idvar="ID", direction="long", varying=reshape.list, timevar="Month", v.names=foo.vars)
    foo.long <- foo.long[order(foo.long$ID,foo.long$Month),]
    

    代码根据需要返回数据:

      ID  lat   long Month  Tave Tmax  Tmin
    F102 51.5 -116.3     1 -12.8 -8.0 -17.5
    F102 51.5 -116.3     2  -9.2 -2.8 -15.6
    F102 51.5 -116.3     3  -4.6  0.4  -9.5
    F102 51.5 -116.3     4  -0.9  5.2  -6.9
    F102 51.5 -116.3     5   4.1 10.5  -2.2
    ...
    

    【讨论】:

      【解决方案4】:

      这是一个 tidyverse 解决方案,我认为您可以扩展。这个解决方案是当你不能使用separate函数时:

      数据

      df1 <- data.frame(stringsAsFactors=FALSE,
            ID = c("F102", "F103", "F105", "F106", "F116", "F117", "F118",
                   "F119", "F120", "F121"),
           lat = c(51.5, 51.5, 51.5, 51.5, 51.5, 51.5, 51.5, 51.5, 51.5, 51.5),
          long = c(-116.3, -116.2, -116.1, -116, -115.3, -115.2, -115.1, -115,
                   -114.9, -114.8),
        Tave01 = c(-12.8, -13, -13.7, -13.7, -11.3, -11.2, -11.1, -10.9, -10.6,
                   -10.3),
        Tave02 = c(-9.2, -9.5, -10.8, -10.8, -7.8, -7.7, -7.4, -7.2, -6.6, -6.2),
        Tave03 = c(-4.6, -4.9, -6.5, -6.4, -2.8, -2.6, -2.4, -2.2, -1.7, -1.3),
        Tave04 = c(-0.9, -1.2, -3.5, -3.3, 1.2, 1.4, 1.6, 1.9, 2.4, 2.7),
        Tave05 = c(4.1, 4, 1.8, 1.8, 5.9, 6.2, 6.4, 6.7, 7, 7.2),
        Tave06 = c(5.8, 5.7, 4.2, 4.2, 7.6, 7.8, 8.1, 8.4, 8.6, 8.9),
        Tave07 = c(9.5, 9.4, 7.6, 7.7, 11.6, 11.8, 12, 12.3, 12.6, 12.7),
        Tave08 = c(8.1, 8, 6.1, 6.2, 10.1, 10.3, 10.6, 10.9, 11, 11.2),
        Tave09 = c(3.2, 3.1, 1.5, 1.7, 5.4, 5.6, 5.9, 6.2, 6.3, 6.5),
        Tave10 = c(-1.1, -1.1, -2.7, -2.5, 2.4, 2.6, 2.7, 3, 3.3, 3.5),
        Tave11 = c(-7.4, -7.6, -9.1, -9, -3.9, -3.7, -3.4, -2.9, -2.5, -2.3),
        Tave12 = c(-12, -12.3, -13.5, -13.4, -10.2, -10.1, -9.9, -9.6, -9, -8.5),
        Tmax01 = c(-8, -7.9, -8.7, -8.5, -5.7, -5.6, -5.4, -5.2, -4.7, -4.2),
        Tmax02 = c(-2.8, -2.9, -4.7, -4.7, -0.7, -0.5, -0.1, 0.3, 1.1, 1.7),
        Tmax03 = c(0.4, 0.2, -1.8, -1.9, 2.4, 2.8, 3.2, 3.6, 4.4, 5.1),
        Tmax04 = c(5.2, 5, 2.2, 2.6, 8.4, 8.6, 8.9, 9.3, 9.8, 10.2),
        Tmax05 = c(10.5, 10.3, 7.6, 7.8, 13.4, 13.6, 13.9, 14.2, 14.7, 15.1),
        Tmax06 = c(9.9, 9.8, 7.1, 7.3, 12.7, 13, 13.3, 13.7, 14.2, 14.7),
        Tmax07 = c(15, 15, 12.2, 12.5, 18.3, 18.6, 18.9, 19.3, 19.8, 20.3),
        Tmax08 = c(14.3, 14.3, 11.5, 11.9, 17.3, 17.5, 17.7, 18.1, 18.5, 18.9),
        Tmax09 = c(8.1, 8.1, 5.7, 6, 11.4, 11.7, 11.9, 12.3, 12.9, 13.3),
        Tmax10 = c(2.5, 2.7, 1.1, 1.7, 9, 9.2, 9.4, 9.7, 10.1, 10.4),
        Tmax11 = c(-4.8, -4.6, -6.9, -6.8, 0.8, 1.2, 1.8, 2.6, 3.1, 3.3),
        Tmax12 = c(-7.6, -7.6, -9.1, -8.9, -5.1, -4.9, -4.7, -4.3, -3.4, -2.8),
        Tmin01 = c(-17.5, -18.1, -18.8, -18.8, -17, -16.9, -16.8, -16.7, -16.5,
                   -16.3),
        Tmin02 = c(-15.6, -16.1, -17, -16.9, -15, -14.9, -14.7, -14.6, -14.3, -14),
        Tmin03 = c(-9.5, -10, -11.2, -11, -8.1, -8, -8, -8, -7.9, -7.7),
        Tmin04 = c(-6.9, -7.3, -9.2, -9.3, -5.9, -5.8, -5.6, -5.4, -5, -4.7),
        Tmin05 = c(-2.2, -2.4, -3.9, -4.3, -1.5, -1.3, -1, -0.8, -0.8, -0.7),
        Tmin06 = c(1.7, 1.7, 1.2, 1.1, 2.4, 2.6, 2.8, 3, 3.1, 3.1),
        Tmin07 = c(3.9, 3.7, 2.9, 2.9, 4.9, 5, 5.2, 5.4, 5.3, 5.2),
        Tmin08 = c(1.9, 1.7, 0.7, 0.6, 2.9, 3.1, 3.6, 3.8, 3.4, 3.4),
        Tmin09 = c(-1.7, -1.9, -2.7, -2.7, -0.7, -0.5, -0.1, 0.1, -0.2, -0.4),
        Tmin10 = c(-4.7, -5, -6.5, -6.6, -4.2, -4.1, -3.9, -3.8, -3.5, -3.4),
        Tmin11 = c(-10, -10.6, -11.3, -11.2, -8.7, -8.6, -8.6, -8.4, -8.2, -7.8),
        Tmin12 = c(-16.4, -17, -18, -17.9, -15.3, -15.2, -15, -14.8, -14.5, -14.2)
      

      )

      库,提取 alpha 和代码的函数

      library(tidyr)
      library(readr)
      
      extract.alpha <- function(x, space = ""){      
              require(stringr)
              require(purrr)
              require(magrittr)
              
              y <- strsplit(unlist(x), "[^a-zA-Z]+") 
              z <- y %>% map(~paste(., collapse = space)) %>% simplify()
              return(z)}
      
      df1 %>%
              gather(Variable, Value, -c(ID, lat, long)) %>%
              mutate(Month = parse_number(Variable),
                     Variable2 = extract.alpha(Variable)) %>% 
              select(-c(Variable, lat, long)) %>%
              spread(Variable2, Value)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-02-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多