【问题标题】:Loop over columns R循环列 R
【发布时间】:2015-12-15 16:24:43
【问题描述】:

我在R 中有一个data.frame,它包含许多带有数值的列。 像这样:

   A       B      C
0.6057  0.1644  6.93
0.5723  0.117   6.59
0.5614  0.1552  7.02
0.4102  0.1059  5.24
0.4945  0.0857  6.64
0.5157  0.0747  7.06
0.7785  0.1394  5.21
0.5492  0.1557  6.06
0.5411  0.1884  5.68
0.6622  0.148   6.1

对于这些列中的每一列,我想创建一个包含四分位值的新列。使用此公式一次处理一列没有问题:

tableOne <- within(data, quartile <-
                    as.integer(cut(A, quantile(A, probs=0:5/5,na.rm=T))))

但由于 100 columns 的名称不同,我想分别循环遍历每一列。

我尝试了一个循环但没有成功:

for(i in names(data)){
  tableOne <- within(data, quarti <- as.integer(cut(i, quantile(i, probs=0:5/5,na.rm=T))))
}

我收到以下错误:

Error in cut.default(i, quantile(i, probs = 0:5/5, na.rm = T)) : 
  'x' must be numeric

我也试过应用函数:

df.two <- lapply(df, function(x) within(data, quartile <- as.integer(cut(x, quantile(x, probs=0:5/5,na.rm=T)))))

没有成功:

Error during wrapup: argument "obj" is missing, with no default
Error during wrapup: target context is not on the stack

关于如何在所有列上迭代我的函数并在同一 data.frame 中获取所有结果的任何建议?

非常感谢

【问题讨论】:

  • 创建一个函数(以向量为参数)并使用lapply
  • 我试过 apply 但我并不比循环更好!
  • df.two &lt;- lapply(data, function(x) within(data, quartile &lt;- as.integer(cut(x, quantile(x, probs=0:5/5,na.rm=T)))))
  • 也许,cbind(df, lapply(df, function(x) as.integer(cut(x, quantile(x, probs=0:5/5,na.rm=T))))),但我无法测试,因为您没有提供可重现的示例。
  • 您的示例数据集不需要超过 3 列,可能需要 10 行。

标签: r loops


【解决方案1】:

请参阅答案末尾以获得更好的方法,这是为了便于理解步骤。

我不确定你愿意做什么,但也许是这样:

df2<- as.data.frame( lapply( df, function(x){
  as.integer( cut(x, quantile(x, probs=(0:5)/5, na.rm=T)))
}))
colnames(df2) <- paste0("quartile_",colnames(df))
df3 <- cbind(df,df2)

这给出了:

        A      B    C quartile_A quartile_B quartile_C
1  0.6057 0.1644 6.93          4          5          4
2  0.5723 0.1170 6.59          4          2          3
3  0.5614 0.1552 7.02          3          4          5
4  0.4102 0.1059 5.24         NA          2          1
5  0.4945 0.0857 6.64          1          1          4
6  0.5157 0.0747 7.06          2         NA          5
7  0.7785 0.1394 5.21          5          3         NA
8  0.5492 0.1557 6.06          3          4          2
9  0.5411 0.1884 5.68          2          5          2
10 0.6622 0.1480 6.10          5          3          3

使用的数据:

> dput(df)
structure(list(A = c(0.6057, 0.5723, 0.5614, 0.4102, 0.4945, 
0.5157, 0.7785, 0.5492, 0.5411, 0.6622), B = c(0.1644, 0.117, 
0.1552, 0.1059, 0.0857, 0.0747, 0.1394, 0.1557, 0.1884, 0.148
), C = c(6.93, 6.59, 7.02, 5.24, 6.64, 7.06, 5.21, 6.06, 5.68, 
6.1)), .Names = c("A", "B", "C"), class = "data.frame", row.names = c(NA, 
-10L))

根据下面的@DavidArenburg 评论,实现相同结果的更好方法是:

df[paste0("quartile_",colnames(df))] <- lapply(df, function(x) as.integer(cut(x, quantile(x, probs=(0:5)/5, na.rm = TRUE))))

这避免了创建一个新的数据框并在最后复制它。

【讨论】:

  • 您可以使用df[paste0("quartile_",colnames(df))] &lt;- lapply(df, function(x) as.integer(cut(x, quantile(x, probs=(0:5)/5, na.rm = TRUE))))一次性完成此操作
  • @David 我将其分为 3 个步骤以方便理解(并且懒得在 1 次通过时缩短它),这表示您应该将其添加为未来读者的另一个答案;)
  • 我认为你可以编辑...我看不出有理由再次转换为data.frame,创建一个新对象,然后使用cbind 再次复制所有内容。上面的行不仅更短,而且我认为效率更高。
  • @David,因为它是你的,我不想偷它;)有多个答案是完全有效的,这里是一种不同的方法,所以它应该独立存在以允许其他人投票选出最有用/性能最好的,以指导读者做出选择(以我的拙见)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-22
  • 2016-03-18
  • 2015-10-12
  • 2010-12-09
  • 2016-06-28
相关资源
最近更新 更多