簡體   English   中英

將列與dplyr和/或tidyr合並/排序

[英]Combine/sort columns with dplyr and/or tidyr

編輯:我已經嘗試了下面的解決方案,但是當我需要將因素轉換為字符並轉換回因素時,我會丟失一些重要信息。

有了這張桌子,我希望從中進行排序,

From    To  count
A       B     2
A       C     1
C       A     3
B       C     1

為此,

  From To count
1    A  B     2
2    A  C     4
3    B  C     1

到目前為止,我看到了兩種選擇,或者選擇兩種:

df[1:2] <- t(apply(df[1:2], 1, sort))    
aggregate(count ~ From + To, df, sum)

這很慢,因為我正在處理9.000.000觀測值。 或者只是將其轉換為iGraph網絡,然后合並邊。

g <- graph_from_data_frame(df, directed = TRUE, vertices = nodes)
g <- as.undirected(g, mode = "mutual", edge.attr.comb=list(weight = "sum"))

我遇到的兩個問題是,我提到的第一個選項實際上應該使用dplyr或tidyr,但到目前為止我仍不知道該怎么做。

網絡/ igraph選項比“ t(apply(”選項)要快,但是我仍然需要將圖形轉換回data.table進行進一步分析。

關於如何使用dplyr或tidyr運行“ t(apply(”)選項的任何想法嗎?

在基數R中,我們可以使用非公式接口將akrun的pminpmax建議與aggregate結合起來,如下所示:

aggregate(df$count, list(From=pmin(df$From, df$To), To=pmax(df$From, df$To)), sum)
  From To x
1    A  B 2
2    A  C 4
3    B  C 1

請注意,這要求df$Fromdf$To是字符向量,而不是因子。

時機
此方法比使用apply更快,因為它不涉及轉換為矩陣。 使用下面的較大數據集,有900萬個觀測值,在我的計算機上使用pminpmax進行aggregate完成時間為14.5秒,而OP的apply方法花費了442.2秒或30倍。

數據

df <-
structure(list(From = c("A", "A", "C", "B"), To = c("B", "C", 
"A", "C"), count = c(2L, 1L, 3L, 1L)), .Names = c("From", "To", 
"count"), class = "data.frame", row.names = c(NA, -4L))

更大的樣本數據

set.seed(1234)
df <- data.frame(From=sample(LETTERS, 9e6, replace=TRUE),
                 To=sample(LETTERS, 9e6, replace=TRUE),
                 count=sample(100, 9e6, replace=TRUE),
                 stringsAsFactors=FALSE)

我們可以使用pmin/pmax 應該更快

library(dplyr)
df1 %>% 
    group_by(From1 = pmin(From, To), To = pmax(From, To)) %>% 
    summarise(count = sum(count)) %>%
    rename(From = From1)
#  From    To count
#  <chr> <chr> <int>
#1     A     B     2
#2     A     C     4
#3     B     C     1
library(tidyverse)
cols_before_merge <- c("From", "To")
out_cols <- c("col_1", "col_2")

df <- tibble::tribble(
  ~From, ~To, ~count,
  "A", "B", 2,
  "A", "C", 1,
  "C", "A", 3,
  "B", "C", 1,
)

有了上述內容,我認為創建唯一鍵的方法可能是:

df_out <- df %>%
  dplyr::mutate(
    key = purrr::pmap_chr(
      list(From, To),
      ~ stringr::str_c(stringr::str_sort(c(...)), collapse = "_")
    )
  )

或者使用整潔的評估來實現更具編程性的方法:

merge_sort <- function(cols_values) {
  purrr::pmap_chr(
    cols_values,
    ~ stringr::str_c(stringr::str_sort(c(...)), collapse = "_")
  )
}

add_key <- function(cols) {
  # column names need to be evaluated using the dataframe as an environment
  cols_quosure <- rlang::enquo(cols)

  # column names should be symbols not strings
  cols_syms <- rlang::syms(cols)

  cols_values <- purrr::map(
    cols_syms,
    ~ rlang::eval_tidy(.x, rlang::quo_get_env(cols_quosure))
  )

  merge_sort(cols_values)
}



# Adding columns for key construction programmatically
df_out <- df %>%
  dplyr::mutate(key = add_key(cols_before_merge))

最后要計數並確保輸出列是因子(因為akrun指出行排序前后的因子水平很容易會有所不同)。

df_out %>%
  dplyr::count(key, name = "count") %>%
  tidyr::separate(key, sep = "_", into = out_cols) %>%
  dplyr::mutate_at(out_cols, as.factor)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM