Объединить строки, если значение другого столбца в следующей строке пусто - PullRequest
0 голосов
/ 31 января 2019

У меня есть набор данных, как показано в таблице Input ниже.Я хочу объединить строки (4,5,6), строки (8,9) и строки (11,12) таблицы Input так, чтобы они имели одинаковые значения ID, как показано в строке 4,8 and 11 в таблице Output ниже.

Я пытался 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"))

Output

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"))

Ответы [ 2 ]

0 голосов
/ 01 февраля 2019

Также возможна 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

Сначала создается группирующая переменная для случаев NA по «ID» и последних не-NA случаев по «ID» перед этими случаями NA.Затем он группируется по этой переменной группировки и объединяет значения из «Имя» в одно.Наконец, он отфильтровывает случаи, когда «ID» равен NA, и удаляет избыточную переменную группировки.

Или то же самое, используя rleid() из data.table для более удобного создания переменной группировки:

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» предыдущим не пропущенным значением, группируете его, а затем объединяете строкипо группам.

0 голосов
/ 01 февраля 2019

Мы можем использовать

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

В первой строке удаляются все строки, где ID равно NA.Тогда

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).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...