суммировать и распространять практически одинаковыми строками - PullRequest
2 голосов
/ 19 марта 2020

Я начал с нескольких необработанных 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"))

На данный момент мой результат выглядит До , но моя цель После

Спасибо в ожидании вашей помощи.

Ответы [ 2 ]

2 голосов
/ 25 марта 2020

Как указывает @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: сохраните метку регистра там, где она доступна

Преобразовав столбец регистра в цифру c, мы можем суммировать все случаи в поисках максимального значения 1. В некоторых случаях NA или NULL рассматривается как -Inf, поэтому мы также обрабатываем это.

Следующий код разрешает шаги 2 и 3 в одном и том же операторе summarise_all.

# 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))
0 голосов
/ 20 марта 2020

... даже если вы решите использовать только столбец видов, игнорируя все остальные столбцы.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

Поэтому я не отступаю от своих комментариев:

Вам нужно будет исправить эти и все другие несоответствия во входных данных, если вы ожидаете получить разумные результаты от pivot_wider()

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...