使用$和列名称向量动态选择数据框列

Sam*_*ong 103 r dataframe r-faq

我希望根据不同的列来订购数据框,一个转弯.我有一个字符向量,其中的相关列名order应该基于:

parameter <- c("market_value_LOCAL", "ep", "book_price", "sales_price", "dividend_yield",
               "beta", "TOTAL_RATING_SCORE", "ENVIRONMENT", "SOCIAL", "GOVERNANCE")
Run Code Online (Sandbox Code Playgroud)

我想循环遍历名称parameter并动态选择要用于order我的数据的列:

Q1_R1000_parameter <- Q1_R1000[order(Q1_R1000$parameter[X]), ]
Run Code Online (Sandbox Code Playgroud)

这里X1:10(因为我有10个项目parameter).


为了使我的示例可重现,请考虑mtcars存储在字符向量中的数据集和一些变量名称cols.当我尝试mtcars使用动态子集选择变量时cols,以与上面(Q1_R1000$parameter[X])相似的方式,未选择该列:

cols <- c("cyl", "am")
mtcars$cols[1]
# NULL
Run Code Online (Sandbox Code Playgroud)

Sim*_*lon 164

你无法做那种子集化$.在源代码(R/src/main/subset.c)中,它声明:

/*$ subset运算符.
我们需要确保只评估第一个参数.
第二个是需要匹配的符号,而不是评估符号.
*/

第二个论点?什么?!你必须认识到$,像R中的一切(包括例如(,+,^等)是一个函数,接受参数,并进行评估.df$V1可以改写为

`$`(df , V1)
Run Code Online (Sandbox Code Playgroud)

或者确实

`$`(df , "V1")
Run Code Online (Sandbox Code Playgroud)

但...

`$`(df , paste0("V1") )
Run Code Online (Sandbox Code Playgroud)

...例如永远不会工作,也不会在第二个参数中首先评估任何其他东西.您只能传递一个永远不会被评估的字符串.

而是使用[(或者[[如果您只想提取单个列作为向量).

例如,

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]
Run Code Online (Sandbox Code Playgroud)

您可以执行无循环的排序,使用do.call构造调用order.以下是可重现的示例:

#  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
Run Code Online (Sandbox Code Playgroud)

  • 这些年来这种情况有改变吗? (3认同)

Dav*_*vid 5

如果我理解正确,您有一个包含变量名称的向量,并且希望循环遍历每个名​​称并按它们对数据框进行排序。如果是这样,这个例子应该为您说明一个解决方案。您的主要问题(完整的示例不完整,所以我不确定您可能还缺少什么)是它应该代替order(Q1_R1000[,parameter[X]])order(Q1_R1000$parameter[X])因为参数是一个外部对象,其中包含与直接列相反的变量名您的数据框(当$合适时)。

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
Run Code Online (Sandbox Code Playgroud)


man*_*ark 5

使用dplyr提供了一种用于对数据帧进行排序的简单语法

library(dplyr)
mtcars %>% arrange(gear, desc(mpg))
Run Code Online (Sandbox Code Playgroud)

使用此处所示的NSE版本以允许动态构建排序列表可能会很有用。

sort_list <- c("gear", "desc(mpg)")
mtcars %>% arrange_(.dots = sort_list)
Run Code Online (Sandbox Code Playgroud)


Vis*_*rma 5

我会实现packagesym的功能rlang。假设 的col值为"mpg"。这个想法是对其进行子集化。

mtcars %>% pull(!!sym(col))
#  [1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2 10.4 10.4 14.7 32.4 30.4 33.9 21.5 15.5 15.2 13.3 19.2 27.3 26.0 30.4 15.8 19.7 15.0
# [32] 21.4
Run Code Online (Sandbox Code Playgroud)

继续编码!

  • `sym` 来自 `rlang`,而不是 `purrr`。最好解释一下*为什么*这是您推荐的 (4认同)