ฉันจะลบทั้งหมดยกเว้นหนึ่งระเบียนที่ซ้ำกันเฉพาะในกรอบข้อมูล R ได้อย่างไร [ปิด]


16

ฉันมีกรอบข้อมูลที่มีรหัสที่ซ้ำกันบางส่วน ฉันต้องการลบระเบียนที่มีรหัสที่ซ้ำกันเก็บเฉพาะแถวที่มีค่าสูงสุด

ดังนั้นสำหรับโครงสร้างเช่นนี้ (ตัวแปรอื่น ๆ ไม่ได้แสดง):

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

ฉันต้องการสร้างสิ่งนี้:

id var_1
1 4
2 3
3 5
4 2

ฉันรู้เกี่ยวกับที่ไม่ซ้ำกัน () และทำซ้ำ () แต่ฉันไม่สามารถหาวิธีรวมกฎการเพิ่มประสิทธิภาพสูงสุด ...


จริง ๆ แล้วมันควรจะอยู่ใน stackoverflow เนื่องจากเป็นงานที่เกี่ยวข้องกับการเขียนโปรแกรมล้วนๆและมีส่วนเกี่ยวข้องกับสถิติน้อยมาก
ผู้ที่กระตือรือร้น

คำตอบ:


24

วิธีหนึ่งคือการเรียงลำดับข้อมูลย้อนกลับและใช้duplicatedเพื่อวางรายการที่ซ้ำทั้งหมด สำหรับฉันวิธีนี้ง่ายกว่าที่คิดใช้ ฉันคิดว่ามันควรจะเร็วมากเช่นกัน

# 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

แก้ไข: ฉันเพิ่งรู้ว่าการเรียงลำดับย้อนกลับข้างต้นไม่จำเป็นต้องเรียงลำดับidเลย คุณสามารถใช้z[order(z$var, decreasing=TRUE),]แทนและมันก็ใช้ได้เช่นกัน

คิดอีกอย่างหนึ่ง ... หากvarคอลัมน์เป็นตัวเลขแสดงว่ามีวิธีการเรียงลำดับแบบง่าย ๆ เพื่อให้เรียงidจากน้อยไปมาก แต่varกำลังจากมากไปน้อย สิ่งนี้ช่วยลดความจำเป็นในการเรียงลำดับที่ส่วนท้าย (สมมติว่าคุณต้องการเรียงลำดับ)

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
วิธีนี้เร็วกว่า "split-compute-rbind" อย่างมีนัยสำคัญ นอกจากนี้ยังช่วยให้การจัดกลุ่มมากกว่าหนึ่งปัจจัย สำหรับค. 650,000 แถว (8, แคบ, คอลัมน์) วิธีการ "สั่งทำซ้ำ" ใช้เวลา 55 วินาที, การแบ่งคำนวณ -bind ... 1 ชั่วโมง 15 นาที แน่นอนว่าเมื่อการคำนวณแบบรวมนั้นไม่ใช่การเลือกหรือการกรองรายการที่ซ้ำกันนั้นจำเป็นต้องใช้วิธีการหลังหรือวิธีการแบบใช้ plyr ที่คล้ายกัน
mjv

7

คุณต้องการเลือกองค์ประกอบสูงสุดจากองค์ประกอบที่มีรหัสเดียวกัน เพื่อที่คุณสามารถใช้ddplyจากแพคเกจ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

uniqueและduplicatedสำหรับการลบระเบียนที่ซ้ำกันในกรณีของคุณคุณมีรหัสที่ซ้ำกันไม่ใช่บันทึก

ปรับปรุง:นี่คือรหัสเมื่อมีตัวแปรเพิ่มเติม:

> 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),])

เกิดอะไรขึ้นถ้ามีตัวแปรอื่น ๆ : คุณจะนำมันไปได้อย่างไร?
Aniko

เราไม่ย้ายคำถามเหล่านี้ - เร่งรีบมากเกินไปเพื่อให้ได้กำไรน้อยเกินไป

6

โซลูชัน base-R จะเกี่ยวพันsplitดังนี้:

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),]))

splitแยก data data ออกเป็นรายการของ chunks ที่เราทำการตัดไปยังแถวเดียวด้วยค่าสูงสุดจากนั้นdo.call(rbind,...)ลดรายการของแถวเดี่ยวลงใน data frame อีกครั้ง


1
และตามปกตินี่จะเร็วกว่า 2x2 เท่าของ plyr

1
@mbq, ใช่, เป็นธรรมชาติ, แต่ถ้าคุณรวมค่าใช้จ่ายในการดีบั๊ก, สำหรับชุดข้อมูลปกติ, ความเร็วที่ได้จะเหมือนกัน :) plyrไม่ได้ถูกออกแบบมาเฉพาะสำหรับความเร็ว, แต่เพื่อความชัดเจนและความสะดวกสบาย
mpiktas

และการใช้ ave นั้นเร็วเป็นสองเท่าเลยล่ะ :)
Eduardo Leoni

2
@Eduardo aveเป็น wrapper ของlapply+ splitตรวจสอบรหัส (-;

1
@Eduardo ใช่ แต่มันทั้งหมดจะทำงานเฉพาะเนื่องจากมีความเป็นไปได้ที่เล่นโวหารของการเรียงลำดับ vectorized ภายในปัจจัยการใช้order; สำหรับปัญหาทั่วไปที่splitหลีกเลี่ยงไม่ได้

5

ฉันชอบที่จะใช้ 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 ไม่ทราบเกี่ยวกับ ave มันปรากฏใน R เมื่อใด
mpiktas

1

อีกวิธีในการทำเช่นนี้กับฐาน:

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

ฉันชอบโซลูชัน plyr ของ mpiktas


1

ถ้าตามตัวอย่าง var คอลัมน์นั้นมีลำดับขึ้นมาแล้วเราไม่จำเป็นต้องเรียงลำดับ data frame เราแค่ใช้ฟังก์ชั่นที่duplicatedผ่านการโต้แย้งfromLast = TRUEดังนั้นการทำซ้ำจะถูกพิจารณาจากด้านหลังโดยเก็บรักษาองค์ประกอบสุดท้าย:

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

มิฉะนั้นเราจะเรียงลำดับข้อมูลจากน้อยไปมาก

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

ใช้dplyrแพคเกจ:

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.