#r #join #merge #match
Вопрос:
У меня есть два кадра данных.Первый фрейм данных состоит из четырех столбцов: 1) Идентификатор, 2) Местоположение, 3) Глубина и 4) Плотность. Второй фрейм данных состоит из 1) идентификатора, 2) Сайта и 3) Выбора.
df1
ID Sites Depth Density
1 B 0.2 0
2 B 0.2 1
3 D 0.3 0
4 D 0.3 1
5 B 0.2 2
df2
ID Sites Choice
1 A No
1 B Yes
1 C No
1 D No
2 A No
2 B Yes
2 C No
2 D No
3 A No
3 B No
3 C No
3 D Yes
4 A No
4 B No
4 C No
4 D Yes
5 A No
5 B Yes
5 C No
5 D No
То, что я пытаюсь сделать, это добавить столбец в df2, который имеет плотность на каждом сайте, когда идентификатор имеет «Да». Ниже приведено то, что я хочу, чтобы результат был:
Желаемый Результат
ID Sites Choice Depth Density
1 A No 0.1 0
1 B Yes 0.2 0
1 C No 0.3 0
1 D No 0.4 0
2 A No 0.1 0
2 B Yes 0.2 1
2 C No 0.3 0
2 D No 0.4 0
3 A No 0.1 0
3 B No 0.2 1
3 C No 0.3 0
3 D Yes 0.4 0
4 A No 0.1 0
4 B No 0.2 1
4 C No 0.3 0
4 D Yes 0.4 1
5 A No 0.1 0
5 B Yes 0.2 2
5 C No 0.3 0
5 D No 0.4 1
Я пробовал использовать следующее, но это не работает:
df3<-df2 %>%
full_join(df1, by = c("ID", "Sites")) %>%
group_by(ID) %>%
mutate(Density = Density[Choice == "Yes"]) %>%
distinct(ID, Sites, .keep_all = TRUE)
Спасибо вам за вашу помощь, сообщество stackoverflow.
Комментарии:
1. Откуда
Depth = 0.1
взялось, когда ID = 1 и Сайты = A? Я не вижу этого ни в одной таблице.
Ответ №1:
Это то, что вы ищете?
df1<-data.frame(stringsAsFactors=FALSE,
ID = c(1, 2, 3, 4, 5),
Sites = c("B", "B", "D", "D", "B"),
Depth = c(0.2, 0.2, 0.3, 0.3, 0.2),
Density = c(0, 1, 0, 1, 2)
)
df2<-data.frame(stringsAsFactors=FALSE,
ID = c(1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5),
Sites = c("A", "B", "C", "D", "A", "B", "C", "D", "A", "B", "C", "D",
"A", "B", "C", "D", "A", "B", "C", "D"),
Choice = c("No", "Yes", "No", "No", "No", "Yes", "No", "No", "No", "No",
"No", "Yes", "No", "No", "No", "Yes", "No", "Yes", "No",
"No")
)
df3<-df2 %>%
left_join(df1, by = c("ID", "Sites")) %>%
mutate(Density=if_else(Choice=="Yes",Density, 0))
Ответ №2:
Данные.
df1 <- data.frame(
ID = seq(from = 1, to = 5, by = 1),
Sites = c("B", "B", "D", "D", "B"),
Depth = c(0.2, 0.2, 0.3, 0.3, 0.2),
Density = c(0,1,0,1,2)
)
qw <- c("No", "Yes")
df2 <- data.frame(
ID = c(rep(1:5, times = 5)),
Sites = sample(LETTERS[1:4], size = 25, replace = TRUE),
Choice = sample(qw, size = 25, replace = T)
)
Но я немного смущен тем, что вам нужно от этого репрекса. В вашем заявлении создается впечатление, что вам нужен подмножество DF3, которое содержит только записи, в которых значение CHOICE == «ДА» является ИСТИННЫМ, а идентификатор = ИДЕНТИФИКАТОР и Сайт = Сайт. Очевидно, что это приведет к очень небольшому количеству записей.
df3 <- merge(df1, df2, by = c("Sites", "ID")) %>%
filter(Choice == "Yes") # only one record from the dummy data.
Если выбор » Да » является свойством идентификатора, но не сайта, вот вариант.
df3 <- df1 %>%
select(-Sites) %>%
left_join(df2 %>% filter(Choice == "Yes"), by = "ID")
Я думаю, я просто запутался, должны ли совпадать оба сайта и идентификаторы. Если это так, то здесь просто не так много записей.
Ответ №3:
Решение data.table:
df1[df2[ID %in% df2[Choice == "Yes", unique(ID)], ],
on = .(ID, Sites)][is.na(Density),
Density := 0][]
Что там внутри:
df2[Choice == "Yes", unique(ID)
фильтры, где выбор «да», и возвращает уникальные идентификаторы. Они понадобятся нам для фильтрацииdf2
.df2[ID %in% df2[Choice == "Yes", unique(ID)], ]
фильтрует только те случаи, когда идентификатор совпадает с идентификаторами, в которых есть хотя бы одно «да» в выборе.df1[df_x, on = .(ID, Sites)]
делает левое соединениеdf1
с тем, что находится внутриdf_x
(в нашем случае отфильтрованноеdf2
.[is.na(Density), Density := 0]
фильтрует строки, в которых указана плотностьNA
, и только в этих строках присваивает 0 плотности.[]
Печать для отображения полученных данных, на самом деле вам это не нужно.