根据ID组中的非唯一名称创建唯一名称

时间:2019-02-07 19:27:44

标签: r dplyr

id 中,我的数据具有多个非唯一的 name 标签。我想创建第三列,以使非唯一名称在其末尾粘贴字母以创建唯一名称。

dat <- structure(list(id = c("172262", "172262", "172262", "172262", 
"172504", "172504", "172504", "172507", "172507", "172507"), 
    name = c("Fam", "Fam", "Fam", "CM_fam", "CBT_Fam", "CBT_Fam", 
    "CBT_Fam", "TAU", "CBT_Educ", "CBT_MI")), class = c("tbl_df", 
"tbl", "data.frame"), row.names = c(NA, -10L))

所需的输出是:

id     name     unique_name    
172262 Fam      Fam_a      
172262 Fam      Fam_b      
172262 Fam      Fam_c      
172262 CM_fam   CM_fam    
172504 CBT_Fam  CBT_Fam_a  
172504 CBT_Fam  CBT_Fam_b  
172504 CBT_Fam  CBT_Fam_c  
172507 TAU      TAU       
172507 CBT_Educ CBT_Educ  
172507 CBT_MI   CBT_MI  

5 个答案:

答案 0 :(得分:3)

您可以将pastesprintfletters一起使用...

dat %>% group_by(id, name) %>% mutate(uname = 
  if (n() > 1) sprintf("%s_%s", name, letters[row_number()]) 
  else name
)

# A tibble: 10 x 3
# Groups:   id, name [6]
   id     name     uname    
   <chr>  <chr>    <chr>    
 1 172262 Fam      Fam_a    
 2 172262 Fam      Fam_b    
 3 172262 Fam      Fam_c    
 4 172262 CM_fam   CM_fam   
 5 172504 CBT_Fam  CBT_Fam_a
 6 172504 CBT_Fam  CBT_Fam_b
 7 172504 CBT_Fam  CBT_Fam_c
 8 172507 TAU      TAU      
 9 172507 CBT_Educ CBT_Educ 
10 172507 CBT_MI   CBT_MI   

对于tidyverse(dplyr所属的)中的其他字符串操作,可能会看到stringr和粘胶。

答案 1 :(得分:2)

您可以使用ave(以R为基础)

transform(dat, unique_name = 
            ave(name,name, FUN = function(x) {
              if((l <- length(x)) == 1) x
              else paste0(x,"_",letters[seq(l)])
            }))
#        id     name unique_name
# 1  172262      Fam       Fam_a
# 2  172262      Fam       Fam_b
# 3  172262      Fam       Fam_c
# 4  172262   CM_fam      CM_fam
# 5  172504  CBT_Fam   CBT_Fam_a
# 6  172504  CBT_Fam   CBT_Fam_b
# 7  172504  CBT_Fam   CBT_Fam_c
# 8  172507      TAU         TAU
# 9  172507 CBT_Educ    CBT_Educ
# 10 172507   CBT_MI      CBT_MI

还有一个代码高尔夫,虽然不通用:

dat$unique_name <- chartr(
  make.unique(dat$name,sep="_"),old="123456789",new="abcdefghi")
dat
# # A tibble: 10 x 3
#        id     name unique_name
#     <chr>    <chr>       <chr>
#  1 172262      Fam         Fam
#  2 172262      Fam       Fam_a
#  3 172262      Fam       Fam_b
#  4 172262   CM_fam      CM_fam
#  5 172504  CBT_Fam     CBT_Fam
#  6 172504  CBT_Fam   CBT_Fam_a
#  7 172504  CBT_Fam   CBT_Fam_b
#  8 172507      TAU         TAU
#  9 172507 CBT_Educ    CBT_Educ
# 10 172507   CBT_MI      CBT_MI

答案 2 :(得分:1)

另一种 dat %>% group_by(id, name) %>% mutate(unique_name = if(n() > 1) paste(name, letters[1:length(name)], sep = "_") else name) id name unique_name <chr> <chr> <chr> 1 172262 Fam Fam_a 2 172262 Fam Fam_b 3 172262 Fam Fam_c 4 172262 CM_fam CM_fam 5 172504 CBT_Fam CBT_Fam_a 6 172504 CBT_Fam CBT_Fam_b 7 172504 CBT_Fam CBT_Fam_c 8 172507 TAU TAU 9 172507 CBT_Educ CBT_Educ 10 172507 CBT_MI CBT_MI 可能性是:

length()

首先,它按“ id”和“ name”分组。然后,如果每组的案例数大于1,则将“名称”中的值与“名称”长度的字母序列组合在一起,否则将分配“名称”中的值。

或者使用n(),而不是dat %>% group_by(id, name) %>% mutate(unique_name = if(length(name) > 1) paste(name, letters[1:length(name)], sep = "_") else name)

seq_along()

或者使用n()代替dat %>% group_by(id, name) %>% mutate(unique_name = if(any(seq_along(name) != 1)) paste(name, letters[1:length(name)], sep = "_") else name)

gl()

或者使用dat %>% group_by(id, name) %>% mutate(unique_name = if(n() > 1) paste(name, gl(length(name), 1, n(), letters), sep = "_") else name) id name unique_name <chr> <chr> <chr> 1 172262 Fam Fam_a 2 172262 Fam Fam_b 3 172262 Fam Fam_c 4 172262 CM_fam CM_fam 5 172504 CBT_Fam CBT_Fam_a 6 172504 CBT_Fam CBT_Fam_b 7 172504 CBT_Fam CBT_Fam_c 8 172507 TAU TAU 9 172507 CBT_Educ CBT_Educ 10 172507 CBT_MI CBT_MI 生成字母的方法稍有不同:

dat %>%
 group_by(id, name) %>%
 mutate(unique_name = if(length(name) > 1) paste(name, gl(length(name), 1, n(), letters), sep = "_") else name)

或者:

dat %>%
 group_by(id, name) %>%
 mutate(unique_name = if(any(seq_along(name) != 1)) paste(name, gl(length(name), 1, n(), letters), sep = "_") else name)

或者:

            {
                "sensor_data": [
                    {
                        "sensor_id": "302CEM/lion/light1",
                        "sensor_state": "on"
                    },
                    {
                        "sensor_id": "302CEM/lion/light2",
                        "sensor_state": "off"
                    }
                ]
            }

            def read_from_db():
                with open('datajson.json') as f:
                    data = json.load(f)

                for sensors in data['sensor_data']:
                    name = sensors['sensor_id']



            read_from_db()

答案 3 :(得分:1)

只需在此处带来一些data.table风味:

library(data.table)
DT <- as.data.table(dat)
DT[, unique_name := if (.N > 1) paste(name, letters[1:.N], sep = "_") 
                    else name, 
   by = .(id, name)]

尽管,正如其他人指出的那样,如果您有26个以上重复的名称,您可能希望将letters[1:.N]替换为1:.N

答案 4 :(得分:1)

可以从这里选择很多选项,但是如果您正在寻找一个相当简单的管道,并且可以使用格式有所不同的输出,则可以使用基数R中的make.unique

library(dplyr)

dat %>% 
  group_by(id, name) %>% 
  mutate(unique_name = make.unique(name))

哪种产量:

   id     name     unique_name
   <chr>  <chr>    <chr>      
 1 172262 Fam      Fam        
 2 172262 Fam      Fam.1      
 3 172262 Fam      Fam.2      
 4 172262 CM_fam   CM_fam     
 5 172504 CBT_Fam  CBT_Fam    
 6 172504 CBT_Fam  CBT_Fam.1  
 7 172504 CBT_Fam  CBT_Fam.2  
 8 172507 TAU      TAU        
 9 172507 CBT_Educ CBT_Educ   
10 172507 CBT_MI   CBT_MI