每组使用一个特定值,组中使用其他每个值

时间:2019-01-04 14:33:38

标签: r for-loop if-statement

我有一个关于R的特定编程问题。 我想在整个数据集上应用自定义函数,但是该函数中的值与其所属的组相比应该有所变化。这是一个与我正在使用的数据集相似的数据集

set.seed(123)
df <- data.frame(group = c(rep("one", 10), rep("two", 9), rep("three", 11)),
         slot = c(1:10, 1:9, 1:11),
         x = sample(100, 30))

和功能

RI_fun <- function(x, y) {
((x - y)/ y) * 100
}

实际数据集较大,但结构相同。关于真实数据集的一些信息:这是一个样本(组)上的一系列测量值(插槽),我希望自定义函数(RI_fun)中的第一个测量值(插槽== 1)为y

我想创建一个新列作为自定义函数的输出,其中x = df $ x,y是每个组的df $ slot == 1的x值。

我试图进行for循环,但没有成功。我的想法是使y值成为if else语句,在该语句中检查df $ group并在刚刚检查过的slot == 1和group == group处应用df $ x。

这是我的尝试:

for (i in seq_along(df$group)) {
RI[i] = RI_fun(x = df$x[i],
               y = (ifelse(df$group == df$group[i],
                           df$x[df$slot == 1 & df$group == df$group[i]],
                           NA)))

但是输出是:

[1]   0.00000 172.41379  41.37931 196.55172 213.79310 -82.75862  72.41379 186.20690  75.86207  44.82759        NA
[12]        NA        NA        NA        NA        NA        NA        NA        NA        NA        NA        NA
[23]        NA        NA        NA        NA        NA        NA        NA        NA

当我手动检查输出应该是什么时,它表明for循环是正确的,直到[11]都不再起作用。我已经尝试过其他一些与此循环类似的for循环,但这是我最接近所需输出的循环。

您所获得的任何帮助将不胜感激。如果我不够清楚,请询问,我会尽力使其更加清晰。

2 个答案:

答案 0 :(得分:1)

很好的问题,并且格式很好,带有可重现的示例!恭喜!

在R中,通常不需要使用循环。 R本质上是向量化的,因此我们可以用向量表达自己。转到data.frames的想法是相同的,并添加了包dplyr,我们获得了一些简单的功能。

首先,我演示您想要的内容:

library(dplyr)
df %>% group_by(group) %>%
  mutate(y=x[slot==1])
as.data.frame(.Last.value)
   group slot  x  y
1    one    1 30 30
2    one    2 72 30
3    one    3 88 30
4    one    4  5 30
5    one    5 55 30
6    one    6 42 30
7    one    7 11 30
8    one    8 53 30
9    one    9 73 30
10   one   10 87 30
11   two    1 52 52
12   two    2 82 52
13   two    3 78 52
14   two    4 59 52
15   two    5 12 52
16   two    6 95 52
17   two    7  1 52
18   two    8 70 52
19   two    9 66 52
20 three    1 69 69
21 three    2 79 69
22 three    3 80 69
23 three    4 21 69
24 three    5 94 69
25 three    6 75 69
26 three    7 25 69
27 three    8 15 69
28 three    9 74 69
29 three   10 31 69
30 three   11 43 69

因此,我们可以确认我们获得了正确的xy值。尝试删除行group_by,看看会发生什么。

对我们获得相关的xy值感到满意,请插入您的函数:

df %>% group_by(group) %>%
  mutate(RI=RI_fun(x, x[slot==1]))

如果您确实尝试删除了group_by行,则会出现错误。这是因为mutate要使用一个值,整个矢量(列)使用1或该列中每个元素使用一个值。那么,如果每个组有多个插槽== 1,会发生什么情况?好吧,您必须决定如何处理偏离您需求的情况。

编辑:

for循环无法按预期运行的原因是由于y处的ifelse。只需替换为

for (i in seq_along(df$group)) {
RI[i] = RI_fun(x = df$x[i],
               y = df$x[df$slot == 1 & df$group == df$group[i]])
}

它应该可以正常工作。

这是由于ifelse是矢量化的;对于test(第一个)参数(df$group == df$group[i])中的每个元素,它将在yes(第二个)或no(第三个)元素中返回相应的元素。

答案 1 :(得分:0)

问题出在ifelse语句上。当您调用ifelse(df $ group == df $ group [i] ...)时,只要df $ group [i]!= df $ group [1],它就会返回false。它返回第一个比较的结果。据我所知,您不需要ifelse。以下代码对我有用(尽管您应该进行手动检查以确保它是正确的)。

df <- data.frame(group = c(rep("one", 10), rep("two", 9), rep("three", 11)),
                 slot = c(1:10, 1:9, 1:11),
                 x = sample(100, 30))

RI_fun <- function(x, y) {
  ((x - y)/ y) * 100
}

RI <- rep(NA, 30)

for (i in seq_along(df$group)) {
  RI[i] = RI_fun(x = df$x[i],
                 y = (df$x[df$slot == 1 & df$group == df$group[i]]))
}

RI