Данные у меня есть:
Что я хочу:
Код, который я попытался:
library(readxl)
library(dplyr)
library(stringr)
data1 <- read_excel("testing.xlsx")
data2 <- data1 %>%
group_by(A) %>%
group_by(B) %>%
mutate(Group = cur_group_id()) %>%
ungroup()
Что я получаю от этого кода:
Обновлено: я получаю сообщение об ошибке: «Невозможно предоставить «.by», если «.data» представляет собой сгруппированный фрейм данных». за все комментарии ниже. Исходные данные, которыми я манипулирую, были соединены слева, а затем сгруппированы. Как мне к этому подойти?
Абсолютно! Если все значения B в разных группах A совпадают, то они находятся в одной группе. В этом случае все значения B (c и e) совпадают для 2 и 5. Надеюсь, это имеет смысл.
Хорошо! Я попробую.
Попробовал обновить, но похоже, что он уже актуален.
вам следует использовать .by =
в исходном несгруппированном кадре данных, т. е. data1
Можно ли использовать предоставленный вами код в сгруппированном наборе? Несгруппированный фрейм данных — это не те данные, которые я хотел сгруппировать.
Вы можете попробовать ниже
library(dplyr)
df %>%
left_join(
(.) %>%
summarise(group = as.factor(toString(sort(B))), .by = A) %>%
mutate(group = as.integer(group))
)
или вы можете дополнительно использовать membership
из пакета igraph
library(dplyr)
library(igraph)
df %>%
mutate(group = {
(.) %>%
graph_from_data_frame() %>%
components() %>%
membership()
}[B])
который дает
A B group
1 1 a 1
2 2 c 2
3 2 e 2
4 3 f 3
5 4 h 4
6 5 c 2
7 5 e 2
igraph
)df %>%
graph_from_data_frame() %>%
plot()
показывает группы
Что делает left_join((.) %>% ...)
?
@AzorAhai-him- позвольте df
левой кнопкой мыши присоединиться к суммарному групповому кадру данных.
О, я понимаю, это, вероятно, могло бы иметь какое-то объяснение.
library(dplyr)
data1 |>
mutate(group = paste(sort(B), collapse = ""), .by = A) |>
mutate(group = cur_group_id(), .by = group)
Выход
A B group
1 1 a 1
2 2 c 2
3 2 e 2
4 3 f 3
5 4 h 4
6 5 c 2
7 5 e 2
Была такая же идея, но потом понял, что она работает только в том случае, если A упорядочена и представляет собой просто числа 1:n. В противном случае это потерпит неудачу, поскольку не принимает во внимание значения A.
@Onyambu, можешь привести пример? Например, он все еще работает с этим фреймом данных (где A не упорядочен, а не просто числа). structure(list(A = c("1", "5A", "5A", "3", "4", "2B", "2B"), B = c("a", "c", "e", "f", "h", "c", "e")), class = "data.frame", row.names = c(NA, -7L))
Ваш пример явно возвращает 1,2,2,3,4,2,2 вместо 1,5A,5A,3,4,5A,5A
@Onyambu да, потому что это явно то, чего хочет ОП. Если они хотят вернуть исходные группы, они могут это сделать A[cur_group_id()]
, но я не думаю, что они этого ищут.
На самом деле A[cur_group_id()]
не сработает
Ох, я понимаю, что ты имеешь в виду. Я думал, что OP хотел группировать, как указано буквой A, из-за их комментариев к решению Thomasiscoding.
df %>%
mutate(group = toString(B), .by=A)%>%
mutate(group = A[match(group, group)], .by=group)
A B group
1 1 a 1
2 2 c 2
3 2 e 2
4 3 f 3
5 4 h 4
6 5 c 2
7 5 e 2
Вы можете сделать это:
setDT(df)[df[, .(B=paste0(sort(B), collapse = "")),A][, Group:=min(A), B], on = "A", .(A, B, Group)]
Выход:
A B Group
<int> <char> <int>
1: 1 a 1
2: 2 c 2
3: 2 e 2
4: 3 f 3
5: 4 h 4
6: 5 c 2
7: 5 e 2
Но, как отмечали другие, это работает только потому, что B можно легко отсортировать и склеить, а A является числовым.
Можете ли вы объяснить, как вы пытаетесь сгруппироваться? Например, почему «2 c», «5 c» и «5 e» находятся в одной группе? Ваш второй
group_by
просто перезаписывает первый, поскольку аргументом по умолчанию является.add = FALSE
.