2013-02-15 39 views
7

Một nhiệm vụ phổ biến trong thao tác dữ liệu trong R là tập hợp một khung dữ liệu bằng cách xóa các hàng phù hợp với một tiêu chí nhất định. Tuy nhiên, cách đơn giản để thực hiện điều này trong R dường như không phù hợp về mặt logic và thậm chí nguy hiểm đối với những người chưa từng trải nghiệm (như bản thân tôi).Cách đơn giản để xóa các dòng dữ liệu phù hợp với các trường hợp không có hàng nào phù hợp với tiêu chí xóa

phép nói rằng chúng tôi có một khung dữ liệu và chúng tôi muốn loại trừ hàng thuộc về việc điều trị "G1":

Treatment=c("G1","G1","G1","G1","G1","G1","G2","G2","G2","G2","G2", 
"G2","G3","G3","G3","G3","G3","G3") 
Vals=c(runif(6),runif(6)+0.9,runif(6)-0.3) 
data=data.frame(Treatment) 
data=cbind(data, Vals) 

Đúng như dự đoán, các mã dưới đây loại bỏ các hàng dataframe phù hợp với tiêu chí của người đầu tiên dòng

to_del=which(data$Treatment=="G1") 
new_data=data[-to_del,] 
new_data 

Tuy nhiên, trái với mong đợi, sử dụng phương pháp này nếu 'mà' lệnh không tìm thấy bất kỳ hàng phù hợp với mã này loại bỏ tất cả các hàng thay vì để tất cả chúng mình

to_del=which(data$Treatment=="G4") 
new_data=data[-to_del,] 
new_data 

Đoạn mã trên dẫn đến khung dữ liệu không có hàng, không có ý nghĩa (tức là, vì R không tìm thấy hàng phù hợp với tiêu chí xóa của tôi, nó đã xóa tất cả các hàng). công việc xung quanh tôi không được công việc nhưng tôi sẽ tưởng tượng có một cách đơn giản hơn để làm điều này mà không cần tất cả các báo cáo có điều kiện

###WORKAROUND 
to_del=which(data$Treatment=="G4") #no G4 treatment in this particular data frame 
if (length(to_del)>0){ 
    new_data=data[-to_del,] 
}else{ 
    new_data=data 
} 
new_data 

Có ai có một cách đơn giản để làm điều này mà làm việc ngay cả khi không có hàng phù hợp với tiêu chuẩn quy định ?

+0

+1: bị ấn tượng bởi những nỗ lực xung quanh công việc khéo léo. – Simon

+0

Cảm ơn các câu trả lời đơn giản và nhanh chóng. Cả hai cách tiếp cận do Joshua và Ricardo đề xuất đều hoạt động tốt: new_data = data [data $ Treatment! = "G4",] new_data = data [! Data $ Treatment == "G4",] –

Trả lời

6

Bạn đã gặp sự cố thường gặp khi sử dụng which. Sử dụng != để thay thế.

new_data <- data[data$Treatment!="G4",] 

Vấn đề là which lợi nhuận integer(0) nếu tất cả các yếu tố này là FALSE. Đây vẫn sẽ là một vấn đề ngay cả khi which trở 0 vì Subsetting bởi zero cũng trả integer(0):

R> # subsetting by zero (positive or negative) 
R> (1:3)[0] # same as (1:3)[-0] 
integer(0) 

Bạn cũng sẽ chạy vào các vấn đề nếu bạn tập hợp con của NA:

R> # subsetting by NA 
R> (1:3)[NA] 
[1] NA NA NA 
+0

Vì vậy, nếu '! =' trả về 'NA'; bất kỳ đề xuất trong trường hợp đó? (Tôi hỏi vì tôi đã sử dụng 'cái đó 'cho điều đó, và may mắn chưa bao giờ gặp vấn đề của OP, mặc dù bây giờ tôi lo lắng một ngày nào đó tôi có thể ...) – Aaron

+0

@Aaron: đó sẽ chỉ là vấn đề nếu kết quả chứa duy nhất 'NA'. Điều này sẽ vẫn hoạt động: '(1: 3) [c (TRUE, NA, FALSE)] # [1] 1 NA'. –

+0

Tôi đoán tôi thường chỉ muốn những cái là 'TRUE', không phải' NA'. Có lẽ tôi chỉ cần đặt 'NA' thành' FALSE'? 'ok <- a! = b; ok [! is.na (ok)] <- FALSE'? – Aaron

2

Vấn đề là bạn không chọn những hàng nào để DELETE bạn đang chọn những hàng nào để KEEP. Và như bạn đã phát hiện ra, bạn thường có thể trao đổi những khái niệm này, nhưng đôi khi, có những vấn đề.

Cụ thể, khi bạn sử dụng which, bạn đang hỏi R "yếu tố nào của vectơ này là đúng". Tuy nhiên, khi nó không tìm thấy, nó chỉ ra điều này bằng cách trả về integer(0).

Số nguyên (0) không phải là số thực, và do đó lấy số âm của số nguyên (0) vẫn cho số nguyên (0).

Tuy nhiên, không cần sử dụng, nếu bạn chỉ đơn giản sử dụng nó để lọc.

Thay vào đó, hãy lấy tuyên bố rằng bạn đang chuyển đến which và chuyển trực tiếp nó dưới dạng bộ lọc đến data[..]. Nhớ lại rằng bạn có thể sử dụng một vector hợp lý làm chỉ mục cũng như một vectơ số nguyên.

+0

Điều gì sẽ xảy ra khi có các giá trị thiếu trong vector hợp lý? Tôi đã sử dụng mà trong trường hợp đó để ngăn chặn odd behvaior. – Aaron

+0

@Aaron, rất hữu ích trong tình huống đó. Nhưng trong thực tế, bạn chỉ thay thế một hành vi "kỳ quặc" với hành vi khác. Nếu mục tiêu là để tránh hành vi bất ngờ, tôi khuyên bạn nên xử lý nó một cách rõ ràng hơn, chẳng hạn như 'x [is.na (x)] <- FALSE' –

+1

Đó là lời khuyên tốt, cảm ơn. – Aaron

3

Tại sao không sử dụng subset?

subset(data, ! rownames(data) %in% to_del) 

(Bạn đã được ngầm phù hợp để rownames trong data[-to_del, ] ví dụ, dù sao.) Tất nhiên một khi làm việc bạn có thể quay về sử dụng chỉ là "["

data[ ! rownames(data) %in% to_del , ] 
3

Tôi thích sử dụng data.table cho việc đặt trước, vì nó trực quan hơn, ngắn hơn và chạy nhanh hơn với các tập dữ liệu lớn.

library(data.table) 
data.dt<-as.data.table(data) 
setkey(data.dt, Treatment) 

data.dt[!"G1",] 
##  Treatment  Vals 
## 1:  G2 0.90264622 
## 2:  G2 1.47842130 
## 3:  G2 1.52494735 
## 4:  G2 1.46373958 
## 5:  G2 1.12850658 
## 6:  G2 1.46705561 
## 7:  G3 0.58451869 
## 8:  G3 -0.20231228 
## 9:  G3 0.52519475 
## 10:  G3 0.62956475 
## 11:  G3 -0.06655426 
## 12:  G3 0.56814703 

data.dt[!"G4",] 
## Treatment  Vals 
## 1   G1 0.93411692 
## 2   G1 0.60153972 
## 3   G1 0.28147464 
## 4   G1 0.97264924 
## 5   G1 0.50804831 
## 6   G1 0.48273876 
## 7   G2 0.90264622 
## 8   G2 1.47842130 
## 9   G2 1.52494735 
## 10  G2 1.46373958 
## 11  G2 1.12850658 
## 12  G2 1.46705561 
## 13  G3 0.58451869 
## 14  G3 -0.20231228 
## 15  G3 0.52519475 
## 16  G3 0.62956475 
## 17  G3 -0.06655426 
## 18  G3 0.56814703 

Lưu ý rằng nếu bạn tập hợp con trên một cột mà không được thiết lập như là chìa khóa, thì bạn cần phải sử dụng tên cột trong tập hợp con (ví dụ data.dt[Vals<0,])

Tôi nghĩ rằng những người tạo ra data.table thể đang làm việc trên một cách để xóa trực tiếp các hàng từ bảng gốc, thay vì phải sao chép tất cả các hàng không bị xóa sang một bảng mới và sau đó xóa bảng gốc. Đây sẽ là một trợ giúp tuyệt vời khi bạn chạy vào giới hạn bộ nhớ.

Các vấn đề liên quan