2015-04-07 22 views
8

Tôi có một câu hỏi đơn giản về tập hợp các giá trị trong R.kết hợp các giá trị trong hàng dựa trên các điều kiện phù hợp trong R

Giả sử tôi có một dataframe:

DF <- data.frame(col1=c("Type 1", "Type 1B", "Type 2"), col2=c(1, 2, 3)) 

mà trông như thế này:

 col1 col2 
1 Type 1 1 
2 Type 1B 2 
3 Type 2 3 

Tôi nhận thấy rằng tôi có Type 1Type 1B trong dữ liệu, vì vậy tôi muốn kết hợp Type 1B vào Type 1.

Vì vậy, tôi quyết định sử dụng dplyr:

filter(DF, col1=='Type 1' | col1=='Type 1B') %>% 
    summarise(n = sum(col2)) 

Nhưng bây giờ tôi cần phải tiếp tục đi với nó:

DF2 <- data.frame('Type 1', filter(DF, col1=='Type 1' | col1=='Type 1B') %>% 
    summarise(n = sum(col2))) 

Tôi đoán tôi muốn cbind này DF2 mới trở lại DF gốc, nhưng điều đó có nghĩa là tôi phải đặt tên cột để nhất quán:

names(DF2) <- c('col1', 'col2') 

OK , Bây giờ tôi có thể rbind:

rbind(DF2, DF[3,]) 

Kết quả? Nó hoạt động ....

col1 col2 
1 Type 1 3 
3 Type 2 3 

... nhưng ugh! Thật kinh khủng! Phải có cách tốt hơn để kết hợp các giá trị đơn giản.

Trả lời

2

Bạn có thể thử:

library(data.table) 

setDT(transform(DF, col1=gsub("(.*)[A-Z]+$","\\1",DF$col1)))[,list(col2=sum(col2)),col1] 

#  col1 col2 
# 1: Type 1 3 
# 2: Type 2 3 

Hoặc thậm chí trực tiếp hơn:

setDT(DF)[, .(col2 = sum(col2)), by = .(col1 = sub("[[:alpha:]]+$", "", col1))] 
+0

Hiện đã nhận được một cách khái quát hơn để làm một cái gì đó đơn giản như vậy, không có? Chắc chắn một hoạt động đơn giản như vậy không cần phải bao gồm sự phù hợp với loại regex !! –

+0

Trong một dòng ngay bây giờ. Nhưng bạn sẽ cần 'gsub' hoặc tìm một mẫu khác để nhận ra rằng' type 1' và 'type1B' là tương tự nhau. Việc tổng hợp có thể được thực hiện với 'aggregate',' dplyr', 'data.table', v.v. –

4

Dưới đây là một cách tiếp cận dplyr thể:

library(dplyr) 
DF %>% 
    group_by(col1 = sub("(.*\\d+).*$", "\\1", col1)) %>% 
    summarise(col2 = sum(col2)) 
#Source: local data frame [2 x 2] 
# 
# col1 col2 
#1 Type 1 3 
#2 Type 2 3 
4

Sử dụng sub() với aggregate(), removin g bất cứ điều gì khác hơn là một chữ số từ ngày kết thúc col1,

do.call("data.frame", 
    aggregate(col2 ~ cbind(col1 = sub("\\D+$", "", col1)), DF, sum) 
) 
#  col1 col2 
# 1 Type 1 3 
# 2 Type 2 3 

Các wrapper do.call() là có để cột đầu tiên sau khi aggregate() được thay đổi hoàn toàn khỏi một ma trận với một vector. Bằng cách này, không có bất kỳ điều ngạc nhiên nào sau đó trên con đường.

1

Theo ý kiến ​​của tôi, aggregate() là chức năng hoàn hảo cho mục đích này, nhưng bạn không cần phải thực hiện bất kỳ xử lý văn bản nào (ví dụ: gsub()). Tôi sẽ thực hiện việc này trong quy trình gồm hai bước:

  1. Ghi đè col1 với nhóm mới mong muốn.
  2. Tính toán tập hợp bằng cách sử dụng col1 mới để chỉ định nhóm.

DF$col1 <- ifelse(DF$col1 %in% c('Type 1','Type 1B'),'Type 1',levels(DF$col1)); 
DF; 
##  col1 col2 
## 1 Type 1 1 
## 2 Type 1 2 
## 3 Type 2 3 
DF <- aggregate(col2~col1, DF, FUN=sum); 
DF; 
##  col1 col2 
## 1 Type 1 3 
## 2 Type 2 3 
+0

Tôi nghĩ rằng đây là câu trả lời hay nhất vì nó tránh xung đột với văn bản. Nó giữ mức độ phức tạp thấp. –

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