Объединение фрейма данных на основе данных в каждом столбце в dplyr - PullRequest
2 голосов
/ 17 апреля 2019

Скажем, у меня есть некоторые сетевые данные, как показано ниже:

col_a <- c("A","B","C")
col_b <- c("B","A","A")
val <- c(1,3,7)
df <- data.frame(col_a, col_b, val)
df

  col_a col_b val
1     A     B   1
2     B     A   3
3     C     A   7

Это может быть сеть, а val может быть весом ребер между ними.Однако я хочу добавить вес между A и B и B и A, чтобы получить следующее:

new_col_a <- c("A", "A")
new_col_b <- c("B", "C")
new_val <- c(4,7)
want_df <- data.frame(new_col_a, new_col_b, new_val)
want_df

  new_col_a new_col_b new_val
1         A         B       4
2         A         C       7

Есть ли способ сделать это в dplyr?

Ответы [ 3 ]

3 голосов
/ 17 апреля 2019

Одна dplyr возможность может быть:

df %>%
 mutate_if(is.factor, as.character) %>%
 group_by(grp = paste(pmin(col_a, col_b), pmax(col_a, col_b), sep = "_")) %>%
 summarise(val = sum(val))

  grp     val
  <chr> <dbl>
1 A_B       4
2 A_C       7

Или с tidyverse, используя аналогичную идею как @Sonny:

df %>%
 mutate_if(is.factor, as.character) %>%
 nest(col_a, col_b) %>%
 group_by(grp = unlist(map(data, function(x) paste(sort(x), collapse = "_")))) %>%
 summarise(val = sum(val))

Если вы хотите также отделитьэто в два столбца (этот шаг также потребует tidyr):

df %>%
 mutate_if(is.factor, as.character) %>%
 group_by(grp = paste(pmin(col_a, col_b), pmax(col_a, col_b), sep = "_")) %>%
 summarise(val = sum(val)) %>%
 separate(grp, c("new_col_a", "new_col_b"), sep = "_")

  new_col_a new_col_b   val
  <chr>     <chr>     <dbl>
1 A         B             4
2 A         C             7

Или в случае второй возможности:

df %>%
 mutate_if(is.factor, as.character) %>%
 nest(col_a, col_b) %>%
 group_by(grp = unlist(map(data, function(x) paste(sort(x), collapse = "_")))) %>%
 summarise(val = sum(val)) %>%
 separate(grp, c("new_col_a", "new_col_b"), sep = "_")
2 голосов
/ 17 апреля 2019

Вы можете использовать dplyr для этого

df <- data.frame(col_a, col_b, val, stringsAsFactors = F)

library(dplyr)
library(tidyr)
df %>% 
  mutate(
    pair = purrr::pmap_chr(
      .l = list(from = col_a, to = col_b),
      .f = function(from, to) paste(sort(c(from, to)), collapse = "_")
    )
  ) %>%
  group_by(pair) %>%
  summarise(new_val = sum(val)) %>%
  separate(pair, c("new_col_a", "new_col_b"), sep = "_")
  # A tibble: 2 x 3
  new_col_a new_col_b new_val
  <chr>     <chr>       <dbl>
1 A         B               4
2 A         C               7

Аналогично одному из моих предыдущих ответов

0 голосов
/ 17 апреля 2019

Если вы сначала сделаете ваши данные аккуратными, длинными, тогда это станет немного проще. Преобразуйте в long, сортируйте метки столбцов независимо от вашей val ues, группы, суммируйте ваши val:

df %>%
    gather(grp,col,-val) %>%
    mutate(col=col[order(col,grp)]) %>%
    spread(grp,col) %>%
    group_by(col_a, col_b) %>%
    summarize(val = sum(val))

## A tibble: 2 x 3
## Groups:   col_a [?]
#  col_a col_b   val
#  <chr> <chr> <dbl>
#1 A     B         4
#2 A     C         7
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...