Pilih kolom bingkai data secara dinamis menggunakan $ dan nilai karakter

121

Saya memiliki vektor nama kolom yang berbeda dan saya ingin dapat mengulang masing-masing untuk mengekstrak kolom itu dari data.frame. Misalnya, pertimbangkan kumpulan data mtcarsdan beberapa nama variabel yang disimpan dalam vektor karakter cols. Ketika saya mencoba untuk memilih variabel dari mtcarsmenggunakan subset dinamis cols, setelah pekerjaan ini

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

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

bagaimana saya bisa mendapatkan ini untuk mengembalikan nilai yang sama seperti

mtcars$mpg

Selanjutnya bagaimana saya bisa mengulang semua kolom colsuntuk mendapatkan nilai dalam semacam loop.

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

Jawaban:

182

Anda tidak dapat melakukan subset semacam itu dengan $. Dalam kode sumber ( R/src/main/subset.c) itu menyatakan:

/ * Operator $ subset.
Kita perlu memastikan untuk hanya mengevaluasi argumen pertama.
Yang kedua akan menjadi simbol yang perlu dicocokkan, bukan dievaluasi.
* /

Argumen kedua? Apa?! Anda harus menyadari bahwa $, seperti segala sesuatu yang lain di R, (termasuk misalnya (, +, ^dll) adalah fungsi, yang mengambil argumen dan dievaluasi. df$V1bisa ditulis ulang sebagai

`$`(df , V1)

atau memang

`$`(df , "V1")

Tapi...

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

... misalnya tidak akan pernah berhasil, begitu pula hal lain yang harus dievaluasi terlebih dahulu dalam argumen kedua. Anda hanya boleh meneruskan string yang tidak pernah dievaluasi.

Sebagai gantinya gunakan [(atau [[jika Anda ingin mengekstrak hanya satu kolom sebagai vektor).

Sebagai contoh,

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]

Anda dapat melakukan pengurutan tanpa loop, menggunakan do.calluntuk membuat panggilan ke order. Berikut adalah contoh yang dapat direproduksi di bawah:

#  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
Simon O'Hanlon
sumber
Apakah situasi ini telah berubah selama bertahun-tahun?
Dunois
4

Jika saya mengerti dengan benar, Anda memiliki vektor yang berisi nama variabel dan ingin mengulang melalui setiap nama dan mengurutkan bingkai data Anda dengan mereka. Jika demikian, contoh ini akan menggambarkan solusi untuk Anda. Masalah utama dalam Anda (contoh penuh tidak lengkap jadi saya "m tidak yakin apa lagi Anda mungkin hilang) adalah bahwa hal itu harus order(Q1_R1000[,parameter[X]])bukan order(Q1_R1000$parameter[X]), karena parameter adalah obyek eksternal yang berisi nama variabel lawan kolom langsung kerangka data Anda (yang mana $akan sesuai).

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
David
sumber
4

Menggunakan dplyr menyediakan sintaks yang mudah untuk menyortir bingkai data

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

Mungkin berguna untuk menggunakan versi NSE seperti yang ditunjukkan di sini untuk memungkinkan pembuatan daftar pengurutan secara dinamis

sort_list <- c("gear", "desc(mpg)")
mtcars %>% arrange_(.dots = sort_list)
manotheshark
sumber
Apa maksud NSE di sini?
Disiplin
1
@discipulus evaluasi non-standar; itu untuk bekerja dengan ekspresi tertunda untuk secara dinamis membangun kode dengan string alih-alih pengkodean keras. Lihat di sini untuk info lebih lanjut: cran.r-project.org/web/packages/lazyeval/vignettes/…
manotheshark
1

Solusi lain adalah menggunakan #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
EJAg
sumber
0

Mengalami masalah serupa karena beberapa file CSV yang memiliki berbagai nama untuk kolom yang sama.
Inilah solusinya:

Saya menulis fungsi untuk mengembalikan nama kolom valid pertama dalam daftar, lalu menggunakan itu ...

# 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]))
}
R Keene
sumber
0

Jika Anda ingin memilih kolom dengan nama tertentu maka lakukan saja

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

Anda dapat menjalankannya dalam lingkaran juga membalikkan cara untuk menambahkan nama dinamis misalnya jika A adalah bingkai data dan xyz adalah kolom yang diberi nama x maka saya melakukan seperti ini

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

sekali lagi ini juga dapat ditambahkan dalam lingkaran

makarand kulkarni
sumber
Saya tidak tahu mengapa memilih secara negatif, tetapi ini berfungsi dan cara yang mudah daripada menulis fungsi yang rumit
makarand kulkarni
0
mtcars[do.call(order, mtcars[cols]), ]
Hong Ooi
sumber
-1

terlambat .. tapi kurasa aku punya jawabannya -

Berikut contoh dataframe study.df saya -

   >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

Lalu -

> ## 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
> 
ValaravausHitam
sumber