Очищення даних невідповідного формату в R?


16

Я часто маю справу з брудними даними опитування, які вимагають багато очищення, перш ніж стати статистикою. Я раніше робив це "вручну" в Excel, іноді використовуючи формули Excel, а іноді перевіряючи записи окремо. Я почав робити все більше і більше цих завдань, написавши сценарії, щоб виконати їх в R, що було дуже корисно (до переваг можна віднести запис про зроблене, менший шанс помилок та можливість повторного використання коду, якщо набір даних є оновлено).

Але все ж є деякі типи даних, з якими я маю проблеми з ефективною обробкою. Наприклад:

> d <- data.frame(subject = c(1,2,3,4,5,6,7,8,9,10,11),
+   hours.per.day = c("1", "2 hours", "2 hr", "2hr", "3 hrs", "1-2", "15 min", "30 mins", "a few hours", "1 hr 30 min", "1 hr/week"))
> d
   subject hours.per.day
1        1             1
2        2       2 hours
3        3          2 hr
4        4           2hr
5        5         3 hrs
6        6           1-2
7        7        15 min
8        8       30 mins
9        9   a few hours
10      10   1 hr 30 min
11      11     1 hr/week

hours.per.dayмається на увазі середня кількість годин на день, проведених на певну діяльність, але у нас є саме те, що написав предмет. Припустимо, я приймаю деякі рішення щодо того, що робити з неоднозначними відповідями, і я хочу, щоб виправлена ​​змінна зміна була hours.per.day2наступною.

   subject hours.per.day hours.per.day2
1        1             1      1.0000000
2        2       2 hours      2.0000000
3        3          2 hr      2.0000000
4        4           2hr      2.0000000
5        5         3 hrs      3.0000000
6        6           1-2      1.5000000
7        7        15 min      0.2500000
8        8       30 mins      0.5000000
9        9   a few hours      3.0000000
10      10   1 hr 30 min      1.5000000
11      11     1 hr/week      0.1428571

Якщо припустити, що кількість випадків досить велика (скажімо, 1000), і знаючи, що випробувані можуть вільно писати все, що їм подобається, який найкращий спосіб підійти до цього?

Відповіді:


13

Я б використовував gsub () для визначення рядків, які я знаю, а потім, можливо, робити все вручну.

test <- c("15min", "15 min", "Maybe a few hours", 
          "4hr", "4hour", "3.5hr", "3-10", "3-10")
new_var <- rep(NA, length(test))

my_sub <- function(regex, new_var, test){
    t2 <- gsub(regex, "\\1", test)
    identified_vars <- which(test != t2)
    new_var[identified_vars] <- as.double(t2[identified_vars])
    return(new_var)    
}

new_var <- my_sub("([0-9]+)[ ]*min", new_var, test)
new_var <- my_sub("([0-9]+)[ ]*(hour|hr)[s]{0,1}", new_var, test)

Для роботи з тими, які потрібно змінити вручну, я пропоную щось подібне:

# Which have we not found
by.hand <- which(is.na(new_var))

# View the unique ones not found
unique(test[by.hand])
# Create a list with the ones
my_interpretation <- list("3-10"= 5, "Maybe a few hours"=3)
for(key_string in names(my_interpretation)){
    new_var[test == key_string] <- unlist(my_interpretation[key_string])
}

Це дає:

> new_var
[1] 15.0 15.0  3.0  4.0  4.0  3.5  5.0  5.0

Regex може бути трохи хитрим, кожен раз, коли я роблю що-небудь з regex, я проводжу кілька простих тестів. Segegege для посібника. Ось деякі основні дії:

> # Test some regex
> grep("[0-9]", "12")
[1] 1
> grep("[0-9]", "12a")
[1] 1
> grep("[0-9]$", "12a")
integer(0)
> grep("^[0-9]$", "12a")
integer(0)
> grep("^[0-9][0-9]", "12a")
[1] 1
> grep("^[0-9]{1,2}", "12a")
[1] 1
> grep("^[0-9]*", "a")
[1] 1
> grep("^[0-9]+", "a")
integer(0)
> grep("^[0-9]+", "12222a")
[1] 1
> grep("^(yes|no)$", "yes")
[1] 1
> grep("^(yes|no)$", "no")
[1] 1
> grep("^(yes|no)$", "(yes|no)")
integer(0)
> # Test some gsub, the \\1 matches default or the found text within the ()
> gsub("^(yes|maybe) and no$", "\\1", "yes and no")
[1] "yes"

Дякую за відповідь Макс. Я не знайомий з регулярними виразами, тому доведеться дізнаватися про них. Ви б не хотіли дати короткий опис того, як ви будете займатися рештою вручну? Чи є кращий спосіб , ніж просто робити що - щось подібне new_var[by.hand] <- c(2, 1, ...)з by.handтого , TRUEза винятком випадків , які зроблені вручну?
mar999

@ mark999: Додано кілька прикладів та пропозиція, як можна робити їх вручну.
Макс Гордон

1
Регулярні вирази є надзвичайно важливими для будь-якого типу маніпулювання даними: очищення даних, як це має ОП, або вилучення даних з файлів, HTML тощо. (Для правильного HTML є бібліотеки, XMLякі допомагають вам витягувати дані, але це не працює, коли HTML неправильно сформований.)
Уейн

6

@ Пропозиція Макса хороша. Здається, що якщо ви пишете алгоритм, який розпізнає числа, а також загальні пов’язані з часом слова / скорочення, ви отримаєте більшу частину шляху там. Це не буде прекрасним кодом, але він буде працювати, і ви можете його вдосконалити з часом, коли ви натрапите на проблемні випадки.

Але для більш надійного (і спочатку трудомісткого) підходу спробуйте Гуглінг "розбирати часовий рядок природної мови". Деякі цікаві висновки - це API відкритого часу , хороший модуль Python та одна з багатьох німецьких потоків, як ця у Stack Overflow .

В основному, розбір природних мов є поширеною проблемою, і ви повинні шукати рішення іншими мовами, ніж R. Ви можете створювати інструменти на іншій мові, до якої можна отримати доступ, використовуючи R, або, принаймні, ви можете отримати хороші ідеї для власного алгоритму.


4

Для чогось подібного, якби він був достатньо довгим, я думаю, я хотів би переглянути список регулярних виразів і правил перетворення і перенести нові значення в інший стовпець (так що ви завжди маєте можливість подвоїти перевірку, не перезавантажуючи необроблені дані) ; ПЗ застосовуватимуться для того, щоб не поки що трансформовані дані до тих пір, поки всі дані не були перетворені або не були вичерпані всі правила. Напевно, найкраще також зберігати список логічних значень, які вказують, які рядки ще не перетворені.

Кілька таких правил очевидно, звичайно, і вони, ймовірно, вирішуватимуть 80-90% випадків, але проблема полягає в тому, що завжди знайдуться такі, яких ви не знаєте, що з’являться (люди дуже винахідливі).

Тоді вам потрібен сценарій, який проходить і представляє оригінали ще не перетворених за списком очевидних правил для вас по черзі, даючи вам можливість скласти регулярний вираз (скажімо ) ідентифікувати ці випадки та надати нову трансформацію для тих випадків, які їй підходять, яку вона додає до оригінального списку та стосується ще не перетворених рядків вихідного вектора перед тим, як перевірити, чи є ще якісь випадки, щоб представити вам .

Також може бути розумним можливість пропустити справу (щоб ви могли перейти до більш легких), так що ви можете підштовхнути дуже важкі справи до кінця.

Найгірший випадок, ви робите кілька вручну.

Потім ви можете зберегти повний перелік створених вами правил і застосувати знову, коли дані зростають або з'явиться новий, подібний набір даних.

Я не знаю, чи віддалено наближається до найкращої практики (я думаю, що там знадобиться щось набагато формальніше), але з точки зору швидкої обробки великої кількості таких даних це може мати певну цінність.


Дякую за відповідь, Глен. Це звучить дуже привабливо. Чи вважаєте ви великою перевагою представлення ще не перетворених значень одне за одним, на відміну від того, щоб просто відображати їх і дивитись на цей результат? Я ніколи не робив нічого подібного, щоб речі були представлені одна за одною.
mar999

1
@ mark999, я думаю, що є одночасно і презентації, і недоліки. Перевагою є простота - використання cat () для відображення неоднозначного часу, а сканування () для запису вашої інтерпретації того часу легко реалізувати. Недоліком є ​​те, що ви можете пропустити велику картину з великою кількістю записів, які ви могли б масово виправити одним рядком коду регулярного виразу. Ви можете подумати над тим, що ви сподіваєтесь отримати: якщо ви просто хочете вирішити цю проблему, зробіть це вручну. Якщо ви хочете дізнатися більше про R, спробуйте кодувати рішення.
Еш

Вибачте за відсутність відповіді; Я широко згоден з коментарем
Еша

4

R містить деякі стандартні функції для обробки даних, які можна використовувати для очищення даних, у своєму базовому пакеті ( gsub, transformтощо), а також у різних сторонніх пакетах, таких як stringr , reshape , reshape2 та plyr . Приклади та найкращі практики використання цих пакунків та їх функцій описані в наступній роботі: http://vita.had.co.nz/papers/tidy-data.pdf .

Крім того, R пропонує деякі пакети, спеціально орієнтовані на очищення та трансформацію даних:

Комплексний та узгоджений підхід до очищення даних у R, включаючи приклади та використання пакетів редагувань та дедукцій , а також опис робочого процесу ( рамки ) очищення даних в R, представлений у наступному документі, який я настійно рекомендую: http : //cran.r-project.org/doc/contrib/de_Jonge+van_der_Loo-Introduction_to_data_cleaning_with_R.pdf .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.