Рассмотрим следующий набор данных и соответствующий код
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 принадлежит к трем когортам). Например, это может произойти, если люди получают более одной степени образования (т. е. две степени бакалавра и одну степень магистра).
Теперь я хотел бы сделать идентификационный номер уникальным для тех работников, которые получают высшее образование более одного раза. Я знаю, как выбрать двойные идентификаторы (см. код). На следующем шаге я хотел бы заменить идентификационный номер другим уникальным идентификатором, состоящим из четырех случайных букв или цифр (в приведенном выше коде я указываю две буквы и две цифры, но это может быть любая комбинация). Однако этот вновь созданный идентификатор должен быть уникальным. Другими словами, ни одно из других наблюдений, получивших новый идентификатор, не должно иметь то же имя. Кто-нибудь знает, как это сделать?
Вы можете сделать следующее:
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()
для вашего реального варианта использования.
Я добавил сюда два варианта:
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:
uids <- apply(combn(c(0:9, letters), 4), 2, \(xs) paste0(xs, collapse = ''))
id
:mydata <- mydata[order(mydata$id),]
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
Можете ли вы показать, какой результат будет приемлемым для ваших выборочных данных?