【问题标题】:How to update name based on other column's condition (Cleaning Data)如何根据其他列条件更新名称(清理数据)
【发布时间】:2020-07-16 21:37:06
【问题描述】:

我下面有一个df

df <- data.frame(LASTNAME = c("Robinson", "Anderson", "Beckham", "Wickham", "Carlos", "Robinson", "Beckham", "Anderson", "Carlos"),
                 FIRSTNAME = c("David", "Adi", "Joan", "Kesley", "Anberto", "Dave", "Joana", "Adien", "An"))

df <- data.frame(lapply(df, as.character), stringsAsFactors = FALSE)

有些名字不一致。我想找到并替换这些。但是当我把它放在函数中时,它不起作用。还有一件事是我的数据很大。有数百个名字,所以有没有更好的方法来做到这一点。 我的代码在单独时(不在功能中)运行良好,但如果我有 100 个名称需要查找和替换,我无法找到一种方法。我找到了参考here,但没有解决我的问题。任何建议,将不胜感激。

fil_name <- function(last,first,alternative){
  df %>% 
    mutate(FIRSTNAME = ifelse(LASTNAME == "last" & FIRSTNAME == "first", "alternative", FIRSTNAME))
}
fil_name(Robinson,Dave,David)

预期输出:

 LASTNAME   FIRSTNAME
1 Robinson     David
2 Anderson     Adien
3  Beckham     Joana
4  Wickham    Kesley
5   Carlos   Anberto
6 Robinson     David
7  Beckham     Joana
8 Anderson     Adien
9   Carlos   Anberto

【问题讨论】:

    标签: r string str-replace data-cleaning


    【解决方案1】:

    我们可以在函数内部转换为字符,它应该可以工作

    fil_name <- function(df, last,first,alternative){
    
             last <- rlang::as_string(rlang::ensym(last))
             first <- rlang::as_string(rlang::ensym(first))
             alternative <- rlang::as_string(rlang::ensym(alternative))
          df %>% 
           dplyr::mutate(FIRSTNAME = case_when(LASTNAME ==  last & 
                    FIRSTNAME == first ~ alternative, TRUE ~ FIRSTNAME))
        }
    fil_name(df, Robinson,Dave,David)
    

    【讨论】:

    • 你的方法非常棒。我挣扎着寻找答案。非常感谢
    【解决方案2】:

    另一种方法是创建一个单独的数据框,包括FIRSTNAME 替代名称配对,将其合并到原始数据中,并为ALTNAME 不是NA 的那些行更新FIRSTNAME

    这允许使用矢量化过程更新数据,而不是一个一个地更改名称。

    # create data frame with a column to maintain original sort order
    df <- data.frame(obs = 1:9,
                     LASTNAME = c("Robinson", "Anderson", "Beckham", "Wickham", "Carlos", "Robinson", "Beckham", "Anderson", "Carlos"),
                     FIRSTNAME = c("David", "Adi", "Joan", "Kesley", "Anberto", "Dave", "Joana", "Adien", "An"),
                     stringsAsFactors = FALSE)
    # create firstname / altname pairs 
    altnames <- data.frame(FIRSTNAME = c("Dave","Adi","Joan","An"),
                           ALTNAME = c("David","Adien","Joana","Anberto"),
                           stringsAsFactors = FALSE)
    # merge by firstname, keeping all rows from original data frame
    combined <- merge(df,altnames,by="FIRSTNAME",all.x=TRUE)
    # update rows where ALTNAME is not NA
    combined[!is.na(combined$ALTNAME),"FIRSTNAME"] <- combined[!is.na(combined$ALTNAME),"ALTNAME"]
    # print the result, ordered by sequence in original data frame
    combined[order(combined$obs),c("LASTNAME","FIRSTNAME")]
    

    ...和输出:

    > combined[order(combined$obs),c("LASTNAME","FIRSTNAME")]
      LASTNAME FIRSTNAME
    6 Robinson     David
    1 Anderson     Adien
    7  Beckham     Joana
    9  Wickham    Kesley
    4   Carlos   Anberto
    5 Robinson     David
    8  Beckham     Joana
    2 Anderson     Adien
    3   Carlos   Anberto
    > 
    

    【讨论】:

    • 您的回答绝对棒极了。非常感谢您的解决方案。
    • @MichaelJohnson - 感谢您的反馈。虽然 tidyverse 有许多有用的功能,但有时它的语法会导致人们实施过于复杂或非矢量化的解决方案。如果您有 100 个名称要清理,fil_name() 函数将对要清理的数据帧进行 200 次传递。将查找表与原始数据合并的替代方法效率更高。
    • 你是对的。这种方法非常简单且更有效。有时基本概念是解决问题的关键。感谢您的出色反馈和解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-23
    • 1970-01-01
    相关资源
    最近更新 更多