Создайте новые уникальные идентификационные номера (идентификаторы)

Рассмотрим следующий набор данных и соответствующий код

mydata<-data.frame(id = c("R001", "R002", "R002", "R003", "R003", "R003"),
                   year = c(2014, 2014, 2015, 2014, 2015, 2017),
                   maledummy = c(1,0,0, 1,1,1))


#select non duplicates
mydata1<-mydata[!duplicated(mydata[c("id")]),]


#select duplicates
mydata2<-mydata[duplicated(mydata[c("id")]),]

#change id numbers of duplicate observation into name with two letters and two numbers
#??

#bind them together to the new dataset
mydatafinal<-rbind(mydata1, mydata2)

В приведенном выше наборе данных у меня есть несколько студентов (id), принадлежащих к когорте выпускников (год). Некоторые студенты принадлежат только к одной когорте выпускников (R001), тогда как другие относятся к двум или даже трем когортам выпускников (R002 принадлежит к двум когортам, а R003 принадлежит к трем когортам). Например, это может произойти, если люди получают более одной степени образования (т. е. две степени бакалавра и одну степень магистра).

Теперь я хотел бы сделать идентификационный номер уникальным для тех работников, которые получают высшее образование более одного раза. Я знаю, как выбрать двойные идентификаторы (см. код). На следующем шаге я хотел бы заменить идентификационный номер другим уникальным идентификатором, состоящим из четырех случайных букв или цифр (в приведенном выше коде я указываю две буквы и две цифры, но это может быть любая комбинация). Однако этот вновь созданный идентификатор должен быть уникальным. Другими словами, ни одно из других наблюдений, получивших новый идентификатор, не должно иметь то же имя. Кто-нибудь знает, как это сделать?

Можете ли вы показать, какой результат будет приемлемым для ваших выборочных данных?

Scott Hunter 11.08.2024 21:11
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
1
79
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Вы можете сделать следующее:

library(data.table)
setDT(mydata)[, id:=paste0(id, "-", rowid(id))]

Выход:

       id  year maledummy
   <char> <num>     <num>
1: R001-1  2014         1
2: R002-1  2014         0
3: R002-2  2015         0
4: R003-1  2014         1
5: R003-2  2015         1
6: R003-3  2017         1
Ответ принят как подходящий

Используя пакет dplyr с базовыми функциями R paste0() и sample(), вы можете добиться этого. Обратите внимание, что я запустил set.seed(1), чтобы гарантировать воспроизводимость результатов этого примера, опустите set.seed() для вашего реального варианта использования.

Я добавил сюда два варианта:

  • вернуть NA, если работник закончил обучение только один раз
  • вернуть исходный идентификатор, если работник закончил обучение только один раз
library(dplyr)

mydata <- data.frame(id = c("R001", "R002", "R002", "R003", "R003", "R003"),
                     year = c(2014, 2014, 2015, 2014, 2015, 2017),
                     maledummy = c(1,0,0, 1,1,1))

# set.seed(1)

result <- mydata |>
  group_by(id) |>
  mutate(
    new_id = if_else(n() > 1, paste0(sample(c(LETTERS, 0:9), 4), collapse = ""), NA)
         ) |>
  ungroup()

result
# # A tibble: 6 × 4
#   id     year maledummy new_id
#   <chr> <dbl>     <dbl> <chr> 
# 1 R001   2014         1 NA    
# 2 R002   2014         0 NR6U  
# 3 R002   2015         0 NR6U  
# 4 R003   2014         1 UJGI  
# 5 R003   2015         1 UJGI  
# 6 R003   2017         1 UJGI 

result <- mydata |>
  group_by(id) |>
  mutate(new_id = case_when(
    n() > 1 ~ paste0(sample(c(LETTERS, 0:9), 4), collapse = ""),
    TRUE ~ id
  )) |>
  ungroup()

result
# # A tibble: 6 × 4
#   id     year maledummy new_id
#   <chr> <dbl>     <dbl> <chr> 
# 1 R001   2014         1 R001  
# 2 R002   2014         0 O6TF  
# 3 R002   2015         0 O6TF  
# 4 R003   2014         1 JT18  
# 5 R003   2015         1 JT18  
# 6 R003   2017         1 JT18 

Вы можете использовать функцию ниже для создания уникальных комбинаций букв и/или цифр длиной 4.

unique_random <- function(x, n.alpha, n.digit=4-n.alpha, all.unique=TRUE) {
  alphas <- digits <- NULL
  
  if (n.alpha + n.digit != 4) stop("n.alpha and n.digit must sum to 4")
  
    if (all.unique) 
      n <- length(x)
    else
      n <- length(unique(x))

  if (n.alpha>0) {
     ALPHAS <- do.call(paste0, expand.grid(lapply(1:n.alpha, \(x) LETTERS)))
     alphas <- sample(ALPHAS, n)
  }
  if (n.digit>0) {
     DIGITS <- formatC(1:10^n.digit - 1, width=n.digit, flag = "0")
     digits <- sample(DIGITS, n)
  }
  
  if (all.unique)
    paste0(alphas, digits)
  else {
    reps <- rle(x)$lengths
    rep(paste0(alphas, digits), reps)
  }
}

unique_random(mydata2$id, n.alpha=2)
# [1] "XS24" "UR77" "PX75"

unique_random(mydata2$id, 4)
#[1] "JDLO" "CLOI" "VWMF"

unique_random(mydata2$id, 4, all.unique=FALSE)
#[1] "DFFZ" "ROXG" "ROXG"

Другой подход с базой R:

  • получить все отдельные буквенно-цифровые 4-граммы:
uids <- apply(combn(c(0:9, letters), 4), 2, \(xs) paste0(xs, collapse = ''))
  • отсортируйте свой фрейм данных по id:
mydata <- mydata[order(mydata$id),]
  • назначьте отдельный ngram new_id каждому исходному идентификатору, независимо от частоты:
mydata$new_id <- with(mydata,
                      rep(head(uids, length(unique(id))),
                          times = rle(id)$lengths
                      )
)
  • установите final_id на id или new_id в зависимости от уникальности:
mydata$final_id <- 
  with(mydata,
       ifelse(id %in% names(Filter(\(x) x > 1, table(id))),
              new_id,
              id
       )
  )

результат:

> mydata
##     id year maledummy new_id final_id
## 1 R001 2014         1   0123     R001
## 2 R002 2014         0   0124     0124
## 3 R002 2015         0   0124     0124
## 4 R003 2014         1   0125     0125
## 5 R003 2015         1   0125     0125
## 6 R003 2017         1   0125     0125

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