【问题标题】:Advice on Logical Data Tidying for a work project工作项目的逻辑数据整理建议
【发布时间】:2021-06-14 16:37:41
【问题描述】:

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

我正在尝试整理我的数据。我的想法是将所有收集日期放在一列中。这是我卡住的地方。我可以使用 pivot_longer() bc 不是所有的列都是相同的类型。我无法将 excel 日期转换为 R 日期而无需摆脱字符串列表。而且我无法摆脱字符串列表,因为我遇到了错误:长度不兼容。我认为我的逻辑流程是错误的,任何为我指明正确方向的建议都会有所帮助。在我的流程正确后,我可以查找编码。

我有什么:

  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

如果我尝试先将所有内容都转换为日期,则会遇到字符串错误。当我尝试扩展字符串时,由于它们的长度不同,这样做会出错。

【问题讨论】:

  • 尝试使用tidyr包中的gather()函数
  • pivot_longer() 是 tidyr 中 gather() 的新/改进版本。

标签: r tidyr


【解决方案1】:

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

数据

假设,您的数据看起来像

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)

返回

# 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 

【讨论】:

  • 马丁,这正是我想要的。非常感谢。这是我的数据的一个非常简化的版本。我实际上有 8 个收集日期、8 个实验室、8 个测试类型、8 个测试结果等列。共有 54 列。我认为它类似于时间序列数据。我在理解 names_pattern 参数以及如何将特定列映射到新列时遇到了一些麻烦。你怎么告诉它,所有 8 个收集日期列都到收集日期,所有 8 个测试结果列都到测试结果,等等。我总共有 7 个要连接。
  • 我也在网上找到了这个,也差不多。 df_raw %&gt;% pivot_longer(everything(), names_to = c("set", ".value"), names_pattern = "(.+)_(.+)" )
  • 不看实际数据很难给出答案。 names_pattern="(.+)(\\d) 查找以单个数字结尾的任何类型的字符串,并通过 names_to=c("name", "no") 两列将其拆分:第一个 (.+) 中的部分转到“名称”,@ 987654333@ 部分转到“否” .
  • 您可以尝试逐步运行显示的代码并查看和转换。也许您可以将这种方法推广到您的真实数据上。
  • 你是个天才 :-) 我现在明白发生了什么。您将所有内容放在一列中,然后展开列表,然后将其扩大以形成多列。它现在挂断了 unnest() 。错误是:UseMethod(“unnest”)中的错误没有适用于“unnest”的方法应用于“list”类的对象。此外,现在使用 unnest() 时需要“cols”。我将开始着手让这个工作,然后使用 pivot_wider()。非常感谢您为我指明了正确的方向!
猜你喜欢
  • 2018-01-14
  • 2011-11-14
  • 2019-06-21
  • 2020-09-13
  • 2019-11-29
  • 1970-01-01
  • 1970-01-01
  • 2021-11-28
  • 2011-10-06
相关资源
最近更新 更多