2011-09-25 36 views
17

Tôi có một data.frame lớn dữ liệu ký tự mà tôi muốn chuyển đổi dựa trên những gì thường được gọi là từ điển bằng các ngôn ngữ khác.Kiểu từ điển thay thế nhiều mục

Hiện nay tôi đang đi về nó như vậy:

foo <- data.frame(snp1 = c("AA", "AG", "AA", "AA"), snp2 = c("AA", "AT", "AG", "AA"), snp3 = c(NA, "GG", "GG", "GC"), stringsAsFactors=FALSE) 
foo <- replace(foo, foo == "AA", "0101") 
foo <- replace(foo, foo == "AC", "0102") 
foo <- replace(foo, foo == "AG", "0103") 

này hoạt động tốt, nhưng nó rõ ràng là không đẹp và có vẻ ngớ ngẩn để lặp lại các tuyên bố replace mỗi khi tôi muốn thay thế một mục trong dữ liệu. khung.

Có cách nào tốt hơn để làm điều này vì tôi có từ điển khoảng 25 cặp khóa/giá trị không?

+1

Từ điển của bạn có phải là danh sách R không? – Mark

+0

Hiện tại, nhưng sẽ dễ dàng biến nó thành một. – Stedy

+0

Có lẽ câu hỏi này có thể hữu ích: [Case Statement Equivalent] (http://stackoverflow.com/q/4622060/168747), [Cách thêm một cột vào một 'data.frame'] (http: // stackoverflow. com/q/4562547/168747), [Làm sạch dữ liệu trong trang tính Excel] (http://stackoverflow.com/q/7374314/168747). – Marek

Trả lời

18
map = setNames(c("0101", "0102", "0103"), c("AA", "AC", "AG")) 
foo[] <- map[unlist(foo)] 

giả định rằng map bao gồm tất cả các trường hợp trong foo. Điều này sẽ cảm thấy ít giống như một 'hack' và có hiệu quả hơn trong cả không gian và thời gian nếu foo là một ma trận (của nhân vật()), sau đó

matrix(map[foo], nrow=nrow(foo), dimnames=dimnames(foo)) 

Cả hai ma trận và dữ liệu khung biến thể đụng chạm tới R của 2^Giới hạn 31-1 đối với kích thước vectơ khi có hàng triệu SNP và hàng nghìn mẫu.

3

Dưới đây là một cái gì đó đơn giản mà sẽ thực hiện công việc:

key <- c('AA','AC','AG') 
val <- c('0101','0102','0103') 

lapply(1:3,FUN = function(i){foo[foo == key[i]] <<- val[i]}) 
foo 

snp1 snp2 snp3 
1 0101 0101 <NA> 
2 0103 AT GG 
3 0101 0103 GG 
4 0101 0101 GC 

lapply sẽ ra một danh sách trong trường hợp này mà chúng ta không thực sự quan tâm. Bạn có thể gán kết quả cho một cái gì đó nếu bạn thích và sau đó chỉ cần loại bỏ nó. Tôi đang lặp qua các chỉ mục ở đây, nhưng bạn có thể dễ dàng đặt khóa/vals trong danh sách và lặp lại chúng trực tiếp. Lưu ý việc sử dụng nhiệm vụ toàn cầu với <<-.

Tôi đã tìm cách thực hiện việc này với mapply nhưng nỗ lực đầu tiên của tôi không hiệu quả, vì vậy tôi đã chuyển sang. Tôi nghi ngờ một giải pháp với mapply là có thể, mặc dù.

+0

tôi sẽ không tư vấn cho việc sử dụng toán tử gán toàn cục '<< -'. – Ramnath

+1

@Ramnath Đồng ý, '<< -' có thể rủi ro, nhưng nó không phải là xấu. – joran

11

Dưới đây là một giải pháp nhanh chóng

dict = list(AA = '0101', AC = '0102', AG = '0103') 
foo2 = foo 
for (i in 1:3){foo2 <- replace(foo2, foo2 == names(dict[i]), dict[i])} 
+1

bất cứ ai có thể giải thích downvote im lặng? – Ramnath

+3

Tôi thích câu trả lời này vì nó giữ các khóa và giá trị với nhau. Có các khóa và giá trị trong các vectơ ký tự riêng biệt có nghĩa là nếu bạn nhận được thứ tự của một trong các vectơ sai, từ điển của bạn sẽ âm thầm đánh sai tất cả các mục được sắp xếp không chính xác. – mgriebe

+1

Chỉ có sự khác biệt tôi đề nghị là sử dụng ký hiệu vectơ của R trên dòng thứ 3, ví dụ: sapply (1: 3, hàm (i) thay thế (foo2, foo2 == tên (dict [i]), dict [i])) –

17

Nếu bạn đang mở để sử dụng gói, plyr là một trong những rất phổ biến và có ích mapvalues() chức năng này sẽ làm chỉ là những gì bạn đang tìm kiếm:

foo <- mapvalues(foo, from=c("AA", "AC", "AG"), to=c("0101", "0102", "0103")) 

Lưu ý rằng nó hoạt động với nhiều loại dữ liệu của tất cả các loại, không chỉ là dây.

+1

Thật không may, điều này ném một _Error trong plyr :: mapvalues ​​(foo, từ = c ("AA", "AC", "AG"), đến = c ("0101",: 'x' phải là một vector nguyên tử. _ Điều này cũng được ghi lại trong '? Mapvalues'. – Uwe

1

Đã sử dụng câu trả lời của @ Ramnath ở trên, nhưng đã đọc nó (những gì cần thay thế và những gì cần thay thế bằng) từ tệp và sử dụng gsub thay vì thay thế.

hrw <- read.csv("hgWords.txt", header=T, stringsAsFactor=FALSE, encoding="UTF-8", sep="\t") 

for (i in nrow(hrw)) 
{ 
document <- gsub(hrw$from[i], hrw$to[i], document, ignore.case=TRUE) 
} 

hgword.txt chứa các tab sau tách

"from" "to" 
"AA" "0101" 
"AC" "0102" 
"AG" "0103" 
4

Note câu trả lời này bắt đầu như là một nỗ lực để giải quyết vấn đề đơn giản hơn nhiều posted in How to replace all values in data frame with a vector of values?. Rất tiếc, câu hỏi này đã bị đóng là trùng lặp với câu hỏi thực tế. Vì vậy, tôi sẽ cố gắng đề xuất một giải pháp dựa trên các yếu tố thay thế cho cả hai trường hợp, tại đây.


Trong trường hợp chỉ có một vector (hoặc một dữ liệu khung cột) có giá trị cần phải được thay thế không có sự phản đối sử dụng yếu tố chúng ta có thể ép buộc các vector đến yếu tố và thay đổi cấp độ yếu tố theo yêu cầu:

x <- c(1, 1, 4, 4, 5, 5, 1, 1, 2) 
x <- factor(x) 
x 
#[1] 1 1 4 4 5 5 1 1 2 
#Levels: 1 2 4 5 
replacement_vec <- c("A", "T", "C", "G") 
levels(x) <- replacement_vec 
x 
#[1] A A C C G G A A T 
#Levels: A T C G 

Sử dụng forcats gói này có thể được thực hiện trong một lớp lót:

x <- c(1, 1, 4, 4, 5, 5, 1, 1, 2) 
forcats::lvls_revalue(factor(x), replacement_vec) 
#[1] A A C C G G A A T 
#Levels: A T C G 

Trong trường hợp tất cả giá trị của nhiều cột của một khung dữ liệu cần phải được thay thế, cách tiếp cận có thể được mở rộng.

foo <- data.frame(snp1 = c("AA", "AG", "AA", "AA"), 
        snp2 = c("AA", "AT", "AG", "AA"), 
        snp3 = c(NA, "GG", "GG", "GC"), 
        stringsAsFactors=FALSE) 

level_vec <- c("AA", "AC", "AG", "AT", "GC", "GG") 
replacement_vec <- c("0101", "0102", "0103", "0104", "0302", "0303") 
foo[] <- lapply(foo, function(x) forcats::lvls_revalue(factor(x, levels = level_vec), 
                 replacement_vec)) 
foo 
# snp1 snp2 snp3 
#1 0101 0101 <NA> 
#2 0103 0104 0303 
#3 0101 0103 0303 
#4 0101 0101 0302 

Lưu ý rằng level_vecreplacement_vec phải có độ dài bằng nhau.

Quan trọng hơn, level_vec phải là hoàn thành, tức là bao gồm tất cả giá trị có thể có trong các cột bị ảnh hưởng của khung dữ liệu gốc. (Sử dụng unique(sort(unlist(foo))) để xác minh). Nếu không, bất kỳ giá trị bị thiếu nào sẽ bị ép buộc là <NA>. Lưu ý rằng đây cũng là yêu cầu cho Martin Morgans's answer.

Vì vậy, nếu chỉ có một vài giá trị khác nhau được thay thế, bạn có lẽ sẽ tốt hơn với một trong các câu trả lời khác, ví dụ: Ramnath's.

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