R'deki tutarsız formattaki verilerin temizlenmesi?


16

Herhangi bir istatistik yapılmadan önce çok fazla temizlik gerektiren dağınık anket verileriyle sık sık ilgilenirim. Bunu Excel'de, bazen Excel formüllerini kullanarak ve bazen girişleri tek tek kontrol ederek yapıyordum. R'de bunları yapmak için komut dosyaları yazarak bu görevlerin gittikçe daha fazlasını yapmaya başladım, ki bu çok yararlı oldu (faydalar yapılanların kaydını tutmayı, hata olasılığını azaltmayı ve veri kümesi varsa kodu tekrar kullanabilmeyi içerir güncellenmiş).

Ama yine de verimli bir şekilde idare etmekte zorlandığım bazı veri türleri var. Örneğin:

> 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.daybelirli bir etkinliğe harcanan günlük ortalama saat sayısı anlamına gelir, ancak elimizde tam olarak konunun yazdığı şeydir. Belirsiz yanıtlarla ne yapacağım konusunda bazı kararlar verdiğimi ve toplanan değişkeni hours.per.day2aşağıdaki gibi istediğimizi varsayalım .

   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

Vaka sayısının oldukça fazla olduğunu varsayarsak (1000 diyelim) ve deneklerin sevdikleri herhangi bir şeyi yazmakta özgür olduklarını bilerek buna yaklaşmanın en iyi yolu nedir?

Yanıtlar:


13

Ben bildiğim dizeleri tanımlamak için gsub () kullanmak ve daha sonra belki de geri kalanı elle yapmak.

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)

Elle değiştirmeniz gerekenlerle çalışmak için şöyle bir şey öneriyorum:

# 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])
}

Bu şunu verir:

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

Regex biraz zor olabilir, regex ile her şey yaptığımda birkaç basit test yapıyorum. Kullanım kılavuzuna bakınız. İşte bazı temel davranışlar:

> # 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"

Cevabınız için teşekkürler Max. Düzenli ifadelere aşina değilim, bu yüzden onları öğrenmek zorunda kalacaksınız. Gerisini el ile nasıl yapacağınıza dair kısa bir açıklama yapmak ister misiniz? Sadece böyle bir şey yaptığını daha iyi bir yolu var mı new_var[by.hand] <- c(2, 1, ...)ile by.handvarlık TRUEelde gerçekleştirilir durumlar için?
mark999

@ mark999: Bazı örnekler ve bunları elle nasıl yapabileceğinize dair bir öneri eklendi.
Max Gordon

1
Düzenli ifadeler her türlü veri manipülasyonu için çok önemlidir: OP'nin sahip olduğu gibi verileri temizlemek veya dosyalardan, HTML'den vb. XMLVeri çıkarmak için. HTML hatalı biçimlendirildiğinde çalışmaz.)
Wayne

6

@ Max'in önerisi iyi. Görünüşe göre sayıları ve zamanla ilişkili ortak kelimeleri / kısaltmaları tanıyan bir algoritma yazarsanız, bu yoldan en iyi şekilde yararlanabilirsiniz. Bu güzel bir kod olmayacak, ancak işe yarayacak ve sorunlu vakalarla karşılaştıkça zaman içinde iyileştirebilirsiniz.

Ancak daha sağlam (ve başlangıçta zaman alıcı) bir yaklaşım için, Google'ı "doğal bir dil zaman dizgisini ayrıştırmayı" deneyin. Bazı ilginç bulgular Bu açık zaman API , iyi bir Python modülü ve Stack Overflow'da bunun gibi birçok almanca iş parçacığından biridir .

Temel olarak, doğal dil ayrıştırma yaygın bir sorundur ve R dışındaki dillerde çözüm aramalısınız. R kullanarak erişebileceğiniz başka bir dilde araçlar oluşturabilirsiniz veya en azından kendi algoritmanız için iyi fikirler edinebilirsiniz.


4

Böyle bir şey için, yeterince uzun olsaydı, düzenli ifadeler ve dönüşüm kurallarının bir listesini istiyorum ve yeni değerleri başka bir sütuna götürürüm (böylece ham verileri yeniden yüklemeden her zaman iki kez kontrol etme şansınız olur). ; RE'ler, tüm veriler dönüştürülene veya tüm kurallar tükenene kadar bugüne kadar dönüştürülmemiş verilere uygulanacaktır. Hangi satırların henüz dönüştürülmediğini gösteren mantıksal değerlerin bir listesini tutmak muhtemelen en iyisidir.

Bu tür birkaç kural elbette açıktır ve muhtemelen vakaların% 80-90'ını ele alacaktır, ancak sorun her zaman bilmediğiniz bazılarının olacağıdır (insanlar çok yaratıcıdır).

Daha sonra, henüz açıklanmamış kurallar listesi değerlerinin orijinallerini birer birer size sunan ve size düzenli bir ifade yapma şansı veren bir komut dosyasına ihtiyacınız var ( ) bu durumları tanımlamak ve buna uyan durumlar için yeni bir dönüşüm vermek , orijinal listeye ekler ve size sunulması gereken herhangi bir durum olup olmadığını kontrol etmeden önce orijinal vektörün henüz dönüştürülmemiş satırlarına uygulanır. .

Ayrıca bir vakayı atlama seçeneğine sahip olmak da mantıklı olabilir (böylece daha kolay olanlara devam edebilirsiniz), böylece çok zor vakaları sonuna kadar itebilirsiniz.

En kötü durum, birkaç tane elle yapıyorsunuz.

Ardından, veriler büyüdüğünde veya yeni, benzer bir veri kümesi geldiğinde tekrar uygulamak için, oluşturduğunuz kuralların tam listesini tutabilirsiniz.

Uzaktan en iyi uygulamaya yaklaşıp yaklaşmadığını bilmiyorum (orada çok daha resmi bir şeye ihtiyaç olacağını düşünürdüm), ancak bu tür verilerin büyük miktarlarını hızlı bir şekilde işlemek için bir miktar değeri olabilir.


Cevabınız için teşekkürler Glen. Kulağa çok çekici geliyor. Henüz dönüştürülmemiş değerlerin, hepsini görüntülemenin ve bu çıktıya bakmanın aksine, birer birer sunulmasının büyük bir avantaj olduğunu düşünüyor musunuz? Ben her zaman bir şeyler sunmak gibi bir şey yapmadım
mark999

1
@ mark999, her seferinde bir sunumun hem avantajları hem de dezavantajları olduğunu düşünürdüm. Avantaj, basitliktir - belirsiz bir zaman göstermek için cat () kullanmak ve o zamanla ilgili yorumunuzu kaydetmek için scan () kullanmak kolaydır. Dezavantajı, tek bir regex kodu satırında toplu olarak düzeltebileceğiniz birçok girişin büyük resmini kaçırabilirsiniz. Ne elde etmeyi umduğunuzu düşünebilirsiniz: sadece bu sorunu çözmek istiyorsanız, elle yapın. R hakkında daha fazla bilgi edinmek istiyorsanız bir çözümü kodlamayı deneyin.
Ash

Yanıt eksikliği için özür dilerim; Ash'in yorumuna genel olarak katılıyorum
Glen_b-Monica'yı eski durumuna döndür

4

R, bir içeren standart onun içinde, veri temizleme için kullanılabilecek veri manipülasyonu için fonksiyonlar, taban paketi ( gsub, transformörneğin, vs.) yanı sıra, çeşitli üçüncü taraf paketlerini stringr , reshape , reshape2 ve plyr . Bu paketlerin ve işlevlerinin kullanım örnekleri ve en iyi örnekleri aşağıdaki makalede açıklanmıştır: http://vita.had.co.nz/papers/tidy-data.pdf .

Ek olarak, R özellikle veri temizleme ve dönüştürmeye odaklanan bazı paketler sunar :

R'de veri temizlemeye kapsamlı ve tutarlı bir yaklaşım , düzenleme kuralları ve doğru olmayan paketlerin kullanımı ve R'deki veri temizliğinin iş akışının ( çerçeve ) bir açıklaması da dahil olmak üzere aşağıdaki makalede sunulmaktadır: http : : //cran.r-project.org/doc/contrib/de_Jonge+van_der_Loo-Introduction_to_data_cleaning_with_R.pdf .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.