【问题标题】:Creating dummy for every hour of the day为一天中的每个小时创建假人
【发布时间】:2019-10-02 15:30:11
【问题描述】:

我很惊讶在这个网站上找不到可以回答我的问题。

我想为一天中的每个小时创建 24 个虚拟变量(如果时间是一天中的那个小时,则值为 1,否则为 0)。一小部分数据如下所示:

       df <- as.POSIXct(c("08-01-2018 19:46", "08-01-2018 19:50", "08-01- 
       2018 20:46", "09-01-2018 21:17"), format = "%d-%m-%Y %H:%M")

       [1] "2018-01-08 19:46:00 CET" "2018-01-08 19:50:00 CET" "2018-01-08 
       20:46:00 CET" "2018-01-09 21:17:00 CET"

我希望输出是这样的:

           19 20 21
        1:  1  0  0
        2:  1  0  0
        3:  0  1  0
        4:  0  0  1

这个问题我已经看过了:Creating a dummy variable for certain hours of the day

我对我的问题的答案唯一的问题是我必须为每个案例编写 24 个 ifelse 语句。

我想知道是否有更优雅的方式来获得此输出,而无需编写 24 条 ifelse 语句。

如果此问题重复,请告诉我!

提前致谢,

RC

【问题讨论】:

    标签: r


    【解决方案1】:

    这样好吗?如果您需要data.frame,可以在输出中使用as.data.frame

    library(lubridate)
    hours <- as.factor(lubridate::hour(df))
    
    # with intercept
    model.matrix(~hours)
    
    # without intercept - (+0)
    model.matrix(~hours+0)
    

    进一步阅读:

    Generate a dummy-variable

    https://stats.stackexchange.com/questions/174976/why-does-the-intercept-column-in-model-matrix-replace-the-first-factor

    【讨论】:

    • 如果有可能没有表示所有小时,但您想保证所有 24 个虚拟变量,则将 , levels=0:23 添加到对 factor 的调用中。
    • 感谢@Jonny Phelps,它就像一个魅力。还要感谢 Greg Snow 的出色补充!
    【解决方案2】:

    使用基础 R 你可以这样做:

    model.matrix(~a-1,data.frame(a=factor(as.POSIXlt(df)$h)))
    
     a19 a20 a21
    1   1   0   0
    2   1   0   0
    3   0   1   0
    4   0   0   1
    attr(,"assign")
    [1] 1 1 1
    attr(,"contrasts")
    attr(,"contrasts")$a
    [1] "contr.treatment"
    

    【讨论】:

      【解决方案3】:

      使用 tidyverse(使用 NA 抑制编辑):

      df <- tibble::tibble(time = as.POSIXct(c("08-01-2018 19:46", "08-01-2018 19:50", "08-01-2018 20:46", "09-01-2018 21:17"), format = "%d-%m-%Y %H:%M")
      )
      
      suppressPackageStartupMessages(library(dplyr))
      df_dummy <- df %>% 
              mutate(
                      hours = lubridate::hour(time),
                      dummy = 1)
      
      tidyr::pivot_wider(data = df_dummy, names_from = hours, values_from = dummy, values_fill = list(dummy = 0))
      #> # A tibble: 4 x 4
      #>   time                 `19`  `20`  `21`
      #>   <dttm>              <dbl> <dbl> <dbl>
      #> 1 2018-01-08 19:46:00     1     0     0
      #> 2 2018-01-08 19:50:00     1     0     0
      #> 3 2018-01-08 20:46:00     0     1     0
      #> 4 2018-01-09 21:17:00     0     0     1
      

      【讨论】:

        【解决方案4】:

        这个问题可以使用包lubridate来解决。

        使用 for 循环的解决方案

        hour() 为我们提供了 POSIXct 对象的时间。通过创建一个感兴趣的时间向量并让它们在您提供的时间点上运行,可以执行以下操作:

        # hours, storage vector and list for building the dataframe
        hourv <- c(19:21)
        storage <- c()
        list <- list()
        # the loop over the desired hours and points in time 
        for(k in 1:4){
        for(i in 1:3){
          if(hourv[i] == hour(df[k])){
            storage[i] <- 1
          }
          else{
            storage[i] <- 0
          }
        }
        list[[k]] <- storage
        }
        

        结果

        df1 <- as.data.frame(do.call(rbind,list))
        
          V1 V2 V3
        1  1  0  0
        2  1  0  0
        3  0  1  0
        4  0  0  1
        

        数据

        df <- as.POSIXct(c("08-01-2018 19:46", "08-01-2018 19:50", "08-01-2018 20:46", "09-01-2018 21:17"), format = "%d-%m-%Y %H:%M")
        
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-01-11
          • 2011-04-12
          • 1970-01-01
          • 2010-12-14
          • 1970-01-01
          • 2016-05-10
          • 1970-01-01
          • 2017-03-05
          相关资源
          最近更新 更多