首页 > 解决方案 > 如何强制将 tibble 数据框列从 double 转换为 time?

问题描述

我在tidyverse。

read_csv我使用(都具有相同的列)读取了几个 CSV 文件

df <- read_csv("data.csv")

获取一系列数据帧。经过一堆数据清理和计算,我想合并所有数据框。

有几十个几百行和几十列的数据帧。一个最小的例子是

DF1
ID             name   costcentre start  stop  date
  <chr>          <chr>  <chr>      <time> <tim> <chr>    
1 R_3PMr4GblKPV~ Geo    Prizm      01:00  03:00 25/12/2019 
2 R_s6IDep6ZLpY~ Chevy  Malibu        NA     NA NA       
3 R_238DgbfO0hI~ Toyota Corolla    08:00  11:00 25/12/2019 


DF2
ID                  name   costcentre start stop   date
<chr>               <chr>  <chr>      <lgl> <time> <chr>
1 R_3PMr4GblKPV1OYd Geo    Prizm      NA       NA  NA   
2 R_s6IDep6ZLpYvUeR Chevy  Malibu     NA    03:00  12/12/2019
3 R_238DgbfO0hItPxZ Toyota Corolla    NA       NA  NA        

根据我的清洁要求(开始 == NA & stop != NA),其中的一些 NAstart必须是00:00. 我可以在该单元格中输入零:

df <- within(df, start[is.na(df$start) & !is.na(df$stop)] <- 0)

这导致

DF1
ID             name   costcentre start  stop  date
  <chr>          <chr>  <chr>      <time> <tim> <chr>    
1 R_3PMr4GblKPV~ Geo    Prizm      01:00  03:00 25/12/2019 
2 R_s6IDep6ZLpY~ Chevy  Malibu        NA     NA NA       
3 R_238DgbfO0hI~ Toyota Corolla    08:00  11:00 25/12/2019 


DF2
ID                  name   costcentre start stop   date
<chr>               <chr>  <chr>      <dbl> <time> <chr>
1 R_3PMr4GblKPV1OYd Geo    Prizm      NA       NA  NA   
2 R_s6IDep6ZLpYvUeR Chevy  Malibu       0   03:00  12/12/2019
3 R_238DgbfO0hItPxZ Toyota Corolla    NA       NA  NA        

我在合并时遇到问题,有时start是双重的(因为我已经做了一些替换),是合乎逻辑的(因为所有 NA 都没有替换),或者是时间(如果在原始数据读取中有一些时间)

merged_df <- bind_rows(DF1, DF2,...)

给我错误Error: Column开始can't be converted from hms, difftime to numeric

如何强制开始列成为类型time,以便我可以合并我的数据?

标签: rtidyverse

解决方案


我认为重要的一点是startstop列似乎是time类型的,它们是基于hms包的。我想知道为什么/何时显示,因为我以前没有听说过这门课。

正如我所看到的,这些列实际上属于hmsdifftime类。这些对象实际上不是在几分钟内存储(如打印的小标题所暗示的),而是在几秒钟内。如果我们通过查看数据,我们会看到这一点View(df)。有趣的是,如果我们打印数据,变量类型显示为time

要解决您的问题,您必须将所有开始和停止列一致地转换为 hms difftime 列,如下例所示。

最小的可重现示例:

library(dplyr)
library(hms)

df1 <- tibble(id = 1:3, 
              start = as_hms(as.difftime(c(1*60,NA,8*60), units = "mins")),
              stop = as_hms(as.difftime(c(3*60,NA,11*60), units = "mins")))
df2 <- tibble(id = 4:6, 
              start = c(NA,NA,NA), 
              stop = as_hms(as.difftime(c(NA,3*60,NA), units = "mins")))

甚至更容易(但打印与问题略有不同):

df1 <- tibble(id = 1:3, 
              start = as_hms(c(1*60,NA,8*60)),
              stop = as_hms(c(3*60,NA,11*60)))
df2 <- tibble(id = 4:6, 
              start = c(NA,NA,NA), 
              stop = as_hms(c(NA,3*60,NA)))

解决问题:

class(df1$start) # In df1 start has class hms and difftime
class(df2$start) # In df2 start has class logical

# We set start=0 if stop is not missing and turn the whole column into an hms object
df2 <- df2 %>% mutate(start = new_hms(ifelse(!is.na(stop), 0, NA)))

# Now that column types are consistent across tibbles we can easily bind them together
df <- bind_rows(df1, df2)
df

推荐阅读