Tự động chọn cột khung dữ liệu bằng cách sử dụng $ và một giá trị ký tự


120

Tôi có một vectơ gồm các tên cột khác nhau và tôi muốn có thể lặp qua từng tên để trích xuất cột đó từ data.frame. Ví dụ: hãy xem xét tập dữ liệu mtcarsvà một số tên biến được lưu trữ trong một vectơ ký tự cols. Khi tôi cố gắng chọn một biến từ mtcarscách sử dụng một tập hợp con của động cols, nether những công việc

cols <- c("mpg", "cyl", "am")
col <- cols[1]
col
# [1] "mpg"

mtcars$col
# NULL
mtcars$cols[1]
# NULL

làm cách nào để tôi có thể lấy những thứ này để trả về các giá trị giống như

mtcars$mpg

Hơn nữa, làm cách nào để tôi có thể lặp qua tất cả các cột colsđể nhận các giá trị trong một số loại vòng lặp.

for(x in seq_along(cols)) {
   value <- mtcars[ order(mtcars$cols[x]), ]
}

Câu trả lời:


181

Bạn không thể làm kiểu tập hợp con đó với $. Trong mã nguồn ( R/src/main/subset.c) nó nói:

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

Lập luận 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 cả ví dụ (, +, ^vv) là một chức năng, mà sẽ đưa lập luận và được đánh giá. df$V1có thể được viết lại thành

`$`(df , V1)

hoặc thực sự

`$`(df , "V1")

Nhưng...

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

... chẳng hạn sẽ không bao giờ hoạt động, cũng như bất kỳ thứ gì khác trước tiên phải được đánh giá trong đối số thứ hai. Bạn chỉ có thể chuyển một chuỗi 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 duy nhất 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 thứ tự mà không có vòng lặp, sử dụng do.callđể tạo lệnh gọi tới order. Đây là một ví dụ có thể tái tạo bên dưới:

#  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

Tình hình này có thay đổi trong những năm qua không?
Dunois

4

Nếu tôi hiểu chính xác, bạn có một vectơ chứa các tên biế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 chúng. 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 của bạn (ví dụ đầy đủ không hoàn chỉnh nên tôi không chắc bạn có thể thiếu cái gì khác) là nó nên được 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 đối lập với cột trực tiếp của khung dữ liệu của bạn (khi $nào 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

4

Sử dụng dplyr cung cấp một cú pháp dễ dàng để sắp xếp các khung dữ liệu

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

Có thể hữu ích khi sử dụng phiên bản NSE như được hiển thị ở đây để cho phép xây dựng động danh sách sắp xếp

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

NSE ở đây có nghĩa là gì?
discipulus

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

1

Một giải pháp khác là sử dụng #get:

> cols <- c("cyl", "am")
> get(cols[1], mtcars)
 [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4

0

Gặp sự cố tương tự do một số tệp CSV có nhiều tên khác nhau cho cùng một cột.
Đây là giải pháp:

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

# 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]))
}

0

nếu bạn muốn chọn cột có tên cụ thể thì chỉ cần làm

A=mtcars[,which(conames(mtcars)==cols[1])]
#and then
colnames(mtcars)[A]=cols[1]

bạn có thể chạy nó trong vòng lặp cũng như ngược lại để thêm tên động, ví dụ: nếu A là khung dữ liệu và xyz là cột được đặt tên là x thì tôi làm như thế này

A$tmp=xyz
colnames(A)[colnames(A)=="tmp"]=x

một lần nữa, điều này cũng có thể được thêm vào trong vòng lặp


Tôi không biết lý do tại sao bình chọn tiêu cực, nhưng nó hoạt động và cách dễ dàng thay vì viết các chức năng phức tạp
makarand Kulkarni


-1

quá muộn .. nhưng tôi đoán tôi có câu trả lời -

Đây là khung dữ liệu study.df mẫu của tôi -

   >study.df
   study   sample       collection_dt other_column
   1 DS-111 ES768098 2019-01-21:04:00:30         <NA>
   2 DS-111 ES768099 2018-12-20:08:00:30   some_value
   3 DS-111 ES768100                <NA>   some_value

Và sau đó -

> ## Selecting Columns in an Given order
> ## Create ColNames vector as per your Preference
> 
> selectCols <- c('study','collection_dt','sample')
> 
> ## Select data from Study.df with help of selection vector
> selectCols %>% select(.data=study.df,.)
   study       collection_dt   sample
1 DS-111 2019-01-21:04:00:30 ES768098
2 DS-111 2018-12-20:08:00:30 ES768099
3 DS-111                <NA> ES768100
> 
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.