Удалить повторяющиеся данные из data.table

У меня есть таблица данных:

data.table(a=rep(c("xx", "yy"), each=4), b=rep(c("zz", "nn"), each=2), vals=10:17)

    a  b vals
1: xx zz   10
2: xx zz   11
3: xx nn   12
4: xx nn   13
5: yy zz   14
6: yy zz   15
7: yy nn   16
8: yy nn   17

Я хочу этого, так как он выглядит лучше в таблице при экспорте в excel, а затем в слова (я знаю, никогда не использую excel...):

    a  b vals
1: xx zz   10
2: NA NA   11
3: NA nn   12
4: NA NA   13
5: yy zz   14
6: NA NA   15
7: NA nn   16
8: NA NA   17

Обновлено: забыл сказать, что если числовое значение повторяется, его не следует менять на NA, только на символьные столбцы.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
55
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Используя rleid из data.table, мы можем создать функцию

library(data.table)

replace_duplicated <- function(x) {
  replace(x, duplicated(rleid(x)), NA)
}

а теперь примените его к выбранным столбцам (спасибо @markus)

cols = names(df)[sapply(df, is.character)]
df[,(cols) := lapply(.SD, replace_duplicated ), .SDcols = cols]
df

#      a    b vals
#1:   xx   zz   10
#2: <NA> <NA>   11
#3: <NA>   nn   12
#4: <NA> <NA>   13
#5:   yy   zz   14
#6: <NA> <NA>   15
#7: <NA>   nn   16
#8: <NA> <NA>   17

В dplyr мы можем использовать mutate_if

library(dplyr)
df %>% mutate_if (is.character, replace_duplicated)

или mutate_at

df %>% mutate_at(cols, replace_duplicated)

Ницца. Я вижу в своих данных, что это следует делать только в символьных столбцах, чтобы значения не получали NA'ed. Это тоже можно сделать?

Jeppe Olsen 31.01.2019 11:29

@Ronak Вы также можете добавить способ data.tabledf[, lapply(.SD, function(x) replace(x, duplicated(rleid(x)), NA))]

markus 31.01.2019 11:31

OP хочет сохранить последний столбец как есть на случай дублирования чисел.

zx8754 31.01.2019 11:49

@ zx8754 Zx8754 Раньше для этого была включена опция mutate_if, теперь также добавлена ​​опция data.table.

Ronak Shah 31.01.2019 11:52

Здорово! Если я могу предложить, поместите решение data.table вверху, так как OP помечен тегом data.table, а не dplyr.

zx8754 31.01.2019 11:54

Вы можете сделать это с помощью быстрого цикла:

df <- data.frame(a=rep(c("xx", "yy"), each=4), b=rep(c("zz", "nn"), each=2), vals=10:17)

for(i in 1:2){
  df[,i][duplicated(df[,i])] <-NA
}

Мы можем использовать set из data.table для обновления по ссылке

nm1 <- names(dt)[1:2]
for(j in nm1) set(dt, i = which(duplicated(rleid(dt[[j]]))), j = j, value = NA)
dt
#      a    b vals
#1:   xx   zz   10
#2: <NA> <NA>   11
#3: <NA>   nn   12
#4: <NA> <NA>   13
#5:   yy   zz   14
#6: <NA> <NA>   15
#7: <NA>   nn   16
#8: <NA> <NA>   17

Добавление еще одного метода с использованием shift и некоторых таймингов для справки:

set.seed(0L)
sz <- 1e7
DT <- data.table(a=sample(LETTERS, sz, TRUE), b=sample(LETTERS, sz, TRUE))
#DT <- data.table(a=rep(c("xx", "yy"), each=4), b=rep(c("zz", "nn"), each=2), vals=10:17)
DT1 <- copy(DT)
DT2 <- copy(DT)

cols <- c("a","b")


mtd0 <- function() {
    DT[,(cols) := lapply(.SD, function(x) 
        replace(x, duplicated(rleid(x)), NA_character_)) , .SDcols = cols]
}

mtd1 <- function() {
    for(j in cols) 
        set(DT1, i=DT1[, which(get(j)==shift(get(j), 1L))], j=j, value=NA_character_)
}

mtd2 <- function() {
    for(j in cols) 
        set(DT2, i=which(duplicated(rleid(DT2[[j]]))), j=j, value=NA_character_)
}

library(microbenchmark)
microbenchmark(mtd0(), mtd1(), mtd2(), times=3L)

identical(DT, DT1)
#[1] TRUE

identical(DT1, DT2)
#[1] TRUE

тайминги:

Unit: milliseconds
   expr       min        lq      mean    median        uq       max neval cld
 mtd0() 1372.4244 1405.1756 1448.8020 1437.9269 1486.9909 1536.0549     3   b
 mtd1()  280.7695  281.2639  305.5433  281.7583  317.9303  354.1022     3  a 
 mtd2() 1200.5236 1224.5174 1339.0146 1248.5112 1408.2601 1568.0090     3   b

Другие вопросы по теме