我有一个名为“Volume”的小标题,我在其中存储了一些数据(10 列 - 前 2 列是字符,30 行)。 现在我想计算与我的 tibble 的第 3 列相对应的每一列的相对体积。 我目前的解决方案如下所示:
rel.Volume_unmod = tibble(
"Volume_OD" = Volume[[3]] / Volume[[3]],
"Volume_Imp" = Volume[[4]] / Volume[[3]],
"Volume_OD_1" = Volume[[5]] / Volume[[3]],
"Volume_WS_1" = Volume[[6]] / Volume[[3]],
"Volume_OD_2" = Volume[[7]] / Volume[[3]],
"Volume_WS_2" = Volume[[8]] / Volume[[3]],
"Volume_OD_3" = Volume[[9]] / Volume[[3]],
"Volume_WS_3" = Volume[[10]] / Volume[[3]])
rel.Volume_unmod
我想保留 tibble 结构和标签。我确信有一个更好的解决方案,但我对 R 比较陌生,所以我对我来说并不明显。我试过的是这样的,但我实际上无法运行:
rel.Volume = NULL
for(i in Volume[,3:10]){
rel.Volume[i] = tibble(Volume = Volume[[i]] / Volume[[3]])
}
答案 0 :(得分:2)
由于您没有提供一些数据,我按照您提供的描述创建了一些模型数据。这里:
set.seed(1)
Volume <- data.frame(ID = sample(letters, 30, TRUE),
GR = sample(LETTERS, 30, TRUE))
Volume[3:10] <- rnorm(30*8)
library(dplyr)
# rename columns [brute force]
cols <- c("Volume_OD","Volume_Imp","Volume_OD_1","Volume_WS_1","Volume_OD_2","Volume_WS_2","Volume_OD_3","Volume_WS_3")
colnames(Volume)[3:10] <- cols
# divide by Volumn_OD
rel.Volume_unmod <- Volume %>%
mutate(across(all_of(cols), ~ . / Volume_OD))
# result
rel.Volume_unmod
rel.Volume_unmod
中创建的列的名称相对应。无论如何,为了避免任何问题,我重命名了列(有点残酷)。如果您愿意,可以使用 dplyr::rename
来完成。mutate
的列。 mutate
是来自 dplyr
的动词,允许您创建新列或对列执行操作或函数。across
是来自 dplyr
的副词。让我们简单地说,它是一个允许您在多列上执行函数的函数。在这种情况下,我想按 Volum_OD
执行除法。~
是一种创建匿名函数的 tidyverse
方式。 ~ . / Volum_OD
相当于 function(x) x / Volumn_OD
all_of
是必要的,因为在这种特定情况下,我为 across
提供了一个字符向量。没有它,它无论如何都可以工作,但您会收到警告,因为它不明确,并且在相同情况下可能无法正常工作。查看 this book 以了解有关使用 tidyverse
(dplyr
是其中的一部分)进行数据操作的更多信息。
rel.Volume_unmod <- Volume
# rename columns
cols <- c("Volume_OD","Volume_Imp","Volume_OD_1","Volume_WS_1","Volume_OD_2","Volume_WS_2","Volume_OD_3","Volume_WS_3")
colnames(rel.Volume_unmod)[3:10] <- cols
# divide by columns 3
rel.Volume_unmod[3:10] <- lapply(rel.Volume_unmod[3:10], `/`, rel.Volume_unmod[3])
rel.Volume_unmod
lapply
是一个基本的 R 函数,它允许您将函数应用于列表或“可列出”对象的每个项目。rel.Volume_unmod
是一个可列出的对象:数据帧只是一个长度相同的向量列表。因此,lapply
每次取一列 [= 一项] 并应用一个函数。/
。您通常会看到 /
像这样使用:A / B
,但实际上 /
是一个原始函数。你可以用这种方式写同样的东西: `/`(A, B) # same as A / B
lapply
提供附加参数,这些参数直接传递给应用于列表的函数(在本例中为 /
)。因此,我们将 rel.Volume_unmod[3]
作为附加参数编写。lapply
总是返回一个列表。但是,由于我们将 lapply 的结果分配给“数据帧的一部分”,我们将只编辑数据帧的列,因此,我们将拥有一个数据帧而不是列表。让我用更技术的方式重新表述。当您分配 rel.Volume_unmod[3:10] <- lapply(...)
时,您不仅仅是将列表分配给 rel.Volume_unmod[3:10]
。您在技术上正在使用此分配函数:[<-
。这是一个允许编辑列表/矢量/数据框中的项目的功能。具体来说,[<-
允许您在不修改列表/向量/数据框的属性的情况下分配新项目。正如我之前所说,数据框只是具有特定属性的列表。然后,当您使用 [<-
时,您修改了列,但保持属性(在本例中为类 data.frame)保持不变。这就是魔法起作用的原因。答案 1 :(得分:0)
如果没有最小的工作示例,很难猜测变量 Volume
实际指的是什么。除此之外,您的 for
循环似乎有问题:
for(i in Volume[,3:10]){
假设 Volume
指的是 data.frame
或 tibble
,这会导致索引在 3 到 10 之间的实际列向量连续分配给 i
。您可以通过将 print(i)
放入循环中来验证这一点。但在循环内部,您似乎实际上想使用 i
作为变量,仅包含当前列的索引作为数字(而不是列本身):
rel.Volume[i] = tibble(Volume = Volume[[i]] / Volume[[3]])
此外,两个括号通常用于列表,而不是 data.frames
或 tibbles
。 (但是,您可以这样做,因为 data.frames
是列表的特殊情况。)
最后但并非最不重要的一点是,在尝试重新分配给该变量时,使用 rel.Volume
初始化变量 NULL
将导致错误,因为您还没有告诉 R
,rel.Volume
{1}} 应该是。
试试这个,如果你喜欢(感谢@Edo 提供示例数据):
set.seed(1)
Volume <- data.frame(ID = sample(letters, 30, TRUE),
GR = sample(LETTERS, 30, TRUE),
Vol1 = rnorm(30),
Vol2 = rnorm(30),
Vol3 = rnorm(30))
rel.Volume <- Volume[1:2] # Assuming you want to keep the IDs.
# Your data.frame will need to have the correct number of rows here already.
for (i in 3:ncol(Volume)){ # ncol gives the total number of columns in data.frame
rel.Volume[i] = Volume[i]/Volume[3]
}
更像 R
的方法是完全避免使用 for
循环,因为 R
的强度是隐式矢量化。这些表达式将在没有循环的情况下产生相同的结果:
# OK, this one messes up variable names...
rel.V.2 <- data.frame(sapply(X = Volume[3:5], FUN = function(x) x/Volume[3]))
rel.V.3 <- data.frame(Map(`/`, Volume[3:5], Volume[3]))
既然您说您是 R
的新手,坦率地说,我建议您在学习基础知识时避免使用 Tidyverse 软件包。根据我的经验,从长远来看,您最好先学习 base-R
并在您更熟悉核心语言时添加“糖”。以后你仍然可以学习使用 Tidyverse 函数(但是,为什么会有人呢?;-))。