【问题标题】:Extract dates from column names to create time series从列名中提取日期以创建时间序列
【发布时间】:2020-07-04 20:50:23
【问题描述】:

我有一个数据框,其中包含评估地点、不同植被指数和不同日期的计算。我需要在一个新的 data.frame 中加入所有信息,其中嵌入在植被指数中的日期信息包含在输出数据框中的单独列中。

我的数据框结构如下:

df.16 <- data.frame(ID=c("a","b","c"),
                    SUGAR=c(152232.92, 117937.06, 72080.81), 
                    EVI_20160616_re=c(0.51, 0.59, 0.37), # The date is included in the column name.
                    EVI_20161006_re=c(0.59, 0.34, 0.46),
                    GNDVI_20160616_re=c(0.51, 0.59, 0.37),
                    GNDVI_20161006_re=c(0.59, 0.34, 0.46),
                    NDVI_20160616_re=c(0.51, 0.59, 0.37),
                    NDVI_20161006_re=c(0.59, 0.34, 0.46),
                    stringsAsFactors=FALSE)

我想获得一个具有以下结构的新 data.frame,这样每个观测值(行)都会列出给定日期和评估地点的植被指数(EVI、GNDVI 和 NDVI)和 SUGAR 列。

【问题讨论】:

  • 欢迎来到 Stackoverflow!当您加入数据框时,您需要(至少)两个数据框。您的代码仅显示一个数据框。另一个数据框在哪里?
  • 对不起,问题的标题不正确
  • 欢迎来到 Stackoverflow,布莱恩。您的问题的目的似乎是从植被指数的列名中提取日期,因此我相应地编辑了您的问题。请查看并确认我准确理解了您的问题。

标签: r indexing time-series tidyr


【解决方案1】:

使用 R 4.0 和最新版本的 tidyr (1.1.0) 和 dplyr (1.0.0),pivot_longer() 支持将列名拆分为窄格式数据集中的多个变量。拆分后,我们可以使用pivot_wider()EVIGNDVINDVI 创建列。由于输入数据框中变量名称的_re 部分似乎无关紧要,因此我们使用select() 将它们从输出中删除。

df.16 <- data.frame(ID=c("a","b","c"),
                    SUGAR=c(152232.92, 117937.06, 72080.81), 
                    EVI_20160616_re=c(0.51, 0.59, 0.37), # The date is included in the column name.
                    EVI_20161006_re=c(0.59, 0.34, 0.46),
                    GNDVI_20160616_re=c(0.51, 0.59, 0.37),
                    GNDVI_20161006_re=c(0.59, 0.34, 0.46),
                    NDVI_20160616_re=c(0.51, 0.59, 0.37),
                    NDVI_20161006_re=c(0.59, 0.34, 0.46),
                    stringsAsFactors=FALSE) 
library(tidyr)
library(dplyr)
df.16 %>% 
     pivot_longer(.,-c(ID,SUGAR),names_to=c("variable","DATE","RE"),
                  names_sep = "_",values_to = "value") %>%
     select(-RE) %>% 
     pivot_wider(.,c(ID,DATE,SUGAR),names_from=variable,values_from=value)

...和输出:

# A tibble: 6 x 6
  ID    DATE       SUGAR   EVI GNDVI  NDVI
  <chr> <chr>      <dbl> <dbl> <dbl> <dbl>
1 a     20160616 152233.  0.51  0.51  0.51
2 a     20161006 152233.  0.59  0.59  0.59
3 b     20160616 117937.  0.59  0.59  0.59
4 b     20161006 117937.  0.34  0.34  0.34
5 c     20160616  72081.  0.37  0.37  0.37
6 c     20161006  72081.  0.46  0.46  0.46

注意:虽然SUGAR的小数点右边的数据没有打印在输出中,但是通过将结果转换为as.data.frame()可以看出数据是准确的.

如果我们需要将日期值转换为R中的Date对象,可以添加mutate()进行转换:

df.16 %>% group_by(ID,SUGAR) %>% 
     pivot_longer(.,-c(ID,SUGAR),names_to=c("variable","DATE","RE"),
                  names_sep = "_",values_to = "value") %>%
     select(-RE) %>% 
     pivot_wider(.,c(ID,DATE,SUGAR),names_from=variable,values_from=value) %>%
     mutate(DATE = as.Date(DATE,"%Y%m%d"))

...和输出:

# A tibble: 6 x 6
# Groups:   ID, SUGAR [3]
  ID    DATE         SUGAR   EVI GNDVI  NDVI
  <chr> <date>       <dbl> <dbl> <dbl> <dbl>
1 a     2016-06-16 152233.  0.51  0.51  0.51
2 a     2016-10-06 152233.  0.59  0.59  0.59
3 b     2016-06-16 117937.  0.59  0.59  0.59
4 b     2016-10-06 117937.  0.34  0.34  0.34
5 c     2016-06-16  72081.  0.37  0.37  0.37
6 c     2016-10-06  72081.  0.46  0.46  0.46

【讨论】:

    【解决方案2】:

    使用tidyrdplyr

    library(dplyr)
    library(tidyr)
    
    df.16 %>% 
      gather(key = measurement_date, value = value, -ID, -SUGAR) %>% 
      mutate(measurement = gsub("[^A-Z.]", "",  measurement_date), 
             DATE = gsub("[^0-9.]", "",  measurement_date) %>%
                 as.Date(format = "%Y%m%d")) %>%
      select(-measurement_date) %>%
      spread(key = measurement, value = value)
    
    #   ID     SUGAR       DATE  EVI GNDVI NDVI
    # 1  a 152232.92 2016-06-16 0.51  0.51 0.51
    # 2  a 152232.92 2016-10-06 0.59  0.59 0.59
    # 3  b 117937.06 2016-06-16 0.59  0.59 0.59
    # 4  b 117937.06 2016-10-06 0.34  0.34 0.34
    # 5  c  72080.81 2016-06-16 0.37  0.37 0.37
    # 6  c  72080.81 2016-10-06 0.46  0.46 0.46
    

    【讨论】:

      【解决方案3】:

      除了@LenGreski 回答pivot_longer/pivot_wider 之外,还可以单独使用pivot_longer 来完成,方法是利用names_pattern 根据中的模式将字符组捕获为正则表达式模式((...))列名。在这里,使用的正则表达式是从字符串的开头 (^) 捕获不是_ (([^_]+)) 的第一组字符,然后是_,然后是第二组字符不是一个下划线,后跟_re,如果需要,将“DATE”转换为Date 类(ymd 来自lubridate)。另外,请注意在names_to 中指定向量的序列。在这里,值部分指定了值应该进入的列,而“日期”是列名的第二部分

      library(dplyr) # 1.0.0
      library(tidyr)
      library(lubridate)
      df.16 %>%
        pivot_longer(cols = contains("_"), names_to = c(".value", "DATE"), 
               names_pattern= "^([^_]+)_([^_]+)_re") %>%
        mutate(DATE = ymd(DATE))
      # A tibble: 6 x 6
      #  ID      SUGAR DATE         EVI GNDVI  NDVI
      #  <chr>   <dbl> <date>     <dbl> <dbl> <dbl>
      #1 a     152233. 2016-06-16  0.51  0.51  0.51
      #2 a     152233. 2016-10-06  0.59  0.59  0.59
      #3 b     117937. 2016-06-16  0.59  0.59  0.59
      #4 b     117937. 2016-10-06  0.34  0.34  0.34
      #5 c      72081. 2016-06-16  0.37  0.37  0.37
      #6 c      72081. 2016-10-06  0.46  0.46  0.46
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-08-30
        • 2015-05-25
        • 2018-09-16
        • 2015-08-19
        • 1970-01-01
        • 2022-11-23
        • 1970-01-01
        相关资源
        最近更新 更多