【问题标题】:Subset data frame based on first letters of column name基于列名首字母的子集数据框
【发布时间】:2014-03-07 22:39:09
【问题描述】:

我有一个大型数据框,其中多列代表针对不同个体测量的不同变量。列的名称总是以数字开头(例如 1:18)。我想对 df 进行子集化并为每个人创建单独的 dfs。这是一个例子:

x <- as.data.frame(matrix(nrow=10,ncol=18))
colnames(x) <- paste(1:18, 'col', sep="")

我的真实 df 的列名是由个体 ID、变量名和度量数组成的(我对每个变量进行了 3 个度量)。因此,例如,我有个人 1 的度量 b(主体),然后在 df 中我将有 3 个名为:1b1、1b2、1b3 的列。最后,我有 10 个不同的区域(身体、头部、尾部、尾根、背部、侧面、腹部、喉咙、前臂、腿部)。因此,对于每个人,我有 30 列(10 个区域 x 每个区域 3 个度量)。所以我有多个以不同数字开头的变量,然后我想根据它们的唯一数字进行子集化。我尝试使用 grep:

partialName <- 1
df2<- x[,grep(partialName, colnames(x))]
colnames(x)
[1] "1col" "2col" "3col" "4col" "5col" "6col" "7col" "8col" "9col" "10col" 
"11col" "12col" "13col" "14col" "15col" "16col" "17col" "18col"

我的问题在这里你可以看到它没有分开个人,因为 1 和 10 在子集中。换句话说,这会选择以 1 开头的所有人。 最终我想做的是遍历我所有的人 (1:18),为每个人创建新的 dfs。

【问题讨论】:

  • 欢迎来到 SO。您能否提供colnames 并说明您的期望?
  • 感谢 Llopis 的回复。好的。在上面的示例中,我的列名是:[1]“1col”“2col”“3col”“4col”“5col”“6col”“7col”“8col”“9col”“10col”“11col”“12col”“13col” “14col” “15col” “16col” “17col” “18col” 我想返回不同的 dfs 子集,其中它们的名称以相同的数字开头。在上面的示例中,我将有 18 个新的 dfs,每个有 1 列、1col、2col、3cols 等等。清楚吗?
  • @user3293163 将这些内容编辑到问题中,而不是作为评论发布。
  • 如果您的列名格式为 1_var1、2_var1、12_var10,那么您可以使用 melt 获取长格式数据,然后使用 colsplit 将列名拆分为 2 个变量个人和措施。随后,您可以根据需要cast 数据和/或split
  • @user3293163 你的真实 colnames是什么样的,你能控制它们还是只是给定的。

标签: r subset


【解决方案1】:

我认为将数据保存在一个 data.frame 中是最好的选择。要么,要么将其放入data.frame 的列表中。这使得提取每个人的汇总统计数据变得更加容易。

首先创建一些示例数据:

df = as.data.frame(matrix(runif(50 * 100), 100, 50), stringsAsFactors = FALSE)
names_variables = c('spam', 'ham', 'shrub')
individuals = 1:100
column_names = paste(sample(individuals, 50), 
                     sample(names_variables, 50, TRUE), 
                     sep = '')
colnames(df) = column_names

我首先要做的是使用melt 将数据从宽格式转换为长格式。这实际上将所有列堆叠在一个大向量中,并添加一个额外的列来说明它来自哪一列:

library(reshape2)
df_melt = melt(df)
head(df_melt)
  variable      value
1    85ham 0.83619111
2    85ham 0.08503596
3    85ham 0.54599402
4    85ham 0.42579376
5    85ham 0.68702319
6    85ham 0.88642715

然后我们需要将ID号与变量分开。这里假设变量的数字部分是个体ID,文本是变量名:

library(dplyr)
df_melt = mutate(df_melt, individual_ID = gsub('[A-Za-z]', '', variable),
                          var_name = gsub('[0-9]', '', variable))

基本上删除了不需要的字符串部分。现在我们可以做一些好事,比如:

mean_per_indivdual_per_var = summarise(group_by(df_melt, individual_ID, var_name), 
                                       mean(value))
head(mean_per_indivdual_per_var)
  individual_ID var_name mean(value)
1            63     spam   0.4840511
2            46      ham   0.4979884
3            20    shrub   0.5094550
4            90      ham   0.5550148
5            30    shrub   0.4233039
6            21      ham   0.4764298

【讨论】:

  • 亲爱的 Paul Hiemstra,这看起来很不错,但我还是遇到了一些麻烦。首先,我需要将我的数据恢复为原始格式(每个变量在不同的列中)。其次,对于每个变量,我有三个不同的度量,例如 63spam1、63spam2、63spam3。这会干扰个人 ID 的生成,因为 63spam1 变为 631。知道如何处理这个问题吗?非常感谢您的帮助。
  • 请用更多细节扩展您的问题,并向我们展示您在解决问题时的尝试(例如,使用我的示例代码)。如果您在想出自己的解决方案时遇到困难,请编辑此问题或提出新问题。
  • 感谢@Paul Hiemstra。我相应地更改了您的代码。现在列名的结构与我的原始数据相似。它们以数字(个人 ID)开头,然后是变量名称(测量变量的区域),然后是另一个数字(重复)。例如,在您上面的代码中,您有列 81shrub1(个体 81,区域灌木,测量 1)。我最终想要的是每个个人 ID 一个 df。
【解决方案2】:

您的 colnames 似乎是 data.frame 的标准,因此要仅获取第 1 列,您可以这样做:

df2 <- df[,1] #Where 1 can be changed to the number of column you wish.

无需按部分名称进行子集化。 虽然不建议您创建一个循环来这样做:

for (i in ncol(x)){
  assing(paste("df",i), x[,i]) #I use paste to get a different name for each column
}

虽然@paulhiemstra 解决方案避免了循环。

所以有了新信息,你就可以用 grep 做你想做的事,但具体告诉你期望多少匹配:

df2<- x[,grep("1{30}", colnames(x))] 

【讨论】:

  • 对不起,我用了一个不好的变量名例子来说明我的问题。就我而言,如果列号,我将无法工作。
  • 那么,你真正的列名是什么?如果您说您对每个变量有三个观察值(我假设这意味着您可以创建嵌套数据框的每一列:包含所有数据的数据框,以及每个变量内部的多个数据框。但请尝试完成您的问题,我们无法猜测所有这些问题。
  • 我的真实df的列名是个人ID、变量名和度量值的组合(我对每个变量进行了3个度量)。因此,例如,我有个人 1 的度量 b(主体),然后在 df 中我将有 3 个名为:1b1、1b2、1b3 的列。最后,我有 10 个不同的区域(身体、头部、尾部、尾根、背部、侧面、腹部、喉咙、前臂、腿部)。因此,对于每个人,我有 30 列(10 个区域 x 每个区域 3 个度量)。
  • 请添加一个准确反映您的情况的可重现示例。您的问题缺乏细节会导致答案缺乏细节。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-10-08
  • 2020-11-21
  • 1970-01-01
  • 1970-01-01
  • 2021-04-25
  • 2015-08-09
  • 1970-01-01
相关资源
最近更新 更多