【问题标题】:summarize and spread by almost identical strings通过几乎相同的字符串进行汇总和传播
【发布时间】:2020-06-30 06:52:09
【问题描述】:

我从几个具有相似项目的原始 df 开始,清理并合并为长格式,后来我使用 dplyr 将其合并为宽格式...但是,我留下了重复的内容,因为我正在处理 几乎相同的字符串,任何人都可以建议一种更简单的方法来在传播我的数据时删除重复项。

这是我的代码示例

library(tidyverse)
library(readxl)
library(reprex)

all_data_final_wider<-all_data_final %>%
  mutate(cases = case_when(cases=='X' ~ 'x', cases=='x' ~ 'x'))%>%
  group_by(Species) %>%
  mutate(row = row_number()) %>%
  tidyr::pivot_wider(names_from = location, values_from =cases)%>%
  select(-row)

下面是我的样本数据的dput

structure(list(`Wall type (Kaminski 2014)` = c("", "", "hyaline", 
"hyaline", "hyaline", "hyaline", "", "hyaline", "", "hyaline", 
"hyaline", "", "", "porcelaneous (imperforate)", "porcelaneous (imperforate)", 
"porcelaneous (imperforate)", "porcelaneous (imperforate)", "porcelaneous (imperforate)", 
"", "", "", "", "", "", "", "", "", "porcelaneous (imperforate)", 
"porcelaneous (imperforate)", "porcelaneous (imperforate)", "porcelaneous (imperforate)", 
"porcelaneous (imperforate)", "porcelaneous (imperforate)", "porcelaneous (imperforate)", 
"", "", "", "", "", "", "porcelaneous (imperforate)", "", "", 
"", "porcelaneous (imperforate)", "", "", "", "", ""), Order = c("", 
"", "Rotaliida", "Rotaliida", "Rotaliida", "Rotaliida", "", "Rotaliida", 
"", "Rotaliida", "Rotaliida", "", "", "Miliolida", "Miliolida", 
"Miliolida", "Miliolida", "Miliolida", "Miliolida", "", "", "", 
"", "", "", "", "", "Miliolida", "Miliolida", "Miliolida", "Miliolida", 
"Miliolida", "Miliolida", "Miliolida", "", "", "", "", "", "", 
"Miliolida", "", "", "", "Miliolida", "", "", "", "", ""), Superfamily = c("", 
"", "Planorbulinoidea", "Acervulinoidea", "Acervulinoidea", "Acervulinoidea", 
"", "Acervulinoidea", "Acervulinoidea ", "Acervulinoidea", "Acervulinoidea", 
"Milioloidea", "Milioloidea", "Milioloidea", "Milioloidea", "Milioloidea", 
"Milioloidea", "Milioloidea", "", "", "", "", "", "", "", "", 
"", "Milioloidea", "Milioloidea", "Milioloidea", "Milioloidea", 
"Milioloidea", "Milioloidea", "Milioloidea", "", "", "", "", 
"", "", "Milioloidea", "", "", "", "Milioloidea", "", "", "", 
"", ""), Family = c("", "", "Planorbulinidae", "Acervulinoidae", 
"Acervulinoidae", "Acervulinoidae", "", "Acervulinoidae", "Acervulinidae", 
"Acervulinoidae", "Acervulinoidae", "Cribrolinoididae", "Cribrolinoididae", 
"Cribrolinoididae", "Cribrolinoididae", "Hauerinidae", "Hauerinidae", 
"Hauerinidae", "Hauerinidae", "", "", "", "", "", "", "", "", 
"Cribrolinoididae", "Cribrolinoididae", "Cribrolinoididae", "Cribrolinoididae", 
"Cribrolinoididae", "Cribrolinoididae", "Cribrolinoididae", "", 
"", "", "", "", "", "Cribrolinoididae", "", "", "", "Cribrolinoididae", 
"", "", "", "", ""), Genus = c("", "", "?Planorbulina", "Acervulina", 
"Acervulina", "Acervulina", "", "Acervulina", "Acervulina", "Acervulina", 
"Acervulina", "Adelosina", "Adelosina", "Adelosina", "Adelosina", 
"Adelosina", "Adelosina", "Adelosina", "Quinqueloculina", "", 
"", "", "", "", "", "", "", "Adelosina", "Adelosina", "Adelosina", 
"Adelosina", "Adelosina", "Adelosina", "Adelosina", "", "", "", 
"", "", "", "Adelosina", "", "", "", "Adelosina", "Adelosina", 
"Adelosina", "", "", ""), Species = c("", "", "?Planorbulina sp . 1", 
"Acervulina cf. A. mahabethi", "Acervulina cf. A. mahabeti", 
"Acervulina inhaerens", "Acervulina inhaerens ", "Acervulina mabahethi", 
"Acervulina mabahethi ", "Acervulina sp. 01", "Acervulina sp. 01", 
"Adelosina bicornis ", "Adelosina bicornis ", "Adelosina carinatastriata", 
"Adelosina carinatastriata", "Adelosina carinatastriata", "Adelosina carinatastriata", 
"Adelosina carinatastriata", "Adelosina carinatastriata", "Adelosina carinatastriata ", 
"Adelosina carinatastriata ", "Adelosina carinatastriata ", "Adelosina carinatastriata ", 
"Adelosina carinatastriata ", "Adelosina carinatastriata ", "Adelosina carinatastriata ", 
"Adelosina carinatastriata ", "Adelosina cf. A. mediterranensis", 
"Adelosina crassicarinata", "Adelosina crassicarinata", "Adelosina crassicarinata", 
"Adelosina crassicarinata", "Adelosina dagornae", "Adelosina dagornae", 
"Adelosina dagornae", "Adelosina dagornae", "Adelosina dagornae", 
"Adelosina dagornae", "Adelosina dagornae", "Adelosina dagornae", 
"Adelosina echinata", "Adelosina echinata ", "Adelosina echinata ", 
"Adelosina echinata ", "Adelosina honghensis", "Adelosina honghensis", 
"Adelosina honghensis", "Adelosina honghensis ", "Adelosina honghensis ", 
"Adelosina honghensis "), authority = c("Haynesina sp.", "Haynesina sp.", 
"d'Orbigny, 1826", " Said, 1949 ", "", "Schulze, 1854", "Schulze, 1854", 
" Said, 1949 ", "Said, 1949 ", "Schultze, 1854", "", "Walker & Jacob, 1798 ", 
"Walker & Jacob, 1798 ", " Wiesner, 1923 ", " Wiesner, 1923 ", 
" Wiesner, 1923 ", " Wiesner, 1923 ", " Wiesner, 1923 ", "Wiesner, 1923", 
"Wiesner 1923 ", "Wiesner 1923 ", "Wiesner 1923 ", "Wiesner 1923 ", 
"Wiesner 1923 ", "Wiesner 1923 ", "Wiesner 1923 ", "Wiesner 1923 ", 
" Le Calvez & Le Calvez, 1958 ", "", "", "", "", "", "", "Levi et al. 1990 ", 
"Levi et al. 1990 ", "Levi et al. 1990 ", "Levi et al. 1990 ", 
"Levi et al. 1990 ", "Levi et al. 1990 ", "", "d'Orbigny, 1826", 
"d'Orbigny, 1826", "d'Orbigny, 1826", "", "", "", "Lak, 1982", 
"Lak, 1982", "Lak, 1982"), location = c(" Parkar and Gischler  2015 ", 
"Present study", "Cherif et al. 1997", "Amao et al. 2016 PG", 
"Amao_et_al_2019_Persian_Gulf_paper", "Murray 1965", " Shublak  1977 ", 
"Parker and Gischler 2015", " Parkar and Gischler  2015 ", "Amao et al. 2016 PG", 
"Amao_et_al_2019_Persian_Gulf_paper", " Shublak  1977 ", "Khader  2020 ", 
"Al-Zamel et al 1996", "Al-Zamel et al 2009", "Parker and Gischler 2015", 
"Amao et al. 2016 MP", "Amao et al. 2016 Salwa", "Amao_et_al_2019_baseline_paper", 
"Al-Zamel et al.  1996 ", "Khader  1997 ", " Cherif et al.  1997 ", 
"Al-Ghadban  2000 ", "Al-Zamel et al.  2009 ", "Al-Theyabi  2012b ", 
"Al-Enezi et al.  2019 ", "Khader  2020 ", "Amao et al. 2016 MP", 
"Al-Zamel et al 1996", "Cherif et al. 1997", "Al-Zamel & Cherif 1998", 
"Al-Enezi & Frontalini 2015", "Al-Zamel et al 2009", "Al-Enezi & Frontalini 2015", 
"Khader  1997 ", "Al-Ghadban  2000 ", "Al-Zamel et al.  2009 ", 
"Al-Ammar  2011 ", "Al-Enezi and Frontalini  2015 ", "Khader  2020 ", 
"Cherif et al. 1997", "Al-Shuaibi  1997 ", "Al-Ghadban  2000 ", 
"Khader  2020 ", "Cherif et al. 1997", "Clark and Keiji 1975", 
"Nabavi 2014", " Cherif et al.  1997 ", "Al-Ghadban  2000 ", 
"Khader  2020 "), cases = c("X", "X", "x", "x", "x", "x", "X", 
"x", "X", "x", "x", "X", "X", "x", "x", "x", "x", "x", "x", "X", 
"X", "X", "X", "X", "X", "X", "X", "x", "x", "x", "x", "x", "x", 
"x", "X", "X", "X", "X", "X", "X", "x", "X", "X", "X", "x", "x", 
"x", "X", "X", "X")), row.names = c(NA, -50L), class = c("tbl_df", 
"tbl", "data.frame"))

目前,我的结果看起来像Before,但我的目标是After

期待您的帮助。

【问题讨论】:

  • 您导入的数据似乎具有某种嵌套结构:Wall type (Kaminski 2019) > Order > Superfamily > Genus > Species(好像数据在枢轴中桌子?)。结果all_data_final 最终变得非常不整洁。您能否澄清一下“因为我正在处理字符串,所以我留下了重复项” 是什么意思?从您在链接中提供的示例输出中,您似乎期望每个物种有一行,其中Wall type (Kaminski 2019):Genus 的值取自all_data_final 中最“完整”的行。是这样吗?
  • @Hendrik van Broekhuizen,是的......我试图让每个物种一排
  • 要为每个Species 获取一行(根据您的输出示例),所有其他列的值 (Wall type (Kaminski 2019):authority) 对于每个给定的Species 必须保持一致。输入数据中大量的拼写不一致意味着all_data_final 根本不是这种情况。例如。第 8 行和第 9 行中Family 的拼写(“Acervulinoidae”与“Acervulinidae”)。如果您希望从pivot_wider() 获得合理的结果,则需要修复输入数据中的这些和所有其他不一致。
  • @Hendrik van Broekhuizen,感谢您的帮助....
  • @Hendrik van Broekhuizen,只是为了澄清您上面的 cmets ...即使您决定仅使用种类列而忽略其他所有列。e。物种,位置和案例要广泛转向,它仍然无济于事。这比您的评论所暗示的要复杂。

标签: r dplyr tidyverse data-cleaning stringi


【解决方案1】:

...即使您决定只使用种类列而忽略其他列。e。物种,位置和案例要广泛转向,它仍然无济于事。

实际上,只需最少的争吵,它确实有帮助。

这比您的评论所暗示的要复杂。

我不相信它是:

# load libraries
library(tidyverse)

# define data using the structure posted in the initial question

# create all_data_final_wider by taking all_data_final %>% remove all
# leading/trailing white space %>% convert cases column to lowercase %>% select
# columns to retain %>% remove exact duplicates %>% pivot from long to wide
all_data_final_wider <- all_data_final %>% 
  mutate_all(str_squish) %>% 
  mutate(cases = str_to_lower(cases)) %>% 
  select(Species, location, cases) %>% 
  distinct() %>% 
  pivot_wider(names_from = location, values_from = cases)

# prove that there are as many rows in all_data_final_wider as there are
# distinct spellings of the Species column
nrow(all_data_final_wider) == length(unique(all_data_final_wider$Species))
#> [1] TRUE

所以我支持我的 cmets:

如果您希望从pivot_wider() 获得合理的结果,则需要修复输入数据中的这些和所有其他不一致问题

【讨论】:

    【解决方案2】:

    正如@hendrikvanb 指出的那样,您的重复输出行不仅是由于字符串,还包括不完整的数据和某些输入字符串的细微差异。即使两个字符串对于人类读者来说包含相同的信息,R 也会将它们视为不同的,除非每个字符都相同。一旦我们解决了这个问题,解决方案就会容易得多。

    第 1 步:确保名称相似的条目具有相同的名称

    以下代码从一些简单的整理开始(去除多余的空白,使所有内容都小写)。然后它会在您的表格中搜索相似的文本,并且对于每一对都会询问您是否要将其中一个替换为另一个。

    例如如果您的数据集包含“levi et al. 1990”和“levi et al 1990”,其中一个带有句号而另一个没有,您将收到一条消息:

    您想用“levi et al 1990”替换“levi et al. 1990”吗?

    同样的问题也会以相反的顺序被问到。如果单击“是”,则第一个的所有实例都将被数据库中的第二个替换。

    library(dplyr)
    library(tidyr)
    
    # standardise
    standardized <- all_data_final %>%
      rename(walltype = `Wall type (Kaminski 2014)`) %>% # first column in example data has odd name
      mutate_all(as.character) %>%                      # ensures all columns are string not factor
      mutate_all(trimws) %>%                            # leading and trailing white space
      mutate_all(function(x){gsub(" +"," ",x)}) %>%     # remove internal duplicate spaces
      mutate_all(tolower) %>%                           # cast everything to lower
      mutate(row = row_number())
    
    # prompt user to merge text that is very close together
    tollerance = 2
    cols <- c("walltype", "Order", "Superfamily", "Family", "Genus", "Species", "authority", "location")
    
    for(col in cols){
      unique_vals = standardized[[col]] %>% unique() %>% sort()
    
      for(val in unique_vals){
        for(val2 in unique_vals){
          # check if text strings are within edit distance of each other
          if(adist(val, val2) > 0 & adist(val, val2) <= tollerance){
            msg = paste0("Do you want [", val, "] replaced with [", val2, "] ?")
            ans = FALSE
            ans = askYesNo(msg) # ask user for every pair of close values
    
            if(ans)
              standardized <- mutate_all(standardized, function(x){ifelse(x == val, val2, x)})
    
          }
        }
      }
    }
    

    您可以通过调整tollerance 参数来控制此检查的灵敏度。您可以将其视为正确文本和拼写错误之间的字符数。

    第 2 步:保留可用的类别文本信息

    这里的目标是确保如果该物种的一个记录具有目、科、属或权威,那么它会出现在决赛桌中。我们可以通过询问每个物种的最大目数/科/属来做到这一点。

    处理文本时,max 按字母顺序返回最后一条记录。空白或空白首先排序到顶部,因此我们必须使用max,因为min 将返回空文本字段。

    此代码合并到第 3 步中。

    第 3 步:在可用的地方保留大小写标记

    通过将 case 列转换为数字,我们可以汇总不同的 case,寻找最大值 1。在某些情况下,NA 或 NULL 被视为 -Inf,因此我们也处理此问题。

    以下代码在同一 summarise_all 语句中解析第 2 步和第 3 步。

    # collapse
    final_result <- standardized %>%
      mutate(cases = ifelse(!is.na(cases), 1, 0)) %>%
      pivot_wider(names_from = location, values_from = cases) %>%
      group_by(Species) %>%
      summarise_all(max, na.rm = TRUE) %>%                   # hack, ideally we'd handle strings and numbers differently
      mutate_all(function(x){ifelse(is.infinite(x), NA, x)}) # gets rid of -Inf caused by summarise_all
    

    这是我从这段代码中得到的dput 输出:

    
    structure(list(Species = c("", "?planorbulina sp . 1", "acervulina cf. a. mahabethi", 
    "acervulina inhaerens", "acervulina mabahethi", "acervulina sp. 01", 
    "adelosina bicornis", "adelosina carinatastriata", "adelosina cf. a. mediterranensis", 
    "adelosina crassicarinata", "adelosina dagornae", "adelosina echinata", 
    "adelosina honghensis"), walltype = c("", "hyaline", "hyaline", 
    "hyaline", "hyaline", "hyaline", "", "porcelaneous (imperforate)", 
    "porcelaneous (imperforate)", "porcelaneous (imperforate)", "porcelaneous (imperforate)", 
    "porcelaneous (imperforate)", "porcelaneous (imperforate)"), 
        Order = c("", "rotaliida", "rotaliida", "rotaliida", "rotaliida", 
        "rotaliida", "", "miliolida", "miliolida", "miliolida", "miliolida", 
        "miliolida", "miliolida"), Superfamily = c("", "planorbulinoidea", 
        "acervulinoidea", "acervulinoidea", "acervulinoidea", "acervulinoidea", 
        "milioloidea", "milioloidea", "milioloidea", "milioloidea", 
        "milioloidea", "milioloidea", "milioloidea"), Family = c("", 
        "planorbulinidae", "acervulinidae", "acervulinidae", "acervulinidae", 
        "acervulinidae", "cribrolinoididae", "hauerinidae", "cribrolinoididae", 
        "cribrolinoididae", "cribrolinoididae", "cribrolinoididae", 
        "cribrolinoididae"), Genus = c("", "?planorbulina", "acervulina", 
        "acervulina", "acervulina", "acervulina", "adelosina", "quinqueloculina", 
        "adelosina", "adelosina", "adelosina", "adelosina", "adelosina"
        ), authority = c("haynesina sp.", "d'orbigny, 1826", "said, 1949", 
        "schultze, 1854", "said, 1949", "schultze, 1854", "walker & jacob, 1798", 
        "wiesner 1923", "le calvez & le calvez, 1958", "", "levi et al. 1990", 
        "d'orbigny, 1826", "lak, 1982"), row = c(2L, 3L, 5L, 7L, 
        9L, 11L, 13L, 27L, 28L, 32L, 40L, 44L, 50L), `parkar and gischler 2015` = c(1, 
        NA, NA, NA, 1, NA, NA, 1, NA, NA, NA, NA, NA), `present study` = c(1, 
        NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), `cherif et al. 1997` = c(NA, 
        1, NA, NA, NA, NA, NA, 1, NA, 1, NA, 1, 1), `amao et al. 2016 mp` = c(NA, 
        NA, 1, NA, NA, 1, NA, 1, 1, NA, NA, NA, NA), amao_et_al_2019_persian_gulf_paper = c(NA, 
        NA, 1, NA, NA, 1, NA, NA, NA, NA, NA, NA, NA), `murray 1965` = c(NA, 
        NA, NA, 1, NA, NA, NA, NA, NA, NA, NA, NA, NA), `shublak 1977` = c(NA, 
        NA, NA, 1, NA, NA, 1, NA, NA, NA, NA, NA, NA), `khader 2020` = c(NA, 
        NA, NA, NA, NA, NA, 1, 1, NA, NA, 1, 1, 1), `al-zamel et al 1996` = c(NA, 
        NA, NA, NA, NA, NA, NA, 1, NA, 1, NA, NA, NA), `al-zamel et al 2009` = c(NA, 
        NA, NA, NA, NA, NA, NA, 1, NA, NA, 1, NA, NA), `amao et al. 2016 salwa` = c(NA, 
        NA, NA, NA, NA, NA, NA, 1, NA, NA, NA, NA, NA), amao_et_al_2019_baseline_paper = c(NA, 
        NA, NA, NA, NA, NA, NA, 1, NA, NA, NA, NA, NA), `khader 1997` = c(NA, 
        NA, NA, NA, NA, NA, NA, 1, NA, NA, 1, NA, NA), `al-ghadban 2000` = c(NA, 
        NA, NA, NA, NA, NA, NA, 1, NA, NA, 1, 1, 1), `al-theyabi 2012b` = c(NA, 
        NA, NA, NA, NA, NA, NA, 1, NA, NA, NA, NA, NA), `al-enezi et al. 2019` = c(NA, 
        NA, NA, NA, NA, NA, NA, 1, NA, NA, NA, NA, NA), `al-zamel & cherif 1998` = c(NA, 
        NA, NA, NA, NA, NA, NA, NA, NA, 1, NA, NA, NA), `al-enezi & frontalini 2015` = c(NA, 
        NA, NA, NA, NA, NA, NA, NA, NA, 1, 1, NA, NA), `al-ammar 2011` = c(NA, 
        NA, NA, NA, NA, NA, NA, NA, NA, NA, 1, NA, NA), `al-enezi and frontalini 2015` = c(NA, 
        NA, NA, NA, NA, NA, NA, NA, NA, NA, 1, NA, NA), `al-shuaibi 1997` = c(NA, 
        NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 1, NA), `clark and keiji 1975` = c(NA, 
        NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 1), `nabavi 2014` = c(NA, 
        NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 1)), class = c("tbl_df", 
    "tbl", "data.frame"), row.names = c(NA, -13L))
    

    【讨论】:

    • 感谢您的帮助,这正是我想要实现的目标。
    • 不客气。现在您所寻求的解决方案已经很清楚了,我将编辑您的问题的标题,以更好地反映合并非常相似的字符串所面临的挑战。
    猜你喜欢
    • 1970-01-01
    • 2020-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-25
    • 2021-03-18
    • 2017-11-16
    • 1970-01-01
    相关资源
    最近更新 更多