根据R中的两列分配特定值

时间:2018-02-17 02:35:39

标签: r dataframe

我有一个类似于:

的数据框
   Student_ID    Number  Position
    VB-123        10      2
    VB-456        15      5
    VB-789        25      25
    VB-889        12      2
    VB-965        15      7
    VB-758        45      9
    VB-245        25      25

我想添加新列并根据以下条件分配值:

  1. 如果只有Number在整个数据框中重复,请分配A
  2. 如果只有Position在整个数据框中重复,请分配B
  3. 如果NumberPosition都重复,请指定C
  4. 如果没有重复,则分配D
  5. 输出如下:

    Student_ID    Number  Position   Assign
        VB-123        10      2      B
        VB-456        15      5      A
        VB-789        25      25     C
        VB-889        12      2      B
        VB-965        15      7      A
        VB-758        45      9      D
        VB-245        25      25     C
    

3 个答案:

答案 0 :(得分:3)

使用dplyr,

library(dplyr)

students <- data.frame(Student_ID = c("VB-123", "VB-456", "VB-789", "VB-889", "VB-965", "VB-758", "VB-245"), 
                       Number = c(10L, 15L, 25L, 12L, 15L, 45L, 25L), 
                       Position = c(2L, 5L, 25L, 2L, 7L, 9L, 25L))

students2 <- students %>% 
    mutate_at(vars(Number, Position), funs(n = table(.)[as.character(.)])) %>% 
    mutate(Assign = case_when(Number_n > 1 & Position_n > 1 ~ 'C', 
                              Number_n > 1 ~ 'A', 
                              Position_n > 1 ~ 'B', 
                              TRUE ~ 'D'))

students2
#>   Student_ID Number Position Number_n Position_n Assign
#> 1     VB-123     10        2        1          2      B
#> 2     VB-456     15        5        2          1      A
#> 3     VB-789     25       25        2          2      C
#> 4     VB-889     12        2        1          2      B
#> 5     VB-965     15        7        2          1      A
#> 6     VB-758     45        9        1          1      D
#> 7     VB-245     25       25        2          2      C

作为mutate_at行的替代方案,您可以使用add_count两次,根据需要重命名。要删除中间列,请点击select(-matches('_n$'))

您可以通过分配子集来或多或少地复制基础中的逻辑:

students2 <- cbind(students, lapply(students[2:3], function(x) table(x)[as.character(x)]))
students2$Assign <- 'D'
students2$Assign[students2$Number.Freq > 1 & students2$Position.Freq > 1] <- 'C'
students2$Assign[students2$Number.Freq > 1 & students2$Position.Freq == 1] <- 'A'
students2$Assign[students2$Number.Freq == 1 & students2$Position.Freq > 1] <- 'B'
students2[4:7] <- NULL

students2
#>   Student_ID Number Position Assign
#> 1     VB-123     10        2      B
#> 2     VB-456     15        5      A
#> 3     VB-789     25       25      C
#> 4     VB-889     12        2      B
#> 5     VB-965     15        7      A
#> 6     VB-758     45        9      D
#> 7     VB-245     25       25      C

答案 1 :(得分:2)

以下是使用base R的选项。按照evaluateatin('l1')的顺序创建list列名称,预分配'D'以在'dat'中创建'Assign'列,循环遍历'l1'的序列,子集基于“l1”中列名称的数据列,使用duplicated查找重复元素,并将“分配”列重新分配给相应的LETTER

l1 <- list("Number", "Position", c("Number", "Position"))
dat$Assign <- rep("D", nrow(dat))
for(i in seq_along(l1)){
    df <- dat[l1[[i]]]  
    i1 <- duplicated(df)|duplicated(df, fromLast = TRUE)
    dat$Assign <- replace(dat$Assign, i1, LETTERS[i])
}   

-output

dat
#  Student_ID Number Position Assign
#1     VB-123     10        2      B
#2     VB-456     15        5      A
#3     VB-789     25       25      C
#4     VB-889     12        2      B
#5     VB-965     15        7      A
#6     VB-758     45        9      D
#7     VB-245     25       25      C

答案 2 :(得分:1)

使用的解决方案。

library(dplyr)

dat2 <- dat %>% count(Number)
dat3 <- dat %>% count(Position)
dat4 <- dat %>% count(Number, Position)

dat5 <- dat %>%
  left_join(dat2, by = "Number") %>%
  left_join(dat3, by = "Position") %>%
  left_join(dat4, by = c("Number", "Position")) %>%
  mutate(Assign = case_when(
    n > 1               ~ "C",
    n.x > 1 & n.y == 1  ~ "A",
    n.y > 1 & n.x == 1  ~ "B",
    TRUE                ~ "D"
  )) %>%
  select(-n.x, -n.y, -n)
dat5
#   Student_ID Number Position Assign
# 1     VB-123     10        2      B
# 2     VB-456     15        5      A
# 3     VB-789     25       25      C
# 4     VB-889     12        2      B
# 5     VB-965     15        7      A
# 6     VB-758     45        9      D
# 7     VB-245     25       25      C

数据

dat <- read.table(text = "Student_ID    Number  Position
    'VB-123'        10      2
    'VB-456'        15      5
    'VB-789'        25      25
    'VB-889'        12      2
    'VB-965'        15      7
    'VB-758'        45      9
    'VB-245'        25      25",
                  header = TRUE, stringsAsFactors = FALSE)