【问题标题】:maintaining date/POSIXct columns when Converting column class/types转换列类/类型时维护日期/POSIXct 列
【发布时间】:2018-10-07 18:40:56
【问题描述】:

我有一个 400 列的数据框,其中散布着多个日期列。 在下面的代表性示例中,我想实现以下目标:

  1. 将因子转换为数字或字符或 POSIXct
  2. 在合理的情况下将字符转换为数字/整数
  3. 将任何包含日期的列转换为 POSIXct,无论它是因子、字符还是日期

    set.seed(123)
    df1 <- data.frame(
    A = as.numeric(1:10),
    B = sample(seq(as.POSIXct('2000/01/01'), as.POSIXct('2018/01/01'), by="day"), size=10),
    C = as.numeric(sample(20:90, size = 10)),
    D = sample(c("yes", "no"), size=10, replace = TRUE),
    E = as.factor(sample(1000:2000, size = 10)),
    F = as.character(c("test","test2","test3","test4","test5","test6","test7","test8","test9","test10")),
    G = as.factor(c("test","test2","test3","test4","test5","test6","test7","test8","test9","test10")),
    H = as.character(sample(seq(as.POSIXct('2000/01/01'), as.POSIXct('2018/01/01'), by="day"), size=10)),stringsAsFactors=FALSE
    )
    df1
    A                   B  C   D    E      F      G                   H
    1   1 2005-03-06 00:00:00 87  no 1963   test   test 2002-07-27 23:00:00
    2   2 2014-03-11 00:00:00 51  no 1902  test2  test2 2007-06-17 23:00:00
    3   3 2007-05-11 23:00:00 66  no 1690  test3  test3 2007-06-11 23:00:00
    4   4 2015-11-22 00:00:00 58  no 1793  test4  test4 2006-08-20 23:00:00
    5   5 2016-12-02 00:00:00 26  no 1024  test5  test5 2002-09-27 23:00:00
    6   6 2000-10-26 00:00:00 79  no 1475  test6  test6 2002-06-30 23:00:00
    7   7 2009-06-30 23:00:00 35  no 1754  test7  test7 2004-03-11 00:00:00
    8   8 2016-01-19 00:00:00 22  no 1215  test8  test8 2008-05-17 23:00:00
    9   9 2009-11-30 00:00:00 40 yes 1315  test9  test9 2004-10-12 00:00:00
    10 10 2008-03-17 00:00:00 85 yes 1229 test10 test10 2015-06-03 23:00:00
    
    unlist(lapply(df1, class))
      A          B1          B2           C           D           E           F           G           H 
      "numeric"   "POSIXct"    "POSIXt"   "numeric" "character"    "factor" "character"    "factor" "character" 
    

到目前为止,我已经尝试了以下(但它不保留 POSIXct B 列)或将字符日期列(H 列)转换为 POSIXct:

df1_clean <- df1 %>% mutate_all(funs(type.convert(as.character(.), as.is = TRUE)))
unlist(lapply(df1_clean, class))
      A           B           C           D           E           F            G           H 
      "integer" "character"   "integer" "character"   "integer" "character" "character" "character" 

对于这个小数据集,我可以只调用列并使用 lubridate 将 B 和 H 转换为 POSIXct,但我希望它自动跨数据帧。

任何帮助将不胜感激! 谢谢 萌

【问题讨论】:

  • 我不明白:您将所有列显式转换为character,然后当它们失去POSIXct-ness 时您会感到惊讶?在 R 中(不考虑自动强制转换),类通常是互斥的:integer 不能是 charactercharacter 不能是 POSIXct,所以当你说 as.character(.) 时,你是自愿和明确放弃它的日期时间性以将其转换为字符串。您是否尝试在没有先验知识的情况下动态执行此操作,或者您可以使用mutate_at(vars(A,C,...), funs(as.character(.)))
  • 感谢 r2evans!我对一切都变成字符并不感到惊讶 - type.convert 是我遇到的在 R 中动态重新分配类的唯一方法。我不知道如何将其编写为代码,但它可以工作的一种方式将是:i)将字符日期(例如 H 列)转换为 POSIXct,ii)创建不是 POSIXct 的变量列表,最后 iii)将所有不是 POSIXct 的变量转换为 type.convert .希望这可以澄清
  • 注意type.convert 的帮助没有提到POSIXct,所以如果你使用那个函数,你就得靠你自己了。您是否提前知道哪些列应该是哪些列?或者您是否正在尝试提出一个通用功能,无论您向它扔什么,它都会愉快/智能地为您执行此操作?
  • 我很高兴使用 type.convert 的更好替代方法,如果您知道的话。是的,我追求的是一个通用函数,无论我扔什么,它都会分配正确的类。
  • 执行“自动类型确定”的函数通常被编写为将数据写入 R,而不是处理R环境中已经存在的对象。如果这是来自 CSV 或类似文件,我可以建议使用 readr 包吗?它首先为您检查前 1000 行(可配置)和自动类型。

标签: r lubridate posixct


【解决方案1】:

这可能不是最优雅的方式 - 但它似乎对我有用。

#install.packages("tidyverse")
#install.packages("dataCompareR")
library("tidyverse")
library("dataCompareR")



# create reproducible df
set.seed(123)
df1 <- data.frame(
  A = as.numeric(1:10),
  B = sample(seq(as.POSIXct('2000/01/01', tz = "UTC"), as.POSIXct('2018/01/01', tz = "UTC"), by="day"), size=10),
  C = as.numeric(sample(20:90, size = 10)),
  D = sample(c("yes", "no"), size=10, replace = TRUE),
  E = as.factor(sample(1000:2000, size = 10)),
  F = as.character(c("test","test2","test3","test4","test5","test6","test7","test8","test9","test10")),
  G = as.factor(c("test","test2","test3","test4","test5","test6","test7","test8","test9","test10")),
  H = as.character(sample(seq(as.POSIXct('2000/01/01', tz = "UTC"), as.POSIXct('2018/01/01', tz = "UTC"), by="day"), size=10)),stringsAsFactors=FALSE
)
df1 #look at df

unlist(lapply(df1, class)) #look at df classes


df1_clean <- df1 %>% mutate_all(funs(type.convert(as.character(.), as.is = TRUE))) #reassign classes by running type.convert (input are all variables from the df but as.character)
unlist(lapply(df1_clean, class)) #look at df classes now

#check if a column is a Date - https://stackoverflow.com/questions/18178451/is-there-a-way-to-check-if-a-column-is-a-date-in-r
tmp=sapply(df1_clean, function(x) !all(is.na(as.Date(as.character(x),format="%Y-%m-%d", tz = "UTC")))) 

# if tmp is True, change according column to as.POSIXct 
for (i in 1:ncol(df1_clean)){
  if (tmp[i] == T){
    df1_clean[,i]<- as.POSIXct(df1_clean[,i], tz = "UTC")
  }
}

df1_clean #look at df
unlist(lapply(df1_clean, class)) #look at df classes


comp <- rCompare(df1, df1_clean) #compare your dfs before and after using the dataCompareR package
summary(comp) # check summary

【讨论】:

    猜你喜欢
    • 2018-04-01
    • 2020-09-20
    • 1970-01-01
    • 2017-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-10
    相关资源
    最近更新 更多