2011-11-21 64 views
48

Tôi đang cố gắng hiểu cách thay thế giá trị có điều kiện trong một khung dữ liệu mà không cần sử dụng vòng lặp. khung dữ liệu của tôi được cấu trúc như sau:Thay thế giá trị có điều kiện trong một data.frame

> df 
      a b est 
1 11.77000 2 0 
2 10.90000 3 0 
3 10.32000 2 0 
4 10.96000 0 0 
5 9.90600 0 0 
6 10.70000 0 0 
7 11.43000 1 0 
8 11.41000 2 0 
9 10.48512 4 0 
10 11.19000 0 0 

dput đầu ra là thế này:

structure(list(a = c(11.77, 10.9, 10.32, 10.96, 9.906, 10.7, 
11.43, 11.41, 10.48512, 11.19), b = c(2, 3, 2, 0, 0, 0, 1, 2, 
4, 0), est = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)), .Names = c("a", 
"b", "est"), row.names = c(NA, -10L), class = "data.frame") 

Những gì tôi muốn làm, là để kiểm tra giá trị của b. Nếu b là 0, tôi muốn đặt est thành giá trị từ a. Tôi hiểu rằng df$est[df$b == 0] <- 23 sẽ đặt tất cả các giá trị của est thành 23, khi b==0. Điều tôi không hiểu là cách đặt est thành giá trị a khi điều kiện đó là đúng. Ví dụ:

df$est[df$b == 0] <- (df$a - 5)/2.533 

đưa ra cảnh báo sau đây:

Warning message: 
In df$est[df$b == 0] <- (df$a - 5)/2.533 : 
    number of items to replace is not a multiple of replacement length 

Có cách nào mà tôi có thể vượt qua các tế bào có liên quan, chứ không phải là vector?

Trả lời

53

Vì bạn đang có điều kiện lập chỉ mục df$est, bạn cũng cần phải có điều kiện chỉ số vector thay thế df$a:

index <- df$b == 0 
df$est[index] <- (df$a[index] - 5)/2.533 

Tất nhiên, biến index chỉ là tạm thời, và tôi sử dụng nó để làm cho đoạn code một chút dễ đọc hơn. Bạn có thể viết nó trong một bước:

df$est[df$b == 0] <- (df$a[df$b == 0] - 5)/2.533 

Đối readibility thậm chí tốt hơn, bạn có thể sử dụng within:

df <- within(df, est[b==0] <- (a[b==0]-5)/2.533) 

Kết quả, bất kể bạn chọn phương pháp:

df 
      a b  est 
1 11.77000 2 0.000000 
2 10.90000 3 0.000000 
3 10.32000 2 0.000000 
4 10.96000 0 2.352941 
5 9.90600 0 1.936834 
6 10.70000 0 2.250296 
7 11.43000 1 0.000000 
8 11.41000 2 0.000000 
9 10.48512 4 0.000000 
10 11.19000 0 2.443743 

Như những người khác đã chỉ ra, một giải pháp thay thế trong ví dụ của bạn là sử dụng ifelse .

11

Đây là một cách tiếp cận. ifelse được vector hóa và nó kiểm tra tất cả các hàng có giá trị bằng không là b và thay thế est bằng (a - 5)/2.53 nếu đúng như vậy.

df <- transform(df, est = ifelse(b == 0, (a - 5)/2.53, est)) 
5

R-inferno hoặc tài liệu R cơ bản sẽ giải thích lý do tại sao sử dụng df $ * không phải là cách tiếp cận tốt nhất tại đây. Từ trang trợ giúp cho "[":

"Lập chỉ mục theo [tương tự như vectơ nguyên tử và chọn danh sách (các) thành phần được chỉ định. Cả [[và $ chọn một phần tử duy nhất trong danh sách. sự khác biệt là $ không cho phép các chỉ mục được tính toán, trong khi [[does. x $ name là tương đương với x [["name", exact = FALSE]]. . "

Tôi khuyên bạn nên sử dụng ký hiệu [row,col] để thay thế.Ví dụ:

Rgames: foo 
     x y z 
    [1,] 1e+00 1 0 
    [2,] 2e+00 2 0 
    [3,] 3e+00 1 0 
    [4,] 4e+00 2 0 
    [5,] 5e+00 1 0 
    [6,] 6e+00 2 0 
    [7,] 7e+00 1 0 
    [8,] 8e+00 2 0 
    [9,] 9e+00 1 0 
    [10,] 1e+01 2 0 
Rgames: foo<-as.data.frame(foo) 

Rgames: foo[foo$y==2,3]<-foo[foo$y==2,1] 
Rgames: foo 
     x y  z 
1 1e+00 1 0e+00 
2 2e+00 2 2e+00 
3 3e+00 1 0e+00 
4 4e+00 2 4e+00 
5 5e+00 1 0e+00 
6 6e+00 2 6e+00 
7 7e+00 1 0e+00 
8 8e+00 2 8e+00 
9 9e+00 1 0e+00 
10 1e+01 2 1e+01 
+0

này xứng đáng một upvote nếu bạn lần đầu tiên thêm hoặc là một liên kết đến R-Inferno trang hoặc tóm tắt các vấn đề với '$' (hoặc lý tưởng là cả hai). – Andrie

+0

+1 Mặc dù tôi nghĩ toán tử '$' hoàn toàn ổn trong trường hợp này. (Ngoài ra, tôi lưu ý rằng mặc dù cảnh báo bạn sử dụng '$' chính mình ...) – Andrie

+0

@Andrie: vâng, tôi đã sử dụng nó ở nơi nó hoạt động (không phải đó là rất nhiều trợ giúp :-)). OP đã cố gắng sử dụng nó để xác định những yếu tố nào đang được thực hiện, đó là nơi mà sự cố đã bắt đầu. Tôi chỉ sử dụng nó để xác định một điều kiện đã chọn các phần tử dataframe. Nhưng bạn biết rằng :-) –

24

Hãy thử data.table 's := điều hành:

DT = as.data.table(df) 
DT[b==0, est := (a-5)/2.533] 

Đó là nhanh chóng và ngắn. Xem những câu hỏi liên quan để biết thêm thông tin về :=:

Why has data.table defined :=

When should I use the := operator in data.table

How do you remove columns from a data.frame

R self reference

+0

Đẹp, Cảm ơn bạn đã tham khảo +1 cho mọi thứ. – PKumar

+0

Phản hồi rất hữu ích. Nếu bạn sử dụng điều này, hãy đảm bảo rằng DT không phải là một hàm trong gói data.table, mà là một tham chiếu cho đối tượng bảng dữ liệu. –

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