【问题标题】:Parsing a string in R and comparing the values with another column解析 R 中的字符串并将值与另一列进行比较
【发布时间】:2021-07-13 16:04:08
【问题描述】:

这可能看起来微不足道,但我真的陷入了将值与这个复杂字符串进行比较的问题

我的数据框如下所示:

Id History Report Month
1001 Jun:2020,030/XXX-May:2020,035/XXX-Apr:2020,040/XXX-Mar:2020,060/XXX July 2021
1003 Jun:2017,823/XXX-May:2017,000/XXX-Apr:2017,000/XXX-Mar:2017,000/XXX July 2021
1005 Apr:2019,000/XXX-Mar:2019,800/XXX-Feb:2019,000/XXX-Jan:2019,000/XXX July 2021
1006 Jun:2020,000/XXX-May:2020,030/XXX-Apr:2020,060/XXX-Mar:2020,090/XXX July 2021

用于比较的列历史的键、值对如下:

Id : 1001 - Jun 2020,030   May 2020, 035   Apr 2020, 040...... 
Id : 1003 - Jun 2017,823   May 2017, 000   Apr 2017, 000...... 

问题陈述是:我想将这些键、值对与报告月份(即总是当前月份)进行比较,并根据它创建一个条件列。逻辑是:2021 年 7 月之前的 24 个月(可能是 12 或 36 个月),即 2021 年 7 月至 2019 年 6 月,在此时间段内的月份中有多少键、值对的值 >= 30 或 >= 60 等。所以如果一个字符串从

输出

Id Report Month +30_last_24 +30_last_36
1001 July 2021 4 4
1003 July 2021 0 0
1005 July 2021 0 1
1006 July 2021 3 3

我最近才开始使用 R,甚至没有解决方案,所以任何帮助都将不胜感激。

修改后的原始数据集

df <- read.table(header = T, text = "Id History ReportMonth
1001    Jun:2020,030/XXX|May:2020,035/XXX|Apr:2020,040/XXX|Mar:2020,060/XXX 'July 2021'
1003    Jun:2017,DDD/XXX|May:2017,030/XXX|Apr:2017,DDD/STD|Mar:2017,000/XXX 'July 2021'
1005    Apr:2019,000/XXX|Mar:2019,800/DDD|Feb:2019,000/XXX|Jan:2019,000/XXX 'July 2021'
1006    Jun:2020,000/XXX|May:2020,030/XXX|Apr:2020,060/XXX|Mar:2020,090/XXX 'July 2021'")

【问题讨论】:

  • 你能否添加一些示例数据 Rakshit?
  • 你是如何在最后一列最后一行得到 4 的?那不应该是3吗??
  • @Onyambu 是的,应该是 3,我的错
  • @RakshitSinghal,请查看修改后的答案。

标签: r parsing


【解决方案1】:

根据修改修订战略-

  • 使用| 分隔行,但仅在使用\\ 转义之后
  • 使用, 分隔成列
  • 使用gsub从值中提取数字
  • 休息很明显。

如有任何疑问,请随时询问。

df <- read.table(header = T, text = "Id History ReportMonth
1001    Jun:2020,030/XXX|May:2020,035/XXX|Apr:2020,040/XXX|Mar:2020,060/XXX 'July 2021'
1003    Jun:2017,DDD/XXX|May:2017,030/XXX|Apr:2017,DDD/STD|Mar:2017,000/XXX 'July 2021'
1005    Apr:2019,000/XXX|Mar:2019,800/DDD|Feb:2019,000/XXX|Jan:2019,000/XXX 'July 2021'
1006    Jun:2020,000/XXX|May:2020,030/XXX|Apr:2020,060/XXX|Mar:2020,090/XXX 'July 2021'")

library(tidyverse)
library(lubridate, warn.conflicts = F)

df %>%
  separate_rows(History, sep = '\\|') %>%
  separate(History, into = c('Hist_mon', 'Hist_val'), sep = ',') %>%
  mutate(Hist_mon = dmy(paste0('1:', Hist_mon)),
         Hist_val = as.numeric(gsub('(\\D*)', '', Hist_val)),
         ReportMonth = dmy(paste0('1 ', ReportMonth))) %>%
  group_by(Id, ReportMonth) %>%
  summarise(last_24_30 = sum(Hist_val >= 30 & Hist_mon >= ReportMonth %m-% months(24)),
            last_36_30 = sum(Hist_val >= 30 & Hist_mon >= ReportMonth %m-% months(36)), .groups = 'drop')
#> # A tibble: 4 x 4
#>      Id ReportMonth last_24_30 last_36_30
#>   <int> <date>           <int>      <int>
#> 1  1001 2021-07-01           4          4
#> 2  1003 2021-07-01           0          0
#> 3  1005 2021-07-01           0          1
#> 4  1006 2021-07-01           3          3

reprex package 创建于 2021-07-16 (v2.0.0)

【讨论】:

  • 嗨@Anil 感谢您的及时回复。我几乎没有后续问题,因为我运行了代码,我发现历史列中的字符串有一些不同的格式: 1. 你使用 sep = '/XXX-' 的地方,我需要使用 sep = '/XXX|'因为在我的数据中不是'/XXX-',而是/XXX| 2.代替/XXX|....之前的数字部分可以是XXX/XXX| .例如:Jun:2017,XXX/XXX|May:2017,030/XXX|或 Jun:2017,DDD/XXX|May:2017,030/XXX| 3.“/”之后也没有固定模式。我看到了 Jun:2017,DDD/DDD|May:2017,030/DDD 的值
  • 我在原始问题中添加了一个数据框以具有所有可能的格式
  • @RakshitSinghal,我在这里想念你的 cmets。告诉我一件事,DDD/.. 中的数字将如何考虑?
【解决方案2】:
library(tidyverse)
library(lubridate)
df %>%
  separate_rows(History, sep = '[|]')%>%
  filter(str_detect(History, "\\w"), str_detect(History, "\\d+/"))%>%
  separate(History, c("Date", "Value", "d"), sep = '[,/]', convert = TRUE) %>%
  mutate(across(c(Date,ReportMonth), ~myd(paste(.x, "01")))) %>%
  group_by(Id) %>%
  summarise(r = list(map(c(m24 = 24, m36 = 36), ~sum(
    Date + months(.x) > ReportMonth & Value >= 30)))) %>%
  unnest_wider(r) %>%
  right_join(df, 'Id')

  
# A tibble: 4 x 5
     Id   m24   m36 History_Report                                                      Month    
  <int> <int> <int> <chr>                                                               <chr>    
1  1001     4     4 Jun:2020,030/XXX-May:2020,035/XXX-Apr:2020,040/XXX-Mar:2020,060/XXX July 2021
2  1003     0     0 Jun:2017,823/XXX-May:2017,000/XXX-Apr:2017,000/XXX-Mar:2017,000/XXX July 2021
3  1005     0     1 Apr:2019,000/XXX-Mar:2019,800/XXX-Feb:2019,000/XXX-Jan:2019,000/XXX July 2021
4  1006     3     3 Jun:2020,000/XXX-May:2020,030/XXX-Apr:2020,060/XXX-Mar:2020,090/XXX July 2021

【讨论】:

  • 嘿@Onyambu - 感谢您的及时回复,请您再看一遍问题,字符串格式内部有多种变化。我提供了数据集来涵盖所有可能的情况。很抱歉没有提供我原始问题的完整信息
  • @RakshitSinghal 有些是字符而不是数字,例如 DDD/XXX 你想如何对待它们?
  • 我想把它们当作0。这意味着实际数字没有报告,所以我别无选择,只能把它们当作0。基本上如果'/'之前的任何东西都在非数字格式,如 XXX 或 DDD.. 那么它应该被忽略或视为 0
  • 此解决方案似乎有效,但汇总存在一个问题。我的数据有重复的 ID,我希望以非聚合方式获得结果。现在对于 4 个重复的 id,它给了我相同的结果,我猜是因为最后的正确连接。有没有一种方法可以做到这一点,而无需在最后总结结果,而只需将单个行的结果放在它们前面。我尝试了 mutate 而不是 summarise 但它没有用
  • @RakshitSinghal 一开始就做df %&gt;% rownames_to_column()... 并在groupby 中包含groupby(rowname)
猜你喜欢
  • 2015-04-04
  • 1970-01-01
  • 1970-01-01
  • 2022-06-14
  • 2019-06-17
  • 1970-01-01
  • 2014-01-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多