Самый простой способ очистки сложных данных

Представьте набор данных:

df1 <- tibble::tribble(~City,   ~Year,  ~Coffee,    ~Tea,   ~Year,  ~Sugar, ~At,    ~Empty,
"NY",   "2020", "", "", "2020", "2",    "", "",
"NY",   "2019", "5",    "3",    "2019", "5",    "", "",
"City", "Year", "Coffee",   "Tea",  "Year", "Sugar",    "", "",
"ATL",  "2020", "", "", "2020", "2",    "", "",
"ATL",  "2019", "5",    "3",    "2019", "5",    "", "",
"Data input by: Alex",  "", "", "", "", "", "", "",
"BOS",  "Year", "", "Coffee",   "", "Tea",  "Sugar",    "",
"BOS",  "2020", "", "7",    "2020", "8",    "3",    "",
"BOS",  "2019", "", "7",    "2019", "7",    "2",    "",
"MS",   "Year", "Frappacino",   "Green Tea",    "", "Coffee",   "Sugar",    "",
"MS",   "2020", "5",    "6",    "2019", "8",    "3",    "",
"MS",   "2019", "5",    "5",    "2020", "8",    "3",    "",
"City", "Year", "Coffee",   "Tea",  "Year", "Sugar",    "At",   "",
"HW",   "2020", "500",  "300",  "2020", "200",  "", "",
"HW",   "2019", "450",  "320",  "2019", "180",  "", "",
"Data input by: Aleksanteri",   "", "", "", "", "", "", "",
"Kaupunki", "Vuosi",    "Kahvi",    "Tee",  "Vuosi",    "At",   "Sokeri",   "",
"HEL",  "2020", "7",    "4",    "2018", "", "4",    "",
"HEL",  "2019", "7",    "4",    "2019", "", "4",    "",
"HEL",  "2018", "6",    "3",    "2020", "", "5",    "")

Тот же набор данных (для визуального представления):

Проблемы:

  1. City ATL является ошибкой (это копия NY) [но мы не можем знать, существует ли такой шаблон]
  2. Два человека вводят данные в исходную базу данных (красные строки, первый столбец, но могут быть в любом месте строки).
  3. ЛС смещается на одну ячейку, начиная с года; второе название "Год" отсутствует
  4. У MS есть фраппачино и зеленый чай, но нет данных о чае :(
  5. У MS данные о кофе перевернуты по годам (2020 — это 2019, а 2019 — это 2020).
  6. У HW неправильный ввод валюты (слишком разные числа); правильная валюта — X/100 (500 HW — это 5 (500/100))
  7. HEL имеет финские названия столбцов на входе (а хотелось бы, чтобы данные в контроле не сдвигались); чтобы мы знали: Vuosi = Год; Каупунки = Город; Кахви = Кофе; Тройник = Чай; Сокери = Сахар :)
  8. В HEL есть разница в годах для Sokeri (сахар) по сравнению с Kahvi (кофе) и Tee (чай).
  • Пустой столбец полностью пуст (это может быть место для потенциальных сдвигов в данных [не наш случай].

Есть ли простой способ справиться с такими проблемами с данными?

Я только что столкнулся с этой проблемой. Я решал ее одну за другой, а затем остановился на идее, что должен быть простой метод для всего.

слишком много вопросов, чтобы найти простые условия. Я бы порекомендовал преобразовать его в Excel.

Roman 16.01.2023 11:55

Спасибо, Роман. Это может быть хорошо именно для этого набора данных. Но если у вас огромный набор данных, это усложняет использование Excel. Буду благодарен даже за самое простое среди сложных решений :)

Alexander Shemetev 16.01.2023 11:58

Единственный успех, который у меня был с подобными наборами данных, — это чтение их по строкам и обдумывание «откуда мне знать, что делать с каждой строкой» и, таким образом, сборка ряда правил. Это медленная и раздражающая работа по его настройке.

Paul Stafford Allen 16.01.2023 11:58

Спасибо, Пол! Я сделал алгоритм, который уменьшает количество ячеек, которые нужно искать (что помогает). Но я уверен, что должно быть какое-то более простое решение. Пожалуйста, не стесняйтесь выражать любые идеи или коды :)

Alexander Shemetev 16.01.2023 12:01

Проблемы с фактическим набором данных все те же :) Итак, я попытался воспроизвести проблемы на примере небольшого набора данных :)

Alexander Shemetev 16.01.2023 12:03

Предполагая, что годы не перекошены по горизонтали, и в вашем выводе вы можете сократить столбец до одного года, вы можете расплавить свою таблицу на c("City", "Year"). Затем интерпретируйте столбец значений для тех, которые представляют собой строку букв, сравните их с переменной и исправьте столбец переменной, где это необходимо.

Merijn van Tilborg 16.01.2023 13:43

OpenRefine можно использовать для исследовательского анализа и обработки данных, но это все равно будет процесс, в значительной степени управляемый человеком.

Tom Morris 16.01.2023 22:16
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
7
60
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Немного быстро и грязно, и вам может понадобиться некоторая тонкая настройка, если ваши данные еще более изменчивы, чем я предполагал.

Ключевым требованием в моем подходе является то, что ваша первая строка, по крайней мере, город, имеет правильное имя и что год правильно назван в первой строке и в известной позиции (вы можете найти его по именам вашей таблицы. Но годы не могут быть перекошены по столбцам.

Я использую data.table здесь

library(data.table)

setDT(df1)

# find the year columns
cols <- names(df1)
ypos <- last(which(cols %in% "Year"))

# split your data to deal with differences in years per row (for HEL)
dt <- rbindlist(list(df1[, 1L:(ypos-1L), with = F], df1[, c(1L, ypos:length(cols)), with = F]), fill = T)

# melt data and take the first row as headers we will fix later on
# this only works though when you know the Year column is never shifted to another column
dt <- melt.data.table(dt, id.vars = c("City", "Year"), variable.factor = F)

dt <- dt[!(Year == "" & value == ""),]
dt <- dt[, City := fifelse(City %in% c("City", "Kaupunki"), shift(City, type = "lead"), City)]
dt <- dt[!(value == "" | value == "At")]

v_f <- c("Kahvi", "Tee", "Sokeri")
v_t <- c("Coffee", "Tea", "Sugar")
dt[, value := str_replace_all(value,setNames(v_t, v_f))]

dt[, new_variable := first(value), rleid(City)]
dt[is.na(as.numeric(new_variable)), variable := new_variable][, new_variable := NULL]
dt[, value := as.numeric(value)]
dt <- dt[!is.na(value)]
dt[, value := fifelse(value > 100, value / 100, value)]

dcast(dt, City + Year ~ variable, value.var = "value")

Полученные результаты

    City Year Coffee Frappacino Green Tea Sugar Tea
 1:  ATL 2019    5.0         NA        NA   5.0 3.0
 2:  ATL 2020     NA         NA        NA   2.0  NA
 3:  BOS 2019    7.0         NA        NA   2.0 7.0
 4:  BOS 2020    7.0         NA        NA   3.0 8.0
 5:  HEL 2018    6.0         NA        NA   4.0 3.0
 6:  HEL 2019    7.0         NA        NA   4.0 4.0
 7:  HEL 2020    7.0         NA        NA   5.0 4.0
 8:   HW 2019    4.5         NA        NA   1.8 3.2
 9:   HW 2020    5.0         NA        NA   2.0 3.0
10:   MS 2019    8.0          5         5   3.0  NA
11:   MS 2020    8.0          5         6   3.0  NA
12:   NY 2019    5.0         NA        NA   5.0 3.0
13:   NY 2020     NA         NA        NA   2.0  NA

Другие вопросы по теме