Paket R untuk mengkombinasikan tingkat faktor untuk datamining?

10

Ingin tahu apakah ada yang menjalankan paket / fungsi dalam R yang akan menggabungkan level faktor yang proporsinya dari semua level dalam faktor kurang dari ambang tertentu? Secara khusus, salah satu langkah pertama dalam persiapan data yang saya lakukan adalah meruntuhkan tingkat faktor yang jarang (katakanlah ke tingkat yang disebut 'Lain-lain') yang tidak membentuk setidaknya, katakanlah, 2% dari total. Ini dilakukan tanpa pengawasan dan dilakukan ketika tujuannya adalah untuk memodelkan beberapa kegiatan dalam pemasaran (bukan deteksi penipuan, di mana kejadian yang sangat kecil itu bisa sangat penting). Saya mencari fungsi yang akan runtuh level sampai sebagian ambang batas terpenuhi.

MEMPERBARUI:

Berkat saran-saran hebat ini saya menulis sebuah fungsi dengan cukup mudah. Namun saya menyadari bahwa adalah mungkin untuk menghancurkan level dengan proporsi <minimum dan masih memiliki level yang dikode ulang menjadi <minimum, membutuhkan penambahan level terendah dengan proporsi> minimum. Mungkin bisa lebih efisien tetapi tampaknya berhasil. Peningkatan selanjutnya adalah mencari cara untuk menangkap "aturan" untuk menerapkan logika runtuh ke data baru (satu set validasi atau data masa depan).

collapseFactors<- function(tableName,minPercent=5,fillIn ="RECODED" )
{
    for (i in 1:ncol(tableName))
        {   

            if(is.factor(tableName[,i]) == TRUE) #process just factors
            {


                sortedTable<-sort(prop.table(table(tableName[,i])))
                numberToCollapse<-length(sortedTable[sortedTable<(minPercent/100)])

                if (sum(sortedTable[1:numberToCollapse])<(minPercent/100))
                    {
                        numberToCollapse=numberToCollapse+1 #add next level if < minPercent
                    }

                if(numberToCollapse>1) #if not >1 then nothing to collapse
                {
                    lf <- names(sortedTable[1:numberToCollapse])
                    levels(tableName[,i])[levels(tableName[,i]) %in% lf] <- fillIn
                }
            }#end if a factor


        }#end for loop

    return(tableName)

}#end function
B_Miner
sumber
Untuk pendekatan lain: stats.stackexchange.com/questions/227125/…
kjetil b halvorsen

Jawaban:

11

Sepertinya itu hanya masalah "melepaskan" faktor; tidak perlu menghitung jumlah sebagian atau membuat salinan vektor asli. Misalnya,

set.seed(101)
a <- factor(LETTERS[sample(5, 150, replace=TRUE, 
                           prob=c(.1, .15, rep(.75/3,3)))])
p <- 1/5
lf <- names(which(prop.table(table(a)) < p))
levels(a)[levels(a) %in% lf] <- "Other"

Di sini, tingkat faktor asli didistribusikan sebagai berikut:

 A  B  C  D  E 
18 23 35 36 38 

dan kemudian menjadi

Other     C     D     E 
   41    35    36    38 

Mungkin mudah dibungkus menjadi suatu fungsi. Ada combine_factor()fungsi dalam paket membentuk kembali , jadi saya kira itu bisa berguna juga.

Juga, karena Anda tampaknya tertarik pada penambangan data, Anda mungkin melihat paket caret . Ini memiliki banyak fitur yang berguna untuk preprocessing data, termasuk fungsi-fungsi seperti nearZeroVar()yang memungkinkan untuk menandai prediktor dengan distribusi nilai-nilai yang diamati yang sangat tidak seimbang (Lihat sketsa, contoh data, fungsi pra-pemrosesan, visualisasi dan fungsi lainnya , hal. 5, misalnya penggunaan).

chl
sumber
@ CHI Terima kasih. Saya telah mempelajari paket caret dan menggunakannya untuk menyetel parameter meta. sangat berguna!.
B_Miner
@chl +1, bagus. Saya menulis fungsi saya semata-mata karena kode a [level (a)% dalam% lf] <- "Lainnya" tidak berfungsi, jadi saya berasumsi bahwa perubahan level faktor adalah urusan yang rumit. Seperti biasa ternyata, bahwa R tidak rumit, saya :)
mpiktas
@mpiktas Thx. Anda dapat bekerja pada level vektor dengan misalnya a[as.character(a) %in% lf] <- lf[1]; a <- factor(droplevels(a), labels=c("Other",LETTERS[3:5])),.
chl
+1. a [level (a)% in% lf] <- "Other" tentu saja menghemat satu ton baris kode. Pintar dan efisien!
Christopher Aden
Tetapi perhatikan bahwa [a == "a"] <- "Lainnya" tidak akan berfungsi, yang bagi saya cukup alami untuk menganggap bahwa itu seharusnya. Terutama karena [a == "a"] sangat valid.
mpiktas
5

Satu-satunya masalah dengan jawaban Christopher adalah bahwa itu akan mencampur urutan asli faktor tersebut. Ini perbaiki saya:

 Merge.factors <- function(x, p) {
     t <- table(x)
     levt <- cbind(names(t), names(t)) 
     levt[t/sum(t)<p, 2] <- "Other"
     change.levels(x, levt)
 }

di mana change.levelsfungsi berikut. Saya menulisnya beberapa waktu lalu, jadi saya curiga mungkin ada cara yang lebih baik untuk mencapai apa yang dilakukannya.

 change.levels <- function(f, levt) {
     ##Change the the names of the factor f levels from
     ##substitution table levt.
     ## In the first column there are the original levels, in
     ## the second column -- the substitutes
     lv <- levels(f)
     if(sum(sort(lv) != sort(levt[, 1]))>0)
     stop ("The names from substitution table does not match given level names")
     res <- rep(NA, length(f))

     for(i in lv) {
          res[f==i] <- as.character(levt[levt[, 1]==i, 2])
     }
     factor(res)
}
mpiktas
sumber
4

Saya menulis fungsi cepat yang akan mencapai tujuan ini. Saya pengguna R pemula, jadi mungkin lambat dengan tabel besar.

Merge.factors <- function(x, p) { 
    #Combines factor levels in x that are less than a specified proportion, p.
    t <- table(x)
    y <- subset(t, prop.table(t) < p)
    z <- subset(t, prop.table(t) >= p)
    other <- rep("Other", sum(y))
    new.table <- c(z, table(other))
    new.x <- as.factor(rep(names(new.table), new.table))
    return(new.x)
}

Sebagai contoh dalam aksi:

> a <- rep("a", 100)
> b <- rep("b", 1000)
> c <- rep("c", 1000)
> d <- rep("d", 1000)
> e <- rep("e", 400)
> f <- rep("f", 100)
> x <- factor(c(a, b, c, d, e, f))
> summary(x)
   a    b    c    d    e    f 
 100 1000 1000 1000  400  100 
> prop.table(table(x))
x
         a          b          c          d          e          f 
0.02777778 0.27777778 0.27777778 0.27777778 0.11111111 0.02777778 
> 
> w <- Merge.factors(x, .05)
> summary(w)
    b     c     d     e Other 
 1000  1000  1000   400   200 
> class(w)
[1] "factor"
Christopher Aden
sumber
Terima kasih atas pengamatannya, John. Saya telah mengubahnya sedikit untuk menjadikannya sebuah faktor. Yang saya lakukan adalah membuat ulang vektor asli dari tabel, jadi jika ada cara untuk melewati langkah itu, ini akan lebih cepat.
Christopher Aden
Terima kasih kepada semua orang yang merespons. R saya lemah tetapi kemampuan untuk melakukan ini dengan begitu sedikit baris kode merupakan bukti betapa kuatnya itu dan membuat saya ingin belajar.
B_Miner