【问题标题】:Replacing week/month times as strings with time in years? (R)将周/月时间作为字符串替换为以年为单位的时间? (右)
【发布时间】:2018-08-19 02:52:03
【问题描述】:

我找到了一个宠物收养数据集,其中包含宠物收养时的年龄。但是,年龄变量在同一列中包含诸如“3 个月”或“4 年”或“3 周”之类的字符串。数据集在其他方面很整洁。如何将这些变量转换为年份值?

我尝试过这样的事情:

for(i in i:nrow(Pet_Train$AgeuponOutcome)){
 if(grepl(i, "month") == TRUE)
   Pet_Train$Age_in_Years[i] == "0"

}

但我对循环/if 语句/我刚刚查找的这个“grepl”函数几乎没有经验。我确实有使用 mutate() 和 filter() 之类的整洁函数的经验,但我不确定如何将这些函数与这些可能的参数组合一起应用。

因为有 27,000 个实例,所以我宁愿不手动完成。

编辑: 我想出了如何使用 grepl 函数将包含“月”的实例替换为“不到一年”。但是有没有办法把确切的月数转换成小数的年份?

【问题讨论】:

  • 如果您已经将数量和单位放入不同的列中(应该可以通过拆分文本来轻松完成),那么您可以执行以下操作:df[,'years']

标签: r date


【解决方案1】:

只是为了扩展我留下的评论,您可以使用ifelse。首先,这是您的数据的可重现示例(在提出问题时提供此示例对您总是非常有用):

df <- data.frame("Duration" = c("3 months", "4 years", "3 weeks"))

然后您可以使用字符串拆分从中拆分出单位和值

df$Value <- as.numeric(vapply(strsplit(as.character(df$Duration), split = " "), `[`, 1, FUN.VALUE=character(1)))
df$Units <- vapply(strsplit(as.character(df$Duration), split = " "), `[`, 2, FUN.VALUE=character(1))

最后,使用 nested ifelse arguments 告诉 R 如果列中的数据符合条件该怎么办,如果不符合条件怎么办 - 所以我有这样的说法,如果单位是周数,将金额除以 52.18(每年的周数)。

df$Years <- ifelse(df[,'Units']=="weeks", df[,'Value']/(365.25/7), ifelse(df[,'Units']=="months", df[,'Value']/12, df[,'Value']))

以及成功输出:

> df
  Duration Value  Units      Years
1 3 months     3 months 0.25000000
2  4 years     4  years 4.00000000
3  3 weeks     3  weeks 0.05749487

注意:将“天”作为时间单位会更合适,如果您有第一个和第二个事件的日期(出生日期和收养日期)那个动物)。这是因为年和月是可变长度单位 - 12 月比 2 月长,2016 年比 2015 年和 2017 年长。

【讨论】:

    【解决方案2】:

    David Rubinger 的答案使用lubridate 包将字符串强制转换为Duration 类的对象。

    as.duration() 函数似乎可以识别各种字符串,例如,

    age_text <- c("3 months", "4 years", "3 weeks", "52 weeks", "365 days 6 hours")
    lubridate::as.duration(age_text)
    
    [1] "7889400s (~13.04 weeks)" "126230400s (~4 years)"   "1814400s (~3 weeks)"    
    [4] "31449600s (~52 weeks)"   "31557600s (~1 years)"
    

    但是,OP 已要求将字符串转换为年份值而不是秒数。

    这可以通过使用as.numeric() 函数来实现,该函数采用units 参数来指定所需的转换:

    as.numeric(lubridate::as.duration(age_text), units = "years")
    
    [1] 0.25000000 4.00000000 0.05749487 0.99657769 1.00000000
    

    也可以选择其他单位:

    as.numeric(lubridate::as.duration(age_text), units = "months")
    
    [1]  3.0000000 48.0000000  0.6899384 11.9589322 12.0000000
    
    as.numeric(lubridate::as.duration(age_text), units = "weeks")
    
    [1]  13.04464 208.71429   3.00000  52.00000  52.17857
    

    【讨论】:

      【解决方案3】:

      前两个仅使用 R 的基数,第三个使用 dplyr 和 tidyr。

      1) 使用read.table 将输入列拆分为数字和单位部分,然后将数字部分乘以单位部分所代表的年份分数。

      PT <- data.frame(Age = c("3 months", "4 years", "3 weeks")) # input
      
      transform(cbind(PT, read.table(text = as.character(PT$Age))), 
        Years = V1 * (7 / 365.25 * (V2 == "weeks") + 1/12 * (V2 == "months") + (V2 == "years")))
      

      给予:

             Age V1     V2      Years
      1 3 months  3 months 0.25000000
      2  4 years  4  years 4.00000000
      3  3 weeks  3  weeks 0.05749487
      

      2) 或者,最后一行可以写成switch

      transform(cbind(PT, read.table(text = as.character(PT$Age), as.is = TRUE)), 
        Years = V1 * sapply(V2, switch, weeks = 7 / 365.25, months = 1 / 12, years = 1))
      

      3) 这使用 dplyr 和 tidyr:

      PT %>%
         separate(Age, c("No", "Units")) %>%
         mutate(No = as.numeric(No), 
                Years = No * case_when(Units == "weeks" ~ 7 / 365.25,
                                       Units == "months" ~ 1 / 12,
                                       Units == "years" ~ 1))
      

      给予:

        No  Units      Years
      1  3 months 0.25000000
      2  4  years 4.00000000
      3  3  weeks 0.05749487
      

      【讨论】:

        【解决方案4】:

        基于lubridate的解决方案:

        library(tidyverse)
        library(lubridate)
        dat <- data_frame(age_text = c("3 months", "4 years", "3 weeks"))
        dat %>% mutate(age_in_years = duration(age_text) / dyears(1))
        

        【讨论】:

          猜你喜欢
          • 2011-01-15
          • 2023-03-17
          • 2020-10-24
          • 2018-05-04
          • 1970-01-01
          • 2014-10-16
          • 1970-01-01
          • 2011-05-07
          • 2022-07-04
          相关资源
          最近更新 更多