Я хотел бы заменить повторяющиеся значения для каждого сайта на NA и сохранить первое повторяющееся значение, которое появляется слева направо.
Например, на сайте «Альц-Эттельбрюк» значение «7» повторяется в столбцах 4 и 5. Это означает, что столбец 5 только этого сайта должен возвращать значение NA. Число 12 повторяется во всех столбцах на сайте «Наш-Гемунд/Вианден», поэтому я хотел бы оставить число 12 во втором столбце, но остальные следует заменить на NA.
Для этого я использовал дублированную функцию, но она возвращает «NULL».
Чтобы воспроизвести проблему, я использовал следующий фрейм данных и указал в конце желаемый результат.
Любая помощь будет оценена по достоинству. Заранее спасибо.
df <- data.frame(stringsAsFactors = FALSE,
check.names = FALSE,
Site = c("Att-Bissen","Alz-Ettelbruck","Our-Gemund/Vianden",
"Syre Felsmuhle/Mertert","Ernz Blanche-Larochette"),
`2001-12-01 to 2021-12-01` = c(12, 1, 12, 1, 8),
`1991-12-01.to 2021-12-01` = c(5, 4, 12, 6, 14),
`1981-12-01 to 2021-12-01` = c(12, 7, 12, 20, 14),
`1971-12-01 to 2021-12-01` = c(19, 7, 12, 13, 14))
# Replace repeated values with NA per row
data <- for (i in 1:nrow(df)) {
df[i, -1][duplicated(df[i, -1])] <- NA
}
Вот что я хотел бы вернуть скрипту:





(Обновлено: в первой версии кода base-R и dplyr+tidyr использовался duplicated, который ошибочно удалял 12 в столбце 4 строки 1. Он был отредактирован, чтобы исправить это, чтобы не использовать duplicated.)
Сокращение, сравнивающее столбец с обновленным столбцом.
df[,-1] <- Reduce(
function(prev, this) replace(this, is.na(prev) | this == prev, this[NA][1]),
df[,-1], accumulate = TRUE)
df
# Site 2001-12-01 to 2021-12-01 1991-12-01.to 2021-12-01 1981-12-01 to 2021-12-01 1971-12-01 to 2021-12-01
# 1 Att-Bissen 12 5 12 19
# 2 Alz-Ettelbruck 1 4 7 NA
# 3 Our-Gemund/Vianden 12 NA NA NA
# 4 Syre Felsmuhle/Mertert 1 6 20 13
# 5 Ernz Blanche-Larochette 8 14 NA NA
Я жестко запрограммировал df[,-1] в обоих местах, это легко может быть и df[,2:5], просто оно должно быть одинаковым в обоих местах (слева от <- и внутри Reduce).
Это теряет некоторую эффективность, поскольку имеет двойной поворот.
library(dplyr)
library(tidyr) # pivot_*
df %>%
pivot_longer(cols = -Site) %>%
arrange(Site, desc(name)) %>%
mutate(.by = "Site", value = if_else(value == lag(value, default=-1L), value[NA], value)) %>%
pivot_wider(id_cols = Site) %>%
slice(match(Site, df$Site)) %>%
select(match(names(.), names(df)))
# # A tibble: 5 × 5
# Site `2001-12-01 to 2021-12-01` `1991-12-01.to 2021-12-01` `1981-12-01 to 2021-12-01` `1971-12-01 to 2021-12-01`
# <chr> <dbl> <dbl> <dbl> <dbl>
# 1 Att-Bissen 12 5 12 19
# 2 Alz-Ettelbruck 1 4 7 NA
# 3 Syre Felsmuhle/Mertert 1 6 20 13
# 4 Ernz Blanche-Larochette 8 14 NA NA
# 5 Our-Gemund/Vianden 12 NA NA NA
Одним из побочных эффектов поворота является то, что порядок строк и столбцов не гарантированно будет восстановлен, поэтому я добавил в конце наиболее эстетичный slice(.) %>% select(.), чтобы он соответствовал вашим входным данным. (Это совершенно не обязательно.)
Данные
df <- structure(list(Site = c("Att-Bissen", "Alz-Ettelbruck", "Our-Gemund/Vianden", "Syre Felsmuhle/Mertert", "Ernz Blanche-Larochette"), "2001-12-01 to 2021-12-01" = c(12, 1, 12, 1, 8), "1991-12-01.to 2021-12-01" = c(5, 4, 12, 6, 14), "1981-12-01 to 2021-12-01" = c(12, 7, 12, 20, 14), "1971-12-01 to 2021-12-01" = c(19, 7, 12, 13, 14)), class = "data.frame", row.names = c(NA, -5L))
Вы были близки, df[i, -1] дает список, значит, вы хотите unlist его.
> df2 <- df ## copy to avoid overwriting
> for (i in 1:nrow(df2)) {
+ df2[i, -1][duplicated(unlist(df2[i, -1]))] <- NA
+ }
> df2
Site 2001-12-01 to 2021-12-01 1991-12-01.to 2021-12-01 1981-12-01 to 2021-12-01 1971-12-01 to 2021-12-01
1 Att-Bissen 12 5 NA 19
2 Alz-Ettelbruck 1 4 7 NA
3 Our-Gemund/Vianden 12 NA NA NA
4 Syre Felsmuhle/Mertert 1 6 20 13
5 Ernz Blanche-Larochette 8 14 NA NA
Однако, если вы считаете дубликатами только последующие идентичные значения, как показано в желаемом выводе, рассмотрите возможность использования diff.
> df2 <- df ## copy to avoid overwriting
> for (i in 1:nrow(df2)) {
+ df2[i, -1][c(Inf, diff(unlist(df[i, -1]))) == 0] <- NA
+ }
> df2
Site 2001-12-01 to 2021-12-01 1991-12-01.to 2021-12-01 1981-12-01 to 2021-12-01 1971-12-01 to 2021-12-01
1 Att-Bissen 12 5 12 19
2 Alz-Ettelbruck 1 4 7 NA
3 Our-Gemund/Vianden 12 NA NA NA
4 Syre Felsmuhle/Mertert 1 6 20 13
5 Ernz Blanche-Larochette 8 14 NA NA