【问题标题】:Concatenate Rows If Value of Another Column In Next Row Is Empty如果下一行中另一列的值为空,则连接行
【发布时间】:2019-01-31 20:57:45
【问题描述】:

我有一个数据集,如下表Input 所示。我想组合Input 表的行(4,5,6)、行(8,9) 和行(11,12),以便它们共享相同的ID,如下面Output 表中的行4,8 and 11 所示。

我试过merge(),但没有按预期工作。这里的关键是具有唯一值的ID 列。

关于如何有效地实现这一点有什么建议吗?

输入

Row Name Val1 Val2 Unit ID
1        -0.5 5.5   V   UI-001
2    a   -0.5 2.5   V   UI-002
3    b   -0.5 5.5   V   UI-003
4    c   -0.5 5.5   V   UI-004
5    d              
6    e              
7        -45 125  Ohms  UI-005
8    f     2        kV  UI-006
9    g              
10   h   500        V   UI-007
11   i    15        kV  UI-008
12   j              
13   k                  UI-009

输入的dput()

structure(list(Name = c(NA, "a", "b", "c", "d", "e", NA, "f", 
"g", "h", "i", "j", "k"), Val1 = c(-0.5, -0.5, -0.5, -0.5, NA, 
NA, -45, 2, NA, 500, 15, NA, NA), Val2 = c(5.5, 2.5, 5.5, 5.5, 
NA, NA, 125, NA, NA, NA, NA, NA, NA), Unit = c("V", "V", "V", 
"V", NA, NA, "Ohms", "kV", NA, "V", "kV", NA, NA), ID = c("UI-001", 
"UI-002", "UI-003", "UI-004", NA, NA, "UI-005", "UI-006", NA, 
"UI-007", "UI-008", NA, "UI-009")), row.names = c(NA, -13L), class = 
c("tbl_df", "tbl", "data.frame"))

输出

Row Name Val1 Val2 Unit ID
1        -0.5 5.5   V   UI-001
2    a   -0.5 2.5   V   UI-002
3    b   -0.5 5.5   V   UI-003
4    cde -0.5 5.5   V   UI-004      
5        -45  125 Ohms  UI-005
6    fg    2        kV  UI-006  
7    h   500        V   UI-007
8    ij   15        kV  UI-008
9    k                  UI-009

输出的dput()

structure(list(Name = c(NA, "a", "b", "cde", NA, "fg", "h", "ij", 
"k"), Val1 = c(-0.5, -0.5, -0.5, -0.5, -45, 2, 500, 15, NA), 
Val2 = c(5.5, 2.5, 5.5, 5.5, 125, NA, NA, NA, NA), Unit = c("V", 
"V", "V", "V", "Ohms", "kV", "V", "kV", NA), ID = c("UI-001", 
"UI-002", "UI-003", "UI-004", "UI-005", "UI-006", "UI-007", 
"UI-008", "UI-009")), row.names = c(NA, -9L), class = c("tbl_df", 
"tbl", "data.frame"))

【问题讨论】:

  • 您可以使用dput(your_input_df) 以r 可读的形式提供您的输入表吗?由于所有缺失值,很难解析您提供的输入。
  • @MattSummersgill - 我已添加 dput() 值,请检查。

标签: r concatenation


【解决方案1】:

我们可能会使用

out <- df[!is.na(df$ID), ]
out$Name[!is.na(out$Name)] <- tapply(df$Name, cumsum(!is.na(df$ID)), paste, collapse = "")[!is.na(out$Name)]
out
#    Name  Val1  Val2 Unit     ID
# 1  <NA>  -0.5   5.5    V UI-001
# 2     a  -0.5   2.5    V UI-002
# 3     b  -0.5   5.5    V UI-003
# 4   cde  -0.5   5.5    V UI-004
# 7  <NA> -45.0 125.0 Ohms UI-005
# 8    fg   2.0    NA   kV UI-006
# 10    h 500.0    NA    V UI-007
# 11   ij  15.0    NA   kV UI-008
# 13    k    NA    NA <NA> UI-009

第一行删除了IDNA 的所有行。那么

tapply(df$Name, cumsum(!is.na(df$ID)), paste, collapse = "")
#     1     2     3     4     5     6     7     8     9 
#  "NA"   "a"   "b" "cde"  "NA"  "fg"   "h"  "ij"   "k" 

Name!is.na(out$Name) 构造正确的值会告诉我们应该修改out 的哪些行(这是必需的,因为"NA"NA 不同)。

【讨论】:

  • .@JuliusVainora - 这对我来说R 有点令人困惑。我作为示例显示的数据有空单元格。但是你假设那些是NA。根据我的小R 经验,它们都是两个不同的值,is.na() 在实际数据为空单元格时将不起作用。请纠正我。
  • .@JuliusVainora - 忘了感谢您的解决方案。我会接受这个作为答案。是否可以用我想要组合的两行的值来添加空间?示例:f g 而不是 fg 在行 8 在列 name
  • @ChetanArvindPatil,我不认为它们是NA,您的dput 输出将它们作为NA,通常这是一件好事。例如,拥有"" 将允许Val1 是数字。如果你真的想要"",它不是“空”,它是一个长度为零的字符,你可以做df[is.na(df)] &lt;- ""。当然,只需将sep = "" 替换为sep = " "
  • .@JuliusVainora - 谢谢。是否可以用我想要组合的两行的值来添加空间?示例:f g 而不是 fg 行中的 8 列名。
  • @ChetanArvindPatil,是的,我的意思是说sep = " " 而不是sep = ""
【解决方案2】:

还有dplyr 的可能性:

df %>%
 mutate(grp = ifelse((is.na(lead(ID, default = last(ID))) & !is.na(ID)) | is.na(ID), 1, 0),
        grp = ifelse(grp != 0, cumsum(grp != lag(grp, 1, default = first(grp))), 0)) %>%
 group_by(grp) %>%
 mutate(Name = ifelse(grp != 0, paste(Name, collapse = ""), Name)) %>%
 filter(!is.na(ID)) %>%
 ungroup() %>%
 select(-grp)

  Name      Val1   Val2 Unit  ID    
  <chr>    <dbl>  <dbl> <chr> <chr> 
1 <NA>    -0.500   5.50 V     UI-001
2 a       -0.500   2.50 V     UI-002
3 b       -0.500   5.50 V     UI-003
4 cde     -0.500   5.50 V     UI-004
5 <NA>   -45.0   125.   Ohms  UI-005
6 fg       2.00   NA    kV    UI-006
7 h      500.     NA    V     UI-007
8 ij      15.0    NA    kV    UI-008
9 k       NA      NA    <NA>  UI-009

首先,它为“ID”上的 NA 案例和“ID”上的最后一个非 NA 案例在这些 NA 案例之前创建一个分组变量。然后,它按该分组变量进行分组,并将“名称”中的值组合为一个。最后过滤掉“ID”为NA的情况,去掉冗余的分组变量。

或者同样使用data.table中的rleid()来更方便地创建分组变量:

df %>%
 mutate(grp = ifelse((is.na(lead(ID, default = last(ID))) & !is.na(ID)) | is.na(ID), 1, 0),
        grp = ifelse(grp == 1, rleid(grp), grp)) %>%
 group_by(grp) %>%
 mutate(Name = ifelse(grp != 0, paste(Name, collapse = ""), Name)) %>%
 filter(!is.na(ID)) %>%
 ungroup() %>%
 select(-grp)

或者使用fill()的不同可能性:

df %>%
 mutate(ID_temp = ID) %>%
 fill(ID, .direction = "down") %>%
 group_by(ID) %>%
 mutate(Name = paste(Name, collapse = "")) %>%
 filter(!is.na(ID_temp)) %>%
 select(-ID_temp)

在这里,您将使用前一个非缺失值填充缺失的“ID”值,按它进行分组,然后组合每个组的行。

【讨论】:

    猜你喜欢
    • 2020-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-04
    • 1970-01-01
    相关资源
    最近更新 更多