有了这个表,我希望它可以从中排序,
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以进行进一步分析。
关于如何运行“t(apply(”选项与dplyr或tidyr?
)的任何想法答案 0 :(得分:3)
在基础R中,我们可以使用非公式界面将akrun的pmin
和pmax
建议与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$From
和df$To
是字符向量,而不是因素。
<强>定时强>
此方法比使用apply
更快,因为它不涉及转换为矩阵。使用下面的大数据集,有900万观测值,使用pmin
和pmax
与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)
答案 1 :(得分:2)
我们可以使用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
答案 2 :(得分:0)
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 = "_")
)
)
或者是使用tidy evaluation的更具编程性的方法:
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)