Ja Mah
Ja Mah

Reputation: 29

creating a function using for loop then mutate a new column using the created function

I have a data frame, dt, 

    id    trial period  nature  decision
1   4119369 1   1   17  10
2   4119369 1   2   17  10
3   4119369 1   3   17  10
4   4119369 1   4   17  0
5   4119369 1   5   17  0
6   4119369 2   1   6   8
7   4119369 2   2   6   9
8   4119369 2   3   6   6
9   4119369 2   4   6   13
10  4119369 2   5   6   13
11  4119369 3   1   14  1
12  4119369 3   2   14  2
13  4119369 3   3   14  6
14  4119369 3   4   14  10
15  4119369 3   5   14  18
16  4119356 1   1   17  4
17  4119356 1   2   17  8
18  4119356 1   3   17  12
19  4119356 1   4   17  16
20  4119356 1   5   17  18
21  4119356 2   1   6   4
22  4119356 2   2   6   12
23  4119356 2   3   6   8
24  4119356 2   4   6   6
25  4119356 2   5   6   7
26  4119356 3   1   14  5
27  4119356 3   2   14  10
28  4119356 3   3   14  15
29  4119356 3   4   14  12
30  4119356 3   5   14  13

I want to use for loop function to count the correct decision override of each id in each period of a trial. There are 5 periods in a trial and decision is between 1 and 20. The nature of each trial doesnt change. The decision rule is if decision of period 1 < nature, then decision should be between 10 and 20 for the rest of the trial. And if decision of period 1 > nature, then decision should be between 1 and 14 for the rest of the trial. The function I created is

correct_override = function(period = 1:5, decision, nature){
  correct=0;
  if(decision[period==1]<=nature){
  for (p in period){
    d = decision[p]
    correct = correct + (d >= 10 & d <= 20) 
  }}else if (decision[period==1]>nature){
    for (p in period){
    d = decision[p]
    correct = correct + (d >= 1 & d <= 14)
  }
  } else{
    correct=0
  }
  return(correct)
  
} 

Then I use the function in the dt

trial_dt = group_by(dt, id, trial) %>%
  mutate(correct_or =
              correct_override(
                period = period,
                decision = decision,
                nature = nature))

So as you can see, I created a function called correct_override but it doesnt do the work as I get a warming "the condition has length > 1 and only the first element will be used"

Upvotes: 0

Views: 48

Answers (1)

Marcelo Avila
Marcelo Avila

Reputation: 2374

It is important to note that the warning is just a warning, it is not an error so the output could still be correct.

In this case, the warning arises because if() expects a logical vector of length 1, as in the help description:

A length-one logical vector that is not NA. Conditions of length greater than one are currently accepted with a warning, but only the first element is used.

To suppress the warning you can make sure the condition will always be of length 1:

Option 1: use period == 1 to slice nature as well.

...
    if (decision[period==1]<=nature[period==1]) {
...

Option 2: explicitly take the first element of the condition:

...
    if ( (decision[period==1]<=nature)[1] ) {
...

If the logic within the function is otherwise correct, it should be fine. If not, please update your question with the desired output.

Data

library(dplyr)

dt <- tribble(
  ~id, ~trial, ~period, ~nature,  ~decision, 
  4119369, 1, 1, 17, 10,
  4119369, 1, 2, 17, 10,
  4119369, 1, 3, 17, 10,
  4119369, 1, 4, 17, 0,
  4119369, 1, 5, 17, 0,
  4119369, 2, 1, 6,  8,
  4119369, 2, 2, 6,  9,
  4119369, 2, 3, 6,  6,
  4119369, 2, 4, 6,  13,
  4119369, 2, 5, 6,  13,
  4119369, 3, 1, 14, 1,
  4119369, 3, 2, 14, 2,
  4119369, 3, 3, 14, 6,
  4119369, 3, 4, 14, 10,
  4119369, 3, 5, 14, 18,
  4119356, 1, 1, 17, 4,
  4119356, 1, 2, 17, 8,
  4119356, 1, 3, 17, 12,
  4119356, 1, 4, 17, 16,
  4119356, 1, 5, 17, 18,
  4119356, 2, 1, 6,  4,
  4119356, 2, 2, 6,  12,
  4119356, 2, 3, 6,  8,
  4119356, 2, 4, 6,  6,
  4119356, 2, 5, 6,  7,
  4119356, 3, 1, 14, 5,
  4119356, 3, 2, 14, 10,
  4119356, 3, 3, 14, 15,
  4119356, 3, 4, 14, 12,
  4119356, 3, 5, 14, 13)

Function



correct_override = function(period = 1:5, decision, nature) {
  correct = 0 
  if (decision[period==1]<=nature[period==1]) {
    for (p in period){
      d = decision[p]
      correct = correct + (d >= 10 & d <= 20) 
    } 
  } else if (  decision[period==1]>nature[period==1]) {
    for (p in period){
      d = decision[p]
      correct = correct + (d >= 1 & d <= 14)
    }
  } else {
    correct = 0
  }
  return(correct)
}

Results

dt %>% 
  group_by(id, trial) %>%
  mutate(correct_or =
           correct_override(
             period = period,
             decision = decision,
             nature = nature))
#> # A tibble: 30 x 6
#> # Groups:   id, trial [6]
#>         id trial period nature decision correct_or
#>      <dbl> <dbl>  <dbl>  <dbl>    <dbl>      <dbl>
#>  1 4119369     1      1     17       10          3
#>  2 4119369     1      2     17       10          3
#>  3 4119369     1      3     17       10          3
#>  4 4119369     1      4     17        0          3
#>  5 4119369     1      5     17        0          3
#>  6 4119369     2      1      6        8          5
#>  7 4119369     2      2      6        9          5
#>  8 4119369     2      3      6        6          5
#>  9 4119369     2      4      6       13          5
#> 10 4119369     2      5      6       13          5
#> # … with 20 more rows

Created on 2021-07-11 by the reprex package (v2.0.0)

Upvotes: 1

Related Questions