【问题标题】:Replace Dataframe Column Values with User Defined Function in R用 R 中的用户定义函数替换数据框列值
【发布时间】:2021-03-23 23:33:02
【问题描述】:

我在尝试用自值替换的列中有一组分组的值

col1
a
a;a;b;c
c;b;a
NA
b;b;b

我想用mixed 或单个当前值替换所有值,例如a;a;a;a 变为a

预期输出

col1
a
Mixed
Mixed
NA
b

代码

grouping = function(x){
y = as.list(strsplit(x, ";")[[1]])

#select first element, and test if each is the same element.
z = ""
for (i in 1:length(y)){
  if (as.character(y[1]) != as.character(y[i])) {
    z = 'mixed'
    break
  } else {
    z = as.character(y[1])
  }
}
return(z)
}

db %>%
select(col1) %>%
mutate(
test = grouping(col1)
)

我已经尝试了几种不同的方法,要么最终导致它根本不起作用,要么为所有内容赋予值 a

【问题讨论】:

  • 好电话,已更新

标签: r dataframe dplyr user-defined-functions


【解决方案1】:

您可以将grouping 函数编写为:

grouping <- function(x) {
  sapply(strsplit(x, ';'), function(x) 
        if(length(unique(x)) == 1) unique(x) else 'Mixed')
}
db$test <- grouping(db$col1)
db

#     col1  test
#1       a     a
#2 a;a;b;c Mixed
#3   c;b;a Mixed
#4    <NA>  <NA>
#5   b;b;b     b

【讨论】:

    【解决方案2】:

    通过定义用户函数f的基本R选项

    f <- function(x) ifelse(length(u <- unique(unlist((strsplit(x, ";"))))) > 1, "Mixed", u)
    

    这样

    > transform(df, col1 = Vectorize(f)(col1))
       col1
    1     a
    2 Mixed
    3 Mixed
    4  <NA>
    5     b
    

    【讨论】:

      【解决方案3】:

      我们可以从字母'col1'中提取子字符串,使用n_distinct检查不同元素的数量,使用case_when将具有多个唯一元素的元素更改为'Mixed'

      library(dplyr)
      library(stringr)
      library(purrr)
      df1 %>%
          mutate(col1 = case_when(map_dbl(str_extract_all(col1,
               "[a-z]"), n_distinct) >1 ~ "Mixed",
             is.na(col) ~ NA_character_, 
            TRUE ~ substr(col1, 1, 1)))
      

      -输出

      #  col1
      #1     a
      #2 Mixed
      #3 Mixed
      #4  <NA>
      #5     b
      

      或者另一种选择是通过separate_rows 分隔符将列拆分,然后将row_numbersummarise 具有多于一行的元素(在distinct 之后)分组为“混合”

      library(tidyr)
      df1 %>% 
         mutate(rn = row_number()) %>%
         separate_rows(col1) %>% 
         distinct() %>%
         group_by(rn) %>% 
         summarise(col1 = case_when(n() > 1 ~ 'Mixed', TRUE ~ first(col1)), 
              .groups = 'drop') %>%
         select(-rn)
      

      -输出

      # A tibble: 5 x 1
      #  col1 
      #  <chr>
      #1 a    
      #2 Mixed
      #3 Mixed
      #4 <NA> 
      #5 b    
      

      或者使用带有紧凑选项的base R

      v1 <- gsub("([a-z])\\1+", "\\1", gsub(";", "", df1$col1))
      replace(v1, nchar(v1) > 1, "Mixed")
      #[1] "a"     "Mixed" "Mixed" NA      "b"    
      

      OP 函数中的问题是它只提取第一个 [[1]] list 元素

      as.list(strsplit(x, ";")[[1]])
      

      因为strsplit 返回一个list,其中length 等于初始数据的行数。所以,基本上只选择第一个,就被回收了

      数据

      df1 <- structure(list(col1 = c("a", "a;a;b;c", "c;b;a", NA, "b;b;b")),
      class = "data.frame", row.names = c(NA, 
      -5L))
      

      【讨论】:

        【解决方案4】:

        您也可以将其用于您的功能并使用base R

        #Function  
        myfun <- function(x)
        {
          y <- unlist(strsplit(x, ";"))
          if(length(unique(y))==1)
          {
            z <- unique(y)
          } else
          {
            z <- 'Mixed'
          }
        }
        #Apply
        df$New <- apply(df,1,myfun)
        

        输出:

        df
             col1   New
        1       a     a
        2 a;a;b;c Mixed
        3   c;b;a Mixed
        4    <NA>  <NA>
        5   b;b;b     b
        

        使用的一些数据:

        #Data
        df <- structure(list(col1 = c("a", "a;a;b;c", "c;b;a", NA, "b;b;b")), class = "data.frame", row.names = c(NA, 
        -5L))
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2022-01-14
          • 1970-01-01
          • 1970-01-01
          • 2021-09-14
          • 1970-01-01
          • 2014-12-15
          • 1970-01-01
          相关资源
          最近更新 更多