【问题标题】:cross-join ids to extract data from other columns within the same R data frame交叉连接 id 从同一 R 数据框中的其他列中提取数据
【发布时间】:2020-07-24 01:52:05
【问题描述】:

我有一个像这样的 R 数据框(但数据不会按任何列排序):

ppl <- structure(list(id = c("I0000", "I0001", "I0002", "I0003", "I0004","I0005", "I0006", "I0007", "I0008", "I0009"), Birth_Date = structure(c(NA, 517, -10246, -8723, 2349, -25125, NA, -12141, 2349, NA), class = "Date"), Father_id = c(NA, "I0002", "I0005", "I0037", "I0002", "I0018", "I0056", "I0005", "I0002", "I0005"), Mother_id = c(NA, "I0003", "I0006", "I0038", "I0003", "I0019", "I0057", "I0006", "I0003", "I0006"), marriage = structure(c(NA_real_, NA_real_, NA_real_, NA_real_, NA_real_, -12119, -12119, NA_real_, NA_real_, NA_real_), class = "Date")), row.names = c(NA, -10L), class = c("tbl_df", "tbl", "data.frame"))

> ppl
# A tibble: 10 x 5
   id    Birth_Date Father_id Mother_id marriage  
   <chr> <date>     <chr>     <chr>     <date>    
 1 I0000 NA         NA        NA        NA        
 2 I0001 1971-06-02 I0002     I0003     NA        
 3 I0002 1941-12-13 I0005     I0006     NA        
 4 I0003 1946-02-13 I0037     I0038     NA        
 5 I0004 1976-06-07 I0002     I0003     NA        
 6 I0005 1901-03-19 I0018     I0019     1936-10-27        
 7 I0006 NA         I0056     I0057     1936-10-27        
 8 I0007 1936-10-05 I0005     I0006     NA        
 9 I0008 1976-06-07 I0002     I0003     NA        
10 I0009 NA         I0005     I0006     NA    

孩子和父母的关系是通过他们不同的ID来建立的。

对于没有marriage日期值的每个人(id),我想根据Birth_date估计该列的日期值> 他/她的第一个孩子(当然这只是一个假设,因为对于某些人来说 Birth_Date 不可用)。

因此,在本例中,一些将获得结婚日期的个人将是 I0002 和 I0003(计算出的结婚将是“1971-06-02”行3 和 4,因为它是 Father_id=='I0002' 和 Mother_id=='I0003' 的 3 个人中的最小 Birth_Date -第 2、5 和 9 行-)。

同样,个人 I0005 和 I0006 会得到结婚日期“1936-10-05”,这是他们孩子的最小已知 Birth_Date (I0002, I0007 和 I0009 - NA 作为 Birth_Date-)。 但是在这种情况下,不应考虑所有子 Birth_Date 值,因为数据框已经具有这些个体的真实 marriage_date 值( “1936-10-27”)。

如您所见,数据帧结构无需更改(相同的行数和相同的列;但最后一个使用 Date 值更新了一些 NA)。

预期结果:

> ppl
# A tibble: 10 x 5
   id    Birth_Date Father_id Mother_id marriage  
   <chr> <date>     <chr>     <chr>     <date>    
 1 I0000 NA         NA        NA        NA        
 2 I0001 1971-06-02 I0002     I0003     NA        
 3 I0002 1941-12-13 I0005     I0006     1971-06-02
 4 I0003 1946-02-13 I0037     I0038     1971-06-02
 5 I0004 1976-06-07 I0002     I0003     NA        
 6 I0005 1901-03-19 I0018     I0019     1936-10-27
 7 I0006 NA         I0056     I0057     1936-10-27
 8 I0007 1936-10-05 I0005     I0006     NA        
 9 I0008 1976-06-07 I0002     I0003     NA        
10 I0009 NA         I0005     I0006     NA        

是否有可能避免使用迭代数据框的函数来完成此任务?

我知道有一些库处理连接,就像提到的那些 here。但我仍然不知道如何使用它们来完成这项任务。

我正在考虑逐行计算(每次迭代一个结婚日期),但我想必须有一些更快的方法来做到这一点。 请详细说明您的答案,因为我是一个完整的 R 新手。这不仅仅是让它工作的问题,而是理解它是如何工作的。

【问题讨论】:

    标签: r self-join minimum as.date


    【解决方案1】:

    我们可以为每个父亲和母亲选择一个最小值为Birth_Date 的行,并加入数据框本身。

    library(dplyr)
    
    ppl %>%
       #Keep only NA values
       filter(is.na(marriage)) %>%
       #For each father and mother
       group_by(Father_id, Mother_id) %>%
       #Select the minimum date
       slice(which.min(Birth_Date)) %>%
       #Get father and mother in same column
       tidyr::pivot_longer(cols = c(Father_id, Mother_id)) %>%
       #rename Birth_Date to marriage and select it with value
       select(marriage = Birth_Date, value) %>%
       #Join with the dataframe itself
       right_join(ppl, by = c('value' = 'id')) %>%
       #If marriage data is already present select that
       mutate(marriage_date = coalesce(marriage.y, marriage.x)) %>%
       #select only columns needed. 
       select(id = value, Birth_Date, Father_id, Mother_id, marriage_date)
    
       id    Birth_Date Father_id Mother_id marriage_date
       <chr> <date>     <chr>     <chr>     <date>       
     1 I0000 NA         NA        NA        NA           
     2 I0001 1971-06-02 I0002     I0003     NA           
     3 I0002 1941-12-13 I0005     I0006     1971-06-02   
     4 I0003 1946-02-13 I0037     I0038     1971-06-02   
     5 I0004 1976-06-07 I0002     I0003     NA           
     6 I0005 1901-03-19 I0018     I0019     1936-10-27   
     7 I0006 NA         I0056     I0057     1936-10-27   
     8 I0007 1936-10-05 I0005     I0006     NA           
     9 I0008 1976-06-07 I0002     I0003     NA           
    10 I0009 NA         I0005     I0006     NA   
    

    【讨论】:

    • 谢谢@ronak-shah ...我猜你没有意识到我编辑了我的原始问题(数据框可能已经有一些 marriage 日期值;我只需要计算当它们是 NA 时)。但我正在尝试你的方法(我是 R 新手)。现在,我收到了这个Error: 'pivot_longer' is not an exported object from 'namespace:tidyr' ...关于原因的任何线索?
    • 是的,更新 tidyrpivot_longer 来自更新版本的 tidyr。如果有一些marrage_date 已经存在,那么你可以filter 只有NA 值。
    • 您介意编辑您的答案,保留所有原始数据框列并添加该过滤器吗?我不明白它是如何工作的以便自己修改它,所以如果你能解释一下你答案的每一行,我将不胜感激
    • @abu 好的,我更新了答案,还在答案的每一行中包含了解释。
    • 非常感谢,现在完美了!!只是好奇:在没有用户定义的循环函数的情况下,仅使用 Rbase 命令(没有 tidyr)是否可以以某种方式完成这项任务?
    猜你喜欢
    • 1970-01-01
    • 2016-12-11
    • 1970-01-01
    • 2021-05-27
    • 2017-11-21
    • 1970-01-01
    • 1970-01-01
    • 2018-09-13
    • 2019-03-30
    相关资源
    最近更新 更多