Динамический выбор столбцов фрейма данных с помощью $ и вектора имен столбцов
я хочу заказать фрейм данных, основанный на разных столбцах, один за другим. У меня есть вектор символов с соответствующими именами столбцов, на которых 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]), ]
здесь X
и 1:10
(потому что у меня есть 10 элементов в parameter
).
чтобы сделать мой пример воспроизводимым, рассмотрим набор данных mtcars
и некоторые имена переменных, хранящиеся в символьном векторе cols
. Когда я пытаюсь выбрать переменную из mtcars
использование динамического подмножества cols
, таким же образом, как и выше (Q1_R1000$parameter[X]
), столбец не выбран:
cols <- c("cyl", "am")
mtcars$cols[1]
# NULL
6 ответов:
вы не можете сделать такое подмножество с
$
. В исходном коде (R/src/main/subset.c
) говорится:/*оператор $ subset.
Мы должны быть уверены, что оцениваем только первый аргумент.
Второй будет символом, который должен быть сопоставлен, а не оценен.
* /второй аргумент? Что?! Вы должны понять, что
$
, как и все остальное в R, (включая, например,(
,+
,^
etc) - это функция, которая принимает аргументы и вычисляется.df$V1
можно переписать в виде`$`(df , V1)
или даже
`$`(df , "V1")
но...
`$`(df , paste0("V1") )
...например, никогда не будет работать, и не будет ничего другого, что должно быть сначала оценено во втором аргументе. Вы можете передать только строку, которая является никогда оценка.
вместо того, чтобы использовать
[
(или[[
если вы хотите извлечь только один столбец как вектор.)например,
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
если я правильно понимаю, у вас есть вектор, содержащий имена переменных и хотел бы цикл через каждое имя и сортировать фрейм данных по ним. Если да, то этот пример должен проиллюстрировать решение для вас. Основная проблема в вашем (полный пример не завершен, поэтому я не уверен, что еще вам может не хватать) заключается в том, что он должен быть
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
использование dplyr обеспечивает простой синтаксис для сортировки фреймов данных
library(dplyr) mtcars %>% arrange(gear, desc(mpg))
было бы полезно использовать версию NSE для динамического построения списка сортировки
sort_list <- c("gear", "desc(mpg)") mtcars %>% arrange_(.dots = sort_list)
была аналогичная проблема из-за некоторых 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])) }
Если вы хотите выбрать столбец с определенным именем, то просто сделать
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
опять же, это также может быть добавлено в цикл