Làm cách nào để xóa tất cả trừ một bản ghi trùng lặp cụ thể trong khung dữ liệu R? [đóng cửa]


16

Tôi có một khung dữ liệu có chứa một số id trùng lặp. Tôi muốn xóa các bản ghi với id trùng lặp, chỉ giữ lại hàng với giá trị tối đa.

Vì vậy, đối với cấu trúc như thế này (các biến khác không được hiển thị):

id var_1
1 2
1 4
2 1
2 3
3 5
4 2

Tôi muốn tạo cái này:

id var_1
1 4
2 3
3 5
4 2

Tôi biết về duy nhất () và trùng lặp (), nhưng tôi không thể tìm ra cách kết hợp quy tắc tối đa hóa ...


Nó thực sự nên nằm trong stackoverflow vì đây là một nhiệm vụ hoàn toàn liên quan đến lập trình và ít liên quan đến thống kê
Nhiệt tình

Câu trả lời:


24

Một cách là sắp xếp ngược dữ liệu và sử dụng duplicatedđể loại bỏ tất cả các bản sao. Đối với tôi, phương pháp này đơn giản hơn về mặt khái niệm so với phương pháp sử dụng. Tôi nghĩ rằng nó cũng sẽ rất nhanh.

# Some data to start with:
z <- data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,5,2))
# id var
#  1   2
#  1   4
#  2   1
#  2   3
#  3   5
#  4   2

# Reverse sort
z <- z[order(z$id, z$var, decreasing=TRUE),]
# id var
#  4   2
#  3   5
#  2   3
#  2   1
#  1   4
#  1   2

# Keep only the first row for each duplicate of z$id; this row will have the
# largest value for z$var
z <- z[!duplicated(z$id),]

# Sort so it looks nice
z <- z[order(z$id, z$var),]
# id var
#  1   4
#  2   3
#  3   5
#  4   2

Chỉnh sửa: Tôi chỉ nhận ra rằng sắp xếp ngược lại ở trên thậm chí không cần phải sắp xếp lại id. Bạn chỉ có thể sử dụng z[order(z$var, decreasing=TRUE),]thay thế và nó sẽ hoạt động tốt.

Thêm một suy nghĩ nữa ... Nếu varcột là số, thì có một cách đơn giản để sắp xếp sao cho idtăng dần, nhưng vargiảm dần. Điều này giúp loại bỏ sự cần thiết của sắp xếp ở cuối (giả sử bạn thậm chí muốn nó được sắp xếp).

z <- data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,5,2))

# Sort: id ascending, var descending
z <- z[order(z$id, -z$var),]

# Remove duplicates
z <- z[!duplicated(z$id),]
# id var
#  1   4
#  2   3
#  3   5
#  4   2

1
Cách tiếp cận này nhanh hơn đáng kể so với "split-compute-rbind". Hơn nữa, nó cho phép nhóm vào nhiều hơn một yếu tố. Đối với một c. 650.000 hàng (8, hẹp, các cột) phương pháp "nhân đôi thứ tự" mất 55 giây, phương pháp tính toán tách rời ... 1 giờ 15 phút. Tất nhiên khi tính toán tổng hợp khác với việc chọn hoặc lọc trùng lặp, cách tiếp cận sau hoặc các cách tiếp cận dựa trên plyr tương tự là cần thiết.
mjv

7

Bạn thực tế muốn chọn phần tử tối đa từ các phần tử có cùng id. Cho rằng bạn có thể sử dụng ddplytừ gói plyr :

> dt<-data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,4,2))
> ddply(dt,.(id),summarise,var_1=max(var))
   id var_1
1  1   4
2  2   3
3  3   4
4  4   2

uniqueduplicatedlà để xóa các bản ghi trùng lặp, trong trường hợp của bạn, bạn chỉ có id trùng lặp, không có bản ghi.

Cập nhật: Đây là mã khi có thêm các biến:

> dt<-data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,4,2),bu=rnorm(6))
> ddply(dt,~id,function(d)d[which.max(d$var),])

Điều gì xảy ra nếu có các biến khác: làm thế nào để bạn mang chúng theo?
Aniko

Chúng tôi không di chuyển những câu hỏi như vậy - quá nhiều vội vàng cho quá ít lợi ích.

6

Giải pháp cơ sở R sẽ liên quan split, như thế này:

z<-data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,4,2))
do.call(rbind,lapply(split(z,z$id),function(chunk) chunk[which.max(chunk$var),]))

splitchia khung dữ liệu thành một danh sách các khối, trên đó chúng tôi thực hiện cắt thành một hàng với giá trị tối đa và sau đó do.call(rbind,...)giảm danh sách các hàng đơn thành khung dữ liệu một lần nữa.


1
Và như thường lệ, nó nhanh hơn khoảng 2 lần so với phiên bản plyr.

1
@mbq, vâng, tự nhiên, nhưng nếu bạn bao gồm chi phí gỡ lỗi, đối với các tập dữ liệu thông thường, tốc độ kết quả là như nhau :) plyr được dành riêng không phải vì tốc độ, mà vì sự rõ ràng và thuận tiện.
mpiktas

và sử dụng ave dù sao cũng nhanh gấp đôi :)
Eduardo Leoni

2
@Eduardo avelà trình bao bọc của lapply+ split, kiểm tra mã (-;

1
@Eduardo Vâng, nhưng tất cả chỉ hoạt động do khả năng sắp xếp véc tơ trong các yếu tố sử dụng order; cho các vấn đề chung chung hơn splitlà không thể tránh khỏi.

5

Tôi thích sử dụng ave

dt<-data.frame(id=c(1,1,2,2,3,4),var=c(2,4,3,3,4,2))
## use unique if you want to exclude duplicate maxima
unique(subset(dt, var==ave(var, id, FUN=max)))

+1, không biết về ave. Khi nào nó xuất hiện trong R?
mpiktas

1

Một cách khác để làm điều này với cơ sở:

dt<-data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,4,2))

data.frame(id=sort(unique(dt$var)),max=tapply(dt$var,dt$id,max))
  id max
1  1   4
2  2   3
3  3   4
4  4   2

Tôi thích giải pháp plyr của mpiktas mặc dù.


1

Nếu, như trong ví dụ, cột var đã theo thứ tự tăng dần, chúng ta không cần phải sắp xếp khung dữ liệu. Chúng ta chỉ sử dụng hàm duplicatedtruyền đối số fromLast = TRUE, vì vậy sao chép được xem xét từ phía ngược lại, giữ các phần tử cuối cùng:

z <- data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,5,2))
z[!duplicated(z$id, fromLast = TRUE), ]

  id var
2  1   4
4  2   3
5  3   5
6  4   2

Mặt khác, chúng tôi sắp xếp khung dữ liệu theo thứ tự tăng dần trước:

z <- z[order(z$id, z$var), ]
z[!duplicated(z$id, fromLast = TRUE), ]

Sử dụng dplyrgói:

library(dplyr)
z %>%
  group_by(id) %>%
  summarise(var = max(var))

Source: local data frame [4 x 2]    
  id var
1  1   4
2  2   3
3  3   5
4  4   2
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.