首页 文章

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

提问于
浏览
81

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

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

我希望循环 parameter 中的名称并动态选择要用于 order 我的数据的列:

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

其中 X1:10 (因为我在 parameter 中有10个项目) .


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

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

6 回答

  • 3

    你不能用 $ 进行那种子集化 . 在源代码( R/src/main/subset.c )中,它声明:

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

    第二个论点?什么?!你必须意识到 $ ,就像R中的其他所有东西一样(包括例如 (+^ 等)是一个函数,它接受参数并进行求值 . df$V1 可以改写为

    `$`(df , V1)
    

    或者确实

    `$`(df , "V1")
    

    但...

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

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

    而是使用 [ (如果您只想将单个列提取为矢量,则使用 [[ ) .

    例如,

    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]
    

    您可以使用 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
    
  • 1

    如果我理解正确,你有一个包含变量名称的向量,并希望遍历每个名称并按它们对数据框进行排序 . 如果是这样,这个例子应该为您说明一个解决方案 . 你的主要问题(完整的例子不完整,所以我不确定你还有什么可能遗漏)是它应该是 order(Q1_R1000[,parameter[X]]) 而不是 order(Q1_R1000$parameter[X]) ,因为参数是一个外部对象,包含一个与a相对的变量名数据框的直接列(适用于 $ 时) .

    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
    
  • 138

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

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

    使用NSE版本允许动态构建排序列表可能很有用

    sort_list <- c("gear", "desc(mpg)")
    mtcars %>% arrange_(.dots = sort_list)
    
  • 0
    Q1_R1000[do.call(order, Q1_R1000[parameter]), ]
    
  • 0

    由于某些CSV文件具有相同列的各种名称,因此存在类似问题 .
    这是解决方案:

    我写了一个函数来返回列表中的第一个有效列名,然后用它...

    # 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

    如果你想选择具有特定名称的列,那么就这样做

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

    您可以在循环中运行它以及添加动态名称的反向方式,例如,如果A是数据框,而xyz是要命名为x的列,那么我喜欢这个

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

    再次,这也可以循环添加

相关问题