Sự khác biệt trong việc thực hiện phân tách nhị phân trong cây quyết định


12

Tôi tò mò về việc triển khai thực tế phân chia nhị phân trong cây quyết định - vì nó liên quan đến các cấp độ của một công cụ dự đoán phân loại .Xj

Cụ thể, tôi thường sẽ sử dụng một số loại sơ đồ lấy mẫu (ví dụ: đóng bao, quá khổ, v.v.) khi xây dựng mô hình dự đoán bằng cây quyết định - để cải thiện độ chính xác và ổn định dự đoán của nó. Trong các thói quen lấy mẫu này, có thể đưa ra một biến phân loại cho thuật toán khớp cây với ít hơn mức hoàn chỉnh.

Nói một biến X mất trên các cấp {A,B,C,D,E}. Trong một mẫu, có thể chỉ có các cấp độ {A,B,C,D}. Sau đó, khi cây kết quả được sử dụng để dự đoán, toàn bộ có thể có mặt.

Tiếp tục từ ví dụ này, giả sử một cây tách ra trên X và gửi {A,B}sang trái và {C,D}phải. Tôi sẽ mong đợi logic của phân tách nhị phân sẽ nói, khi phải đối mặt với dữ liệu mới: "Nếu X có giá trị A hoặc B, hãy gửi sang bên trái, nếu không, hãy gửi trường hợp này sang bên phải". Điều dường như xảy ra trong một số triển khai là "nếu X có giá trị A hoặc B, hãy gửi sang bên trái, nếu X có giá trị C hoặc D gửi sang bên phải". Khi trường hợp này nhận giá trị E, thuật toán bị hỏng.

Cách "đúng" để phân chia nhị phân được xử lý là gì? Có vẻ như cách mạnh mẽ hơn nhiều được thực hiện thường xuyên, nhưng không phải lúc nào cũng vậy (xem Rpart bên dưới).

Dưới đây là một vài ví dụ:

Rpart thất bại, những người khác là ok.

#test trees and missing values

summary(solder)
table(solder$PadType)

# create train and validation
set.seed(12345)
t_rows<-sample(1:nrow(solder),size=360, replace=FALSE)
train_solder<-solder[t_rows,]
val_solder<-solder[-t_rows,]

#look at PadType
table(train_solder$PadType)
table(val_solder$PadType)
#set a bunch to missing
levels(train_solder$PadType)[train_solder$PadType %in% c('L8','L9','W4','W9')] <- 'MISSING'


#Fit several trees, may have to play with the parameters to get them to split on the variable

####RPART
mod_rpart<-rpart(Solder~PadType,data=train_solder)
predict(mod_rpart,val_solder)
#Error in model.frame.default(Terms, newdata, na.action = na.action, xlev = attr(object,  : 
#factor 'PadType' has new level(s) D6, L6, L7, L8, L9, W4

####TREE
mod_tree<-tree(Solder~PadType,data=train_solder,split="gini")
predict(mod_tree,val_solder) #works fine

####ctree
mod_ctree<-ctree(Solder~PadType,data=train_solder,control = ctree_control(mincriterion = 0.05))
predict(mod_ctree,val_solder) #works fine

Câu trả lời:


9

Trong thực tế, có hai loại yếu tố - được sắp xếp (như Tiny <Nhỏ <Trung bình <Lớn <Lớn) và không có thứ tự (Dưa chuột, Cà rốt, Thì là, Aubergine).
Lớp đầu tiên giống như lớp liên tục - chỉ dễ dàng hơn để kiểm tra tất cả các pivots, cũng không có vấn đề gì với việc mở rộng danh sách cấp độ.
Đối với lớp thứ hai, bạn phải tạo một tập hợp các phần tử sẽ được hướng vào một nhánh, để phần còn lại vào nhánh khác - trong trường hợp này bạn có thể:

  1. lỗi ném
  2. giả sử rằng lớp vô hình đi vào chi nhánh yêu thích của bạn
  3. coi đây là NA và chọn chi nhánh theo cách ít ngẫu nhiên hơn.

Bây giờ, việc xử lý trực tiếp các yếu tố không có thứ tự là rất khó để nhiều thuật toán "gian lận" và tuyên bố các yếu tố không được sắp xếp là các yếu tố đã ra lệnh, vì vậy chúng thậm chí không chạm vào vấn đề này *. Phần còn lại thường sử dụng int mask, tức là tối ưu hóa một số nguyên từ đến và coi bit thứ là lựa chọn nhánh cho cấp độ yếu tố . (Bạn có bao giờ tự hỏi tại sao lại có giới hạn thường xuyên ở 32 cấp độ không?) Trong cài đặt này, điều khá tự nhiên là các mức độ không nhìn thấy sẽ âm thầm đi vào nhánh "0". Tuy nhiên, điều này dường như không quá "đúng", bởi vì tại sao chúng ta thực sự nên làm điều này? Và những gì về số lượng mức độ cần thiết để entropy đòn bẩy trong lựa chọn thuộc tính?12#Thể loại-1-1TôiTôi

Tôi muốn nói rằng ý tưởng hợp lý nhất là làm cho người dùng xác định đầy đủ các yếu tố (ví dụ R thực hiện việc này một cách hữu cơ, duy trì các mức thông qua các hoạt động tập hợp con) và sử dụng tùy chọn 1. cho các mức không khai báo và tùy chọn 2. cho các mức được khai báo . Tùy chọn 3. có thể có ý nghĩa nếu bạn đã có một số cơ sở hạ tầng xử lý NA.

*) Ngoài ra còn có chiến lược phụ để thực hiện một số mã hóa lại không tầm thường thành các số, như mã hóa Breiman chẳng hạn - nhưng điều này thậm chí còn tạo ra nhiều vấn đề hơn.


1
Bạn đang nói rằng ctree hoặc cây trong ví dụ của tôi thực sự coi yếu tố không có thứ tự này là một yếu tố có thứ tự và do đó gửi nó vào nhánh "0"?
B_Miner

@mbq bạn có thể vui lòng giải thích lý do tại sao tổng số cách bạn có thể thực hiện chia tách là 2 ^ (# loại + 1) - 2. Tôi không hiểu tại sao phần "-2".
kasa

Hmm, có vẻ như tôi đã làm hỏng công thức này; có 2 từ n-bit, nhưng chúng tôi không tính cả từ a và ~ a, vì vậy 2 ^ (n-1) và chúng tôi không thích chia tách mà không bị đổ, vì vậy 2 ^ (n-1) -1 (nói cách khác, chúng tôi đếm từ 1). n = 1 thì đó là trường hợp đặc biệt.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.