工作项目的逻辑数据整理建议

Advice on Logical Data Tidying for a work project

我的数据集来自 excel 由非数据导向的同事建立的文件。我的数据很敏感,所以我不能共享数据集,但我会尝试举一个例子,这样更容易理解我在说什么。我有一个唯一标识符列。我的问题是日期列。我有多个日期列。当导入到 R 中时,一些列作为日期导入,其中一些作为 excel 日期导入。然后列中的某些单元格具有一串日期(字符类型)。并非所有字符串的大小都相同。有些有 2 个列表,有些有 7 个列表。

我正在尝试整理我的数据。我的想法是将所有收集日期放在一栏中。这就是我被困的地方。我可以使用 pivot_longer() 因为并非所有列都是同一类型。我无法将 excel 日期转换为 R 日期 w/out 以摆脱字符串列表。而且我无法摆脱字符串列表,因为我 运行 进入错误:长度不兼容。我认为我的逻辑流程是错误的,任何指向正确方向的建议都会有所帮助。我可以在我的流程正确后查看编码。

我有:

  Unique.ID Collection.Date1 Test.Result1 Collection.Date2 Test.Result2        Collection.Date3
1         1       12/12/2020     positive           1/1/21     negative                   44890
2         2         11/30/20     negative   1/8/21,1/20/21     negative 2/10/21,3/10/21,4/10/21
3         3          1/20/21     negative            44011     positive                   44007
4         4          12/1/20     positive            44018     negative                   44064

我想要的:

Unique ID     Collection Date     Test Result

1             12/12/20            positive

1             1/1/21              negative

1             2/2/21              NA

2             11/30/20            negative

2             1/8/21              negative

2             1//20/21            negative

2             2/10/21             NA

2             3/10/21             NA

2             4/10/21             NA

3             1/20/21             negative

3             3/3/21              positive

3             4/3/21              NA

4             12/1/20             positive

4             3/3/21              negative

4             4/3/21              NA

如果我尝试先将所有内容都变成日期,则会遇到字符串错误 bc。当我尝试扩展字符串时,由于它们的长度不同,因此出现错误。

由于您没有 post 真实数据,我们必须对您的数据集结构做出一些假设。

数据

假设,你的数据看起来像

structure(list(Unique.ID = c(1, 2, 3, 4), Collection.Date1 = c("12/12/2020", 
"11/30/20", "1/20/21", "12/1/20"), Test.Result1 = c("positive", 
"negative", "negative", "positive"), Collection.Date2 = c("1/1/21", 
"1/8/21,1/20/21", "44011", "44018"), Test.Result2 = c("negative", 
"negative", "positive", "negative"), Collection.Date3 = c("44890", 
"2/10/21,3/10/21,4/10/21", "44007", "44064")), problems = structure(list(
    row = c(1L, 4L), col = c(NA_character_, NA_character_), expected = c("6 columns", 
    "6 columns"), actual = c("7 columns", "7 columns"), file = c("literal data", 
    "literal data")), row.names = c(NA, -2L), class = c("tbl_df", 
"tbl", "data.frame")), class = c("spec_tbl_df", "tbl_df", "tbl", 
"data.frame"), row.names = c(NA, -4L), spec = structure(list(
    cols = list(Unique.ID = structure(list(), class = c("collector_double", 
    "collector")), Collection.Date1 = structure(list(), class = c("collector_character", 
    "collector")), Test.Result1 = structure(list(), class = c("collector_character", 
    "collector")), Collection.Date2 = structure(list(), class = c("collector_character", 
    "collector")), Test.Result2 = structure(list(), class = c("collector_character", 
    "collector")), Collection.Date3 = structure(list(), class = c("collector_character", 
    "collector"))), default = structure(list(), class = c("collector_guess", 
    "collector")), skip = 2L), class = "col_spec"))

或为了更好的可读性

# A tibble: 4 x 6
  Unique.ID Collection.Date1 Test.Result1 Collection.Date2 Test.Result2 Collection.Date3       
      <dbl> <chr>            <chr>        <chr>            <chr>        <chr>                  
1         1 12/12/2020       positive     1/1/21           negative     44890                  
2         2 11/30/20         negative     1/8/21,1/20/21   negative     2/10/21,3/10/21,4/10/21
3         3 1/20/21          negative     44011            positive     44007                  
4         4 12/1/20          positive     44018            negative     44064 

注意:这个数据看起来还不错。我真的能想到更糟糕的数据。如果您的数据还有一些问题,以下工作流程可能会失败。

工作流程

我更喜欢使用 tidyverse 中包含的软件包,在本例中为 dplyrtidyrstringr

根据您的数据,我将执行以下步骤:

  1. 正在将数据转换为长格式。
  2. 分隔一个单元格中的日期,即将“2/10/21、3/10/21、4/10/21”分成单独的行。
  3. 将数据转换为宽格式,将日期和结果分别转换为一列。
  4. 整理你的约会对象,尤其是 Excel 风格的约会对象。

变成了这样的代码

library(tidyr)
library(dplyr)
library(stringr)

df %>% 
  pivot_longer(-Unique.ID, names_pattern="(.+)(\d)", names_to=c("name", "no") ) %>%
  mutate(value = str_split(value, ",\s*")) %>%
  unnest(value) %>%
  pivot_wider(values_fn=list) %>%
  unnest(c(Collection.Date, Test.Result)) %>%
  mutate(Collection.Date = coalesce(as.Date(Collection.Date, "%m/%d/%y"),
                                    as.Date(as.integer(Collection.Date), origin="1900-01-01"))) %>%
  suppressWarnings() %>%
  select(-no)

哪个returns

# A tibble: 15 x 3
   Unique.ID Collection.Date Test.Result
       <dbl> <date>          <chr>      
 1         1 2020-12-12      positive   
 2         1 2021-01-01      negative   
 3         1 2022-11-27      NA         
 4         2 2020-11-30      negative   
 5         2 2021-01-08      negative   
 6         2 2021-01-20      negative   
 7         2 2021-02-10      NA         
 8         2 2021-03-10      NA         
 9         2 2021-04-10      NA         
10         3 2021-01-20      negative   
11         3 2020-07-01      positive   
12         3 2020-06-27      NA         
13         4 2020-12-01      positive   
14         4 2020-07-08      negative   
15         4 2020-08-23      NA