【问题标题】:parse values based on groups in R基于 R 中的组解析值
【发布时间】:2019-08-27 14:46:05
【问题描述】:

我有一个非常大的数据集,其中的一个示例如下所示:

| Id | Name    | Start_Date | End_Date   |
|----|---------|------------|------------|
| 10 | Mark    | 4/2/1999   | 7/5/2018   |
| 10 |         | 1/1/2000   | 9/24/2018  |
| 25 |         | 5/3/1968   | 6/3/2000   |
| 25 |         | 6/6/2009   | 4/23/2010  |
| 25 | Anthony | 2/20/2010  | 7/21/2016  |
| 25 |         | 9/12/2014  | 11/26/2019 |

我需要根据 Id 解析来自 Name 列的名称,以便输出表如下所示:

| Id | Name    | Start_Date | End_Date   |
|----|---------|------------|------------|
| 10 | Mark    | 4/2/1999   | 7/5/2018   |
| 10 | Mark    | 1/1/2000   | 9/24/2018  |
| 25 | Anthony | 5/3/1968   | 6/3/2000   |
| 25 | Antony  | 6/6/2009   | 4/23/2010  |
| 25 | Anthony | 2/20/2010  | 7/21/2016  |
| 25 | Anthony | 9/12/2014  | 11/26/2019 |

如何实现如上所示的输出?我浏览了替代和解析函数,但无法理解它们如何应用于这个问题。

我的数据集是:

df=data.frame(Id=c("10","10","25","25","25","25"),Name=c("Mark","","","","Anthony",""),
              Start_Date=c("4/2/1999", "1/1/2000","5/3/1968","6/6/2009","2/20/2010","9/12/2014"),
              End_Date=c("7/5/2018","9/24/2018","6/3/2000","4/23/2010","7/21/2016","11/26/2019"))

【问题讨论】:

  • @AlexW 我已经纠正了错误
  • @akrun 我检查了尝试这两个代码。第一个给出错误:'arg' 应该是“down”,“up”之一,第二个不填写空白记录。
  • 我使用的是devel 版本的tidyr。如果你使用的是普通的%>% fill(Name) %>% fill(Name, .direction = "up"),它可能有.direction = 'downup'

标签: r grouping gsub substitution


【解决方案1】:

我们可以将空格 ("") 更改为 NA 并使用 fill 将 NA 元素替换为之前的非 NA 元素

library(dplyr)
library(tidyr)
df1 %>%      
   mutate(Name = na_if(Name, "")) %>%
   group_by(Id) %>%
   fill(Name, .direction = "down") %>%
   fill(Name, .direction = "up)
# A tibble: 6 x 4
# Groups:   Id [2]
#  Id    Name    Start_Date End_Date  
#  <chr> <chr>   <chr>      <chr>     
#1 10    Mark    4/2/1999   7/5/2018  
#2 10    Mark    1/1/2000   9/24/2018 
#3 25    Anthony 5/3/1968   6/3/2000  
#4 25    Anthony 6/6/2009   4/23/2010 
#5 25    Anthony 2/20/2010  7/21/2016 
#6 25    Anthony 9/12/2014  11/26/2019

tidyr (‘0.8.3.9000’) 的devel 版本中,这可以在单个fill 语句中完成,因为.direction = "downup" 也是一个选项

df1 %>%      
   mutate(Name = na_if(Name, "")) %>%
   group_by(Id) %>%
   fill(Name, .direction = "downup") 

或者另一种选择是按“Id”分组,并将mutate“名称”作为first非空白元素

df1 %>%
    group_by(Id) %>%        
    mutate(Name = first(Name[Name!=""])) 
# A tibble: 6 x 4
# Groups:   Id [2]
#  Id    Name    Start_Date End_Date  
#  <chr> <chr>   <chr>      <chr>     
#1 10    Mark    4/2/1999   7/5/2018  
#2 10    Mark    1/1/2000   9/24/2018 
#3 25    Anthony 5/3/1968   6/3/2000  
#4 25    Anthony 6/6/2009   4/23/2010 
#5 25    Anthony 2/20/2010  7/21/2016 
#6 25    Anthony 9/12/2014  11/26/2019

数据

df1 <- structure(list(Id = c("10", "10", "25", "25", "25", "25"), Name = c("Mark", 
"", "", "", "Anthony", ""), Start_Date = c("4/2/1999", "1/1/2000", 
"5/3/1968", "6/6/2009", "2/20/2010", "9/12/2014"), End_Date = c("7/5/2018", 
"9/24/2018", "6/3/2000", "4/23/2010", "7/21/2016", "11/26/2019"
)), class = "data.frame", row.names = c(NA, -6L))

【讨论】:

  • 上面的代码用错误的名字填空。我希望空白处填充基于 id 的名称。例如 id="10" 有 "Name=Mark",所以它应该用 Mark 填充 Name 列中的所有空白记录。所以这对 Mark 来说只有 2 条记录。你能看看吗?
  • @hk2 我觉得你只需要在群里加Id就行了。更新答案
  • 非常感谢!它以“向上”和“向下”作为方向。
【解决方案2】:

使用DF在最后的注释中重复定义,将Name的每个零长度元素替换为NA,然后使用na.omit获取唯一的非NA用于填充。我们假设每个Id 只有一个非 NA,问题就是这种情况。如果不是,我们可以用function(x) unique(na.omit(x)) 替换na.omit,假设非NA 在Id 中都是相同的。不使用任何包。

transform(DF, Name = ave(replace(Name, !nzchar(Name), NA), Id, FUN = na.omit))

给予:

  Id    Name Start_Date   End_Date
1 10    Mark   4/2/1999   7/5/2018
2 10    Mark   1/1/2000  9/24/2018
3 25 Anthony   5/3/1968   6/3/2000
4 25 Anthony   6/6/2009  4/23/2010
5 25 Anthony  2/20/2010  7/21/2016
6 25 Anthony  9/12/2014 11/26/2019

na.strings

如果我们首先确保Name 的零长度元素是NA,我们可以稍微简化一下。我们将注释中的read.table 行替换为下面的第一行。那么使用na.locf0就可以了。

DF <- read.table(text = Lines, header = TRUE, as.is = TRUE, sep = "|", 
  strip.white = TRUE, na.strings = "")

transform(DF, Name = ave(Name, Id, FUN = na.omit))

注意

可重现形式的输入:

Lines <- "
 Id | Name    | Start_Date | End_Date   
 10 | Mark    | 4/2/1999   | 7/5/2018   
 10 |         | 1/1/2000   | 9/24/2018  
 25 |         | 5/3/1968   | 6/3/2000   
 25 |         | 6/6/2009   | 4/23/2010  
 25 | Anthony | 2/20/2010  | 7/21/2016  
 25 |         | 9/12/2014  | 11/26/2019"
DF <- read.table(text = Lines, header = TRUE, as.is = TRUE, sep = "|", strip.white = TRUE)

【讨论】:

  • 这不会产生所需的输出。名称应根据其 id 填写。因此,Mark 应该只填充两次,而 Anthony 应该填充 4 次。您能否参考示例输出以了解如何实现?提前致谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多