【问题标题】:What is the most efficient way to select a set of variable names from an R data.frame?从 R data.frame 中选择一组变量名的最有效方法是什么?
【发布时间】:2012-03-14 13:48:17
【问题描述】:

问题:

我经常需要从 R 中的 data.frame 中选择一组变量。 我的研究是社会和行为科学,拥有一个包含数百个变量的数据框架是很常见的(例如,会有一系列调查问题、人口统计项目、绩效指标等的项目级别信息.等)。

作为分析的一部分,我经常想要选择一个变量子集。 例如,我可能想得到:

  • 一组变量的描述性统计
  • 一组变量的相关矩阵
  • 对一组变量进行因子分析
  • 线性模型中的预测变量

现在,我知道有很多方法可以编写代码来选择变量子集。 Quick-r has a nice overview of common ways of extracting variable subsets from a data.frame.

例如,

myvars <- c("v1", "v2", "v3")
newdata <- mydata[myvars]

不过,我对这个过程的效率很感兴趣,尤其是当您可能需要从 data.frame 中提取 20 个左右的变量时。变量的命名约定通常不直观,尤其是在您从其他人那里继承数据集的情况下,因此您可能会想知道,变量是 GendergendersexGENDER、@987654329 @, 等等。 将其乘以需要提取的 20 个变量,记住变量名称的任务变得比实际需要的复杂。

具体例子

为了使下面的讨论具体化,我将使用psych 包中的bfi data.frame。

library(psych)
data(bfi)
df <- bfi
head(df, 1)
      A1 A2 A3 A4 A5 C1 C2 C3 C4 C5 E1 E2 E3 E4 E5 N1 N2 N3 N4 N5 O1 O2 O3 O4
61617  2  4  3  4  4  2  3  3  4  4  3  3  3  4  4  3  4  2  2  3  3  6  3  4
      O5 gender education age
61617  3      1        NA  16
  • 如何有效地选择任意变量集,具体而言,我将选择A1, A2, A3, A5, C2, C3, C5, E2, E3, gender, education, age

我目前的策略

我目前有一系列我使用的策略。 当然,有时我可以利用变量的数字位置或命名约定之类的东西,并使用grep 来选择或paste 来构造。但有时我需要一个更通用的解决方案。我一直在使用以下内容:

1。名称(df)

在早期,我曾经调用names(df),复制引用的变量名,然后编辑直到我想要的。

2。使用数据库

有时我会有一个单独的 data.frame 将每个变量存储为一行,并有变量名称、变量标签的列,并且它有一列指示是否应为特定分析保留变量。然后我可以过滤该include 变量并提取变量名称向量。我发现这在我开发心理测试以及想要包含或排除某些项目的各种迭代时特别有用。

3。输入(名称(df))

作为Hadley Wickham once pointed out to medput是一个不错的选择;例如,dput(names(df))names(df) 更好,因为它输出的列表已经是 c("var1", "var2", ...) 格式:

dput(names(df))
c("A1", "A2", "A3", "A4", "A5", "C1", "C2", "C3", "C4", "C5", 
"E1", "E2", "E3", "E4", "E5", "N1", "N2", "N3", "N4", "N5", "O1", 
"O2", "O3", "O4", "O5", "gender", "education", "age")

然后可以将其复制到脚本中并进行编辑。

但是能不能更高效

我猜dput 是一个相当不错的变量选择策略。该过程的效率很大程度上取决于您将文本复制到脚本中然后将名称列表编辑成所需的名称的熟练程度。

但是,我仍然记得基于 GUI 的变量选择系统的效率。 例如,在 SPSS 中,当您与对话框交互时,您可以用鼠标指向并单击数据集中所需的变量。您可以按住 shift 单击选择一系列变量,您可以按住 shift 并按下向下键选择一个或多个变量,依此类推。然后您可以按Paste,将提取变量名称的命令粘贴到您的脚本编辑器中。

所以,最后是核心问题

  • 是否有一个简单的 GUI 设备允许从 data.frame 中选择变量(例如,guiselect(df) 之类的东西打开一个用于变量选择的 gui 窗口),并返回一个选定的变量名称向量 c("var1", "var2", ...) ?
  • dput 是在 R 中选择一组变量名称的最佳通用选项吗?还是有更好的方法?

更新(2017 年 4 月):我发布了自己对 good strategy below 的理解。

【问题讨论】:

  • 如果您使用 Office 在 Windows 上工作,一个选项是使用 write.csv() 将您的 data.frame 保存到 csv 文件,用 Excel 打开它,删除不需要的列,保存,然后使用read.csv() 将其读回R。我希望人们提出更好的解决方案...
  • edit(df),不要的删掉?
  • @blindJesse 我很少想在这些上下文中实际修改 data.frame。在一组典型的分析中,我将为不同的分析提取 20 或 30 个不同的变量子集。对我来说,任何更改都记录在我的脚本中也很重要,这样结果是可重现的。
  • 我喜欢这个问题!我一直在忍受输入名称(甚至不知道 dput 的事情)。我什至从未想过会有一种 R 风格的方法。
  • @JeromyAnglim。你现在是如何处理这个问题的?现在是 2017 年,我仍然需要在 R 中的 regsubsets( ) 中输入 var1 + var2 + var3 + .... var158。我仍然认为在 JMP 和 SPSS 中进行此类分析更容易。

标签: r


【解决方案1】:

我个人是myvars &lt;- c(...) 的粉丝,然后从那里开始使用mydf[,myvars]

但是,这仍然需要您输入初始变量名(即使只输入一次),据我阅读您的问题,您要问的是这个初始的“选择变量名”。

这是一个简单的简洁的 GUI 设备 -- 我最近被介绍到 menu 函数,它正是一个简单的简洁的 GUI 设备,用于从选择列表。试试menu(names(df),graphics=TRUE) 看看我的意思(返回列号)。如果由于某种原因您的系统无法处理图形,它甚至会提供一个很好的文本界面(尝试使用graphics=FALSE 来了解我的意思)。

但这对您的用处有限,因为您只能选择一个列名。 要选择多选,您可以使用select.list(在?menu 中提到作为多选的替代方法):

# example with iris data (I don't have 'psych' package):
vars <- select.list(names(iris),multiple=TRUE,
                    title='select your variable names',
                    graphics=TRUE)

这也需要graphics=TRUE 选项(单击您要选择的所有项目)。 它返回变量的名称。

【讨论】:

  • 谢谢。你已经明白我的问题了。我不知道select.list。我只是玩了一下。这当然不是多余的。在功能方面,它缺少我在 SPSS gui 上习惯的几个功能。无移位点击;没有移位和光标;键入一个字符不会将选择带到该变量的下一个匹配项,该变量的第一个字符等于该字母)。但我认为这个想法很有希望。
  • 同样遗憾的是,至少在我使用的版本中,tcl/tk 似乎在 rstudio v.0.94.110 中不起作用
  • @JeromyAnglim 我在 Windows 上使用 RStudio v.0.95.258 没有 tcl/tk 问题。
【解决方案2】:

你可以使用select.list(),像这样:

DF <- data.frame(replicate(26,list(rnorm(5))))
names(DF) <- LETTERS
subDF <- DF[select.list(names(DF), multiple=TRUE)]

【讨论】:

  • 谢谢(也+1)。我首先看到了@mathematical.coffee 的答案。但它看起来像你的时间是第一个。正如我在评论中提到的。我认为select.list 还可以。但是,可以添加许多简单的功能来提高可用性。
  • @JeromyAnglim -- 谢谢。我可能已经开始先回答了,但@mathematical.coffee 确实先点击了“保存编辑”。更重要的是——至少在 Windows XP 上,以及 multiple=TRUEgraphics=TRUE(我的默认值),select.list() 很好地支持 Shift-clickCtrl-click,以及它们的典型行为。不过,您是对的,它不会带您在键入时提前与变量名紧密匹配。但对于这类事情,您最好先用grep("gender", ignore.case=TRUE, value=TRUE) 之类的东西探索names(DF)。祝你好运!
  • 好的。我在 Ubuntu 上;所以我想这就是我错过 shift-click 功能的原因。
  • 是的,我花了几分钟想 select.list 坏了,因为我无法让 shift-click 和 ctrl-click 工作,然后我有一个 d'oh 时刻并实现正常点击会做的伎俩:P
【解决方案3】:

我使用以下策略来提高 R 中的变量选择效率。

使用元数据存储变量名

对于某些变量集,我有每个变量一行的数据框。例如,我可能有一个 100 项的性格测试。元数据包括 R 中的变量名称以及所有评分信息(例如,项目是否应该颠倒等等)。然后,我可以从该元数据中提取项目的变量名称和比例名称。

将变量集存储在命名列表中

在每个项目中,我都有一个名为v 的列表,用于存储命名的变量集。 然后在任何需要一组变量的分析中,我可以只引用命名列表。这也使代码更可靠,因为如果变量名称发生变化,所有条件分析也会发生变化。它还有助于在变量排序方式上保持一致性。

这是一个简单的例子:

v <- list()
v$neo_items <- meta.neo$id
v$ds14_items <- meta.ds14$id
v$core_items <- c(v$neo_items, v$ds14_items)       

v$typed_scales <- c("na", "si")
v$typed_all <- c("typed_continuous_sum", "na", "si")
v$neo_facets <- sort(unique(meta.neo$facet))
v$neo_factors <- c("agreeableness", "conscientiousness", 
                   "extraversion", "neuroticism", "openness")
v$outcomes_scales <- c("healthbehavior", "socialsupport", 
                "physical_symptoms", "psychological_symptoms")

从上面的例子可以看出几点:

  • 变量列表通常由我单独存储的元数据生成。例如,我将新人格测试的 240 个项目的变量名存储在 meta.neo$id
  • 在某些情况下,变量名可以来自元数据。例如,我的性格测试元数据中的一列指示该项目属于哪个等级,变量名称是通过采用该列的unique 值从该列派生的。
  • 在某些情况下,变量集是较小集的组合。例如,您可能有一组用于预测变量,一组用于结果,还有一组组合预测变量和结果。预测变量和结果的划分可能对某些回归模型有用,而组合集可能对相关矩阵或因子分析有用。
  • 对于更多的临时变量列表,我仍然使用dput(names(df),其中df 是我的data.frame 来生成字符名称向量,然后将其存储在变量列表中。
  • 这些变量列表通常放置在您加载数据之后,但在您调整数据之前。这样,它们可用于数据准备,并且在您开始运行分析(例如,预测模型、相关性、描述性统计等)时肯定可用。
  • 变量列表的美妙之处在于您可以在 RStudio 中轻松使用自动完成。所以你不需要记住变量名,甚至变量列表的名称。您只需输入 v$ 并按 Tab 或 v$ 以及列表名称的某些部分。

使用变量列表

使用变量列表相当简单,但 R 中的某些函数指定变量名称的方式不同。

简单而标准的场景涉及将变量名称列表提供给 data.frame 子集。例如,

cor(data[,v$mylist])
cor(data[,v$predictors], data[,v$outcomes])

对于需要公式的函数来说,这有点棘手。您可能需要编写一个函数。例如:

v <- list()
v$predictors <- c("cyl", "disp")
f <- as.formula(paste("mpg ~", paste(v$predictors, collapse = " + ")))
lm(f, mtcars)

您还可以在 sapplylapply 等函数中使用变量列表(可能是 tidyverse 的等价物)。例如,

创建一个描述性统计表:

sapply(mydata[, v$outcomes], function(X) c(mean = mean(X), sd = sd(X)))

dput 还是有用的

对于临时变量,甚至当您只是编写代码来创建变量列表时,dput 仍然非常有用。

标准代码是dput(names(df)),其中df 是您的data.frame。比如:

 dput(names(mtcars))

生产

 c("mpg", "cyl", "disp", "hp", "drat", "wt", "qsec", "vs", "am", 
 "gear", "carb")

然后您可以编辑此字符串以提取您需要的变量。 这有一个额外的好处,它可以减少代码中的输入错误。这是非常重要的一点。您不希望花费大量时间尝试调试仅由拼写错误导致的代码。此外,错误输入变量名时的 Rs 错误消息很糟糕。它只是说“选择了未定义的列”。它不会告诉你哪些变量名是错误的。

如果您有大量变量,您还可以使用一系列字符串搜索函数来提取变量名称的子集:

例如

> library(psych)
> dput(names(bfi)) #all items
c("A1", "A2", "A3", "A4", "A5", "C1", "C2", "C3", "C4", "C5", 
"E1", "E2", "E3", "E4", "E5", "N1", "N2", "N3", "N4", "N5", "O1", 
"O2", "O3", "O4", "O5", "gender", "education", "age")
> dput(grep("^..$", names(bfi), value = TRUE)) # two letter variable names
c("A1", "A2", "A3", "A4", "A5", "C1", "C2", "C3", "C4", "C5", 
"E1", "E2", "E3", "E4", "E5", "N1", "N2", "N3", "N4", "N5", "O1", 
"O2", "O3", "O4", "O5")
> dput(grep("^E.$", names(bfi), value = TRUE)) # E items
c("E1", "E2", "E3", "E4", "E5")
> dput(grep(".5$", names(bfi), value = TRUE)) # 5th items
c("A5", "C5", "E5", "N5", "O5")

清理现有变量名并使用命名约定

当我从其他人那里获取数据文件时,变量名称通常缺乏约定或使用约定,这使得在 R 中处理变量的用处不大。我使用的一些规则:

  • 将所有变量设为小写(不得不考虑大小写变量很烦人)
  • 使变量名具有内在意义(其他一些软件使用变量标签来存储有意义的数据;R 并不真正使用标签)
  • 将变量保持在适当的长度(即,不要太长)。最多 10 个字符就可以了。超过 20 个会很烦人。

所有这些步骤通常使变量选择更容易,因为要记住的不一致更少。

对单个变量名使用制表符完成

对于单个变量,我通常使用数据框中的自动完成。例如,df$ 并按 Tab。

我尝试使用允许我尽可能使用自动完成的编码风格。我不喜欢需要我知道变量名而不使用自动完成的函数。例如,当子集 data.frame 时,我更喜欢

df[ df$sample == "control", ]

subset(df, sample == "control")

因为我可以在上面的例子中自动完成变量名“sample”,但不能在第二个例子中。

【讨论】:

    【解决方案4】:

    如果您想要一种忽略变量大小写的方法,并且可能会根据它们的“词干”挑选出变量,那么请使用适当的正则表达式模式并在 grep 中使用 ignore.case-=TRUE 和 value=TRUE:

     dfrm <- data.frame(var1=1, var2=2, var3=3, THIS=4, Dont=5, NOTthis=6, WANTthis=7)
    unlist(sapply( c("Want", "these", "var"),
       function(x) grep(paste("^", x,sep=""), names(dfrm), ignore.case=TRUE, value=TRUE) ))
    #----------------
          Want       var1       var2       var3   # Names of the vector
    "WANTthis"     "var1"     "var2"     "var3"   # Values matched
    > dfrm[desired]
      WANTthis var1 var2 var3
    1        7    1    2    3
    

    【讨论】:

    • 我想我有很多与模式匹配的变量,grep 是一个选项。当我有具有系统命名约定的变量时,我会经常使用paste("var", 1:20, sep="") 之类的东西。但是,对我来说,在许多情况下,尝试考虑一个好的 grep 通常比使用 dput 和一些编辑来挑选变量要花费更长的时间。我想这取决于 data.frame 中的命名约定。我还担心任何类似 grep 的过程,我可能随后将变量添加到现有 grep 可能匹配的 data.frame。
    • 有些人很难满足。
    【解决方案5】:

    你的意思是select

    sub_df = subset(df, select=c("v1","v2","v3"))
    

    【讨论】:

    • 对不起。不,我了解从 data.frame 中提取变量的机制。我对一种为变量名向量生成代码的有效方法很感兴趣。
    • 对不起。我没听懂这个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-10
    • 2020-04-22
    • 1970-01-01
    • 2022-08-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多