web-dev-qa-db-ja.com

行が互いに素でNAを含むデータフレーム内の行をマージします

2つの行があるデータフレームがあります。

| code | name  | v1 | v2 | v3 | v4 |
|------|-------|----|----|----|----|
| 345  | Yemen | NA | 2  | 3  | NA |
| 346  | Yemen | 4  | NA | NA | 5  |

これらの2つの行をマージする簡単な方法はありますか? 「346」の名前を「345」に変更すると、作業が簡単になりますか?

14
LukasKawerau

aggregate を使用できます。列nameで同じ値の行をマージするとします。

_aggregate(x=DF[c("v1","v2","v3","v4")], by=list(name=DF$name), min, na.rm = TRUE)
   name v1 v2 v3 v4
1 Yemen  4  2  3  5
_

これはSQLSELECT name, min(v1) GROUP BY nameのようなものです。 min関数は任意です。maxまたはmeanを使用することもできます。これらはすべて、NAから非NA値を返し、_na.rm = TRUE_。 (SQLのようなcoalesce()関数は、Rに存在する場合、より良い音になります。)

ただし、最初に、特定のnameのすべての非NA値が同一であるかどうかを確認する必要があります。たとえば、aggregateminmaxの両方で実行して比較するか、rangeで実行します。

最後に、v1-4だけでなく多くの変数がある場合は、DF[,!(names(DF) %in% c("code","name"))]を使用して列を定義できます。

10
Daniel Sparing

完全を期すためにdplyr&_data.table_ソリューションを追加

dplyr::coalesce()を使用

_library(dplyr)

sum_NA <- function(x) {if (all(is.na(x))) x[NA_integer_] else sum(x, na.rm = TRUE)}

df %>% 
  group_by(name) %>% 
  summarise_all(sum_NA)
#> # A tibble: 1 x 6
#>   name   code    v1    v2    v3    v4
#>   <fct> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 Yemen   691     4     2     3     5

# Ref: https://stackoverflow.com/a/45515491
# Supply lists by splicing them into dots:
coalesce_by_column <- function(df) {
  return(dplyr::coalesce(!!! as.list(df)))
}

df %>% 
  group_by(name) %>% 
  summarise_all(coalesce_by_column)
#> # A tibble: 1 x 6
#>   name   code    v1    v2    v3    v4
#>   <fct> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 Yemen   345     4     2     3     5
_

_data.table_を使用

_# Ref: https://stackoverflow.com/q/28036294/
library(data.table)
setDT(df)[, lapply(.SD, na.omit), by = name]
#>     name code v1 v2 v3 v4
#> 1: Yemen  345  4  2  3  5
#> 2: Yemen  346  4  2  3  5

setDT(df)[, code := NULL][, lapply(.SD, na.omit), by = name]    
#>     name v1 v2 v3 v4
#> 1: Yemen  4  2  3  5

setDT(df)[, code := NULL][, lapply(.SD, sum_NA), by = name]
#>     name v1 v2 v3 v4
#> 1: Yemen  4  2  3  5
_
2
Tung