2013-08-14 19 views
62

Tôi muốn đặt một khung dữ liệu dựa trên các cột khác nhau, một lần lượt. Tôi có một vector nhân vật với các tên cột liên quan theo đó order cần căn cứ:

parameter <- c("market_value_LOCAL", "ep", "book_price", "sales_price", "dividend_yield", 
       "beta", "TOTAL_RATING_SCORE", "ENVIRONMENT", "SOCIAL", "GOVERNANCE") 

Tôi muốn để lặp qua các tên trong parameter và tự động chọn cột được sử dụng để order dữ liệu của tôi:

Q1_R1000_parameter <- Q1_R1000[order(Q1_R1000$parameter[X]), ] 

trong đó X1:10 (vì tôi có 10 mục trong parameter).


Để làm ví dụ của tôi tái sản xuất, xem xét các dữ liệu thiết mtcars và một số tên biến được lưu trữ trong một vector nhân vật cols. Khi tôi cố gắng chọn một biến từ mtcars sử dụng một tập hợp con năng động của cols, theo một cách tương tự như trên (Q1_R1000$parameter[X]), cột không được chọn:

cols <- c("cyl", "am") 
mtcars$cols[1] 
# NULL 

Trả lời

102

bạn không thể làm điều đó loại Subsetting với $ trong mã nguồn (R/src/main/subset.c) nó nói:

/* Toán tử tập hợp con $.
Chúng ta cần phải chắc chắn chỉ đánh giá đối số đầu tiên.
Biểu tượng thứ hai sẽ là biểu tượng cần được đối sánh, không được đánh giá.
*/

Đối số thứ hai? Gì?! Bạn phải nhận ra rằng $, giống như mọi thứ khác trong R, (bao gồm ví dụ (, +, ^ v.v.) là một hàm, lấy đối số và được đánh giá. df$V1 có thể được viết lại như

`$`(df , V1) 

hoặc thực sự

`$`(df , "V1") 

Nhưng ...

`$`(df , paste0("V1")) 

... ví dụ như sẽ không bao giờ làm việc, cũng không sẽ bất cứ điều gì khác mà trước tiên phải được đánh giá trong đối số thứ hai. Bạn chỉ có thể vượt qua một chuỗi là không bao giờ được đánh giá.

Thay vào đó hãy sử dụng [ (hoặc [[ nếu bạn chỉ muốn trích xuất một cột đơn lẻ dưới dạng vectơ).

Ví dụ,

var <- "mpg" 
#Doesn't work 
mtcars$var 
#These both work, but note that what they return is different 
# the first is a vector, the second is a data.frame 
mtcars[[var]] 
mtcars[var] 

Bạn có thể thực hiện việc đặt hàng mà không có vòng, sử dụng do.call để xây dựng các cuộc gọi đến order. Dưới đây là một ví dụ tái sản xuất dưới đây:

# set seed for reproducibility 
set.seed(123) 
df <- data.frame(col1 = sample(5,10,repl=T) , col2 = sample(5,10,repl=T) , col3 = sample(5,10,repl=T)) 

# We want to sort by 'col3' then by 'col1' 
sort_list <- c("col3","col1") 

# Use 'do.call' to call order. Seccond argument in do.call is a list of arguments 
# to pass to the first argument, in this case 'order'. 
# Since a data.frame is really a list, we just subset the data.frame 
# according to the columns we want to sort in, in that order 
df[ do.call(order , df[ , match(sort_list , names(df)) ] ) , ] 

    col1 col2 col3 
10 3 5 1 
9  3 2 2 
7  3 2 3 
8  5 1 3 
6  1 5 4 
3  3 4 4 
2  4 3 4 
5  5 1 4 
1  2 5 5 
4  5 3 5 
1

Nếu tôi hiểu đúng, bạn có một vector chứa biến tên và muốn lặp qua từng tên và sắp xếp khung dữ liệu của bạn theo tên. Nếu vậy, ví dụ này sẽ minh họa một giải pháp cho bạn. Vấn đề chính trong của bạn (ví dụ đầy đủ không hoàn thành vì vậy tôi "không chắc chắn những gì khác bạn có thể bị thiếu) là nó phải là order(Q1_R1000[,parameter[X]]) thay vì order(Q1_R1000$parameter[X]), vì tham số là một đối tượng bên ngoài có chứa tên biến trái ngược với .. cột trực tiếp của khung dữ liệu của bạn (mà khi $ sẽ là thích hợp)

set.seed(1) 
dat <- data.frame(var1=round(rnorm(10)), 
        var2=round(rnorm(10)), 
        var3=round(rnorm(10))) 
param <- paste0("var",1:3) 
dat 
# var1 var2 var3 
#1 -1 2 1 
#2  0 0 1 
#3 -1 -1 0 
#4  2 -2 -2 
#5  0 1 1 
#6 -1 0 0 
#7  0 0 0 
#8  1 1 -1 
#9  1 1 0 
#10 0 1 0 

for(p in rev(param)){ 
    dat <- dat[order(dat[,p]),] 
} 
dat 
# var1 var2 var3 
#3 -1 -1 0 
#6 -1 0 0 
#1 -1 2 1 
#7  0 0 0 
#2  0 0 1 
#10 0 1 0 
#5  0 1 1 
#8  1 1 -1 
#9  1 1 0 
#4  2 -2 -2 
0
Q1_R1000[do.call(order, Q1_R1000[parameter]), ] 
1

Sử dụng dplyr cung cấp một cú pháp đơn giản để phân loại dữ liệu khung

library(dplyr) 
mtcars %>% arrange(gear, desc(mpg)) 

Nó có thể là hữu ích để sử dụng phiên bản NSE để cho phép tự động xây dựng các loại danh sách

sort_list <- c("gear", "desc(mpg)") 
mtcars %>% arrange_(.dots = sort_list) 
+0

không NSE có ý nghĩa gì ở đây? – discipulus

+1

@discipulus phi tiêu chuẩn đánh giá; đó là để làm việc với các biểu thức bị trì hoãn để tự động tạo mã bằng các chuỗi thay vì mã hóa cứng. Xem tại đây để biết thêm thông tin: https://cran.r-project.org/web/packages/lazyeval/vignettes/lazyeval.html – manotheshark

-1

Có vấn đề tương tự do một số tệp CSV có tên khác nhau cho mẫu e cột.
Đây là giải pháp:

Tôi đã viết một chức năng để trả lại tên cột hợp lệ đầu tiên trong danh sách, sau đó sử dụng mà ...

# Return the string name of the first name in names that is a column name in tbl 
# else null 
ChooseCorrectColumnName <- function(tbl, names) { 
for(n in names) { 
    if (n %in% colnames(tbl)) { 
     return(n) 
    } 
} 
return(null) 
} 

then... 

cptcodefieldname = ChooseCorrectColumnName(file, c("CPT", "CPT.Code")) 
icdcodefieldname = ChooseCorrectColumnName(file, c("ICD.10.CM.Code", "ICD10.Code")) 

if (is.null(cptcodefieldname) || is.null(icdcodefieldname)) { 
     print("Bad file column name") 
} 

# Here we use the hash table implementation where 
# we have a string key and list value so we need actual strings, 
# not Factors 
file[cptcodefieldname] = as.character(file[cptcodefieldname]) 
file[icdcodefieldname] = as.character(file[icdcodefieldname]) 
for (i in 1:length(file[cptcodefieldname])) { 
    cpt_valid_icds[file[cptcodefieldname][i]] <<- unique(c(cpt_valid_icds[[file[cptcodefieldname][i]]], file[icdcodefieldname][i])) 
}