Рассмотрим этот пример данных:
library(tidyverse)
dt <- tibble(Poison = c('Arsenic', 'Arsenic in Wine', 'Cyanide', 'Cyanide and Sugar'),
Result = c('Death', 'Death With Class', 'Death', 'Death'))
Я хочу создать столбец, который присваивает каждой группе идентификационный номер. Однако я хочу, чтобы яды были сгруппированы вместе по строковому обнаружению, то есть «Мышьяк» и «Мышьяк в вине» были одной группой, а «Цианид» и «Цианид и сахар» — другой группой. В настоящее время R считает, что каждая группа является своей собственной, как таковая:
dt <- dt %>%
group_by(Poison) %>%
mutate(Group = n())
# A tibble: 4 × 3
# Groups: Poison [4]
Poison Result Group
<chr> <chr> <int>
1 Arsenic Death 1
2 Arsenic in Wine Death With Class 1
3 Cyanide Death 1
4 Cyanide and Sugar Death 1
Я хочу, чтобы «Мышьяк» и «Мышьяк в вине» относились к группе 1, а «Цианид» и «Цианид и сахар» - к группе 2. Есть идеи?
Знаете ли вы заранее все группы? То есть у вас есть (где-то) c("Arsenic", "Cyanide")?





Комбинация case_when и grepl может быть полезна:
dt %>%
mutate(Group = case_when(
grepl("Arsenic", Poison) ~ 1,
grepl("Cyanide", Poison) ~ 2
))
# A tibble: 4 × 3
Poison Result Group
<chr> <chr> <dbl>
1 Arsenic Death 1
2 Arsenic in Wine Death With Class 1
3 Cyanide Death 2
4 Cyanide and Sugar Death 2
Если вы не хотите записывать Пуассон, это может быть полезно:
dt %>%
mutate(Group = sub(" .*", "", Poison) %>%
as.factor %>%
as.integer())
Я определенно не хочу расписывать яды, так что спасибо за это предостережение! Отлично работает, большое спасибо!
Если мы заранее знаем вектор «кратчайших шаблонов»,
vec <- c("Arsenic", "Cyanide")
### or perhaps this for an automated approach
vec <- unique(sub(" .*", "", dt$Poison))
тогда мы можем сделать:
dt |>
mutate(grp = apply(sapply(vec, grepl, Poison), 1, function(z) which(z)[1]))
# # A tibble: 4 × 3
# Poison Result grp
# <chr> <chr> <int>
# 1 Arsenic Death 1
# 2 Arsenic in Wine Death With Class 1
# 3 Cyanide Death 2
# 4 Cyanide and Sugar Death 2
Используйте код с осторожностью! т.е. набор данных от малого до среднего. Огромный набор данных не будет работать, поскольку adist создает матрицу n by n столбца Poison. т.е. сравнение одного элемента с остальными.
dt %>%
mutate(group = (!adist(Poison, partial = TRUE)) %>%
igraph::graph_from_adjacency_matrix()%>%
igraph::components()%>%
getElement('membership'))
# A tibble: 4 × 3
Poison Result group
<chr> <chr> <dbl>
1 Arsenic Death 1
2 Arsenic in Wine Death With Class 1
3 Cyanide Death 2
4 Cyanide and Sugar Death 2
Если у вас вообще есть вектор необходимых групп, вы можете сделать:
vec <- c("Arsenic", "Cyanide")
transform(dt, group = max.col(-t(adist(vec, Poison, partial = TRUE))))
Poison Result group
1 Arsenic Death 1
2 Arsenic in Wine Death With Class 1
3 Cyanide Death 2
4 Cyanide and Sugar Death 2
Если в Poison есть дублирование, вы можете использовать unique(Poison) снаружи, прежде чем использовать его внутри более крупного набора данных.
@ r2evans Это правильно. в результате чего вы в конечном итоге объедините/присоедините группы к набору данных
Посмотрите, работает ли это с вашим набором данных. Сначала он разбивает строки, а затем сравнивает каждый элемент, чтобы увидеть, существует ли совпадение. Работаем с немного более сложным примером.
library(dplyr)
tibble(dt, grp = sapply(strsplit(dt$Poison, " "), \(x)
paste(unique(unlist(lapply(x, \(y)
which(grepl(paste0("\\b", y, "\\b"), dt$Poison))))), collapse = "")))
# A tibble: 5 × 3
Poison Result grp
<chr> <chr> <chr>
1 Arsenic Death 12
2 Arsenic A in Wine Death With Class 125
3 Cyanide Death 345
4 Cyanide and Sugar Death 345
5 Cyanide and Sugar A Death 3452
вывод с использованием вашего набора данных
# A tibble: 4 × 3
Poison Result grp
<chr> <chr> <chr>
1 Arsenic Death 12
2 Arsenic in Wine Death With Class 12
3 Cyanide Death 34
4 Cyanide and Sugar Death 34
dt <- structure(list(Poison = c("Arsenic", "Arsenic A in Wine", "Cyanide",
"Cyanide and Sugar", "Cyanide and Sugar A"), Result = c("Death",
"Death With Class", "Death", "Death", "Death")), row.names = c(NA,
-5L), class = c("tbl_df", "tbl", "data.frame"))
Забыл вторую половину кадра данных, добавил ее!