简体   繁体   中英

How do I add a vector where I collapse scores from individuals within pairs?

I have done an experiment in which participants have solved a task in pairs, with another participant. Each participant has then received a score for how well they did the task. Pairs have gone through different amounts of trials.

I have a data frame similar to the one below:

participant <- c(1,1,2,2,3,3,3,4,4,4,5,6)
pair <- c(1,1,1,1,2,2,2,2,2,2,3,3)
trial <- c(1,2,1,2,1,2,3,1,2,3,1,1)
score <- c(2,3,6,3,4,7,3,1,8,5,4,3)
data <- data.frame(participant, pair, trial, score)

participant pair trial score
        1    1     1     2
        1    1     2     3
        2    1     1     6
        2    1     2     3
        3    2     1     4
        3    2     2     7
        3    2     3     3
        4    2     1     1
        4    2     2     8
        4    2     3     5
        5    3     1     4
        6    3     1     3

I would like to add a new vector to the data frame, where each participant gets the numeric difference between their own score and the other participant's score within each trial.

Does someone have an idea about how one might do that?

It should end up looking something like this:

participant pair trial score difference
    1        1     1     2       4
    1        1     2     3       0
    2        1     1     6       4
    2        1     2     3       0
    3        2     1     4       3
    3        2     2     7       1
    3        2     3     3       2
    4        2     1     1       3
    4        2     2     8       1
    4        2     3     5       2
    5        3     1     4       1
    6        3     1     3       1

Here's a solution that involves first reordering data such that each sequential pair of rows corresponds to a single pair within a single trial. This allows us to make a single call to diff() to extract the differences:

data <- data[order(data$trial,data$pair,data$participant),];
data$diff <- rep(diff(data$score)[c(T,F)],each=2L)*c(-1L,1L);
data;
##    participant pair trial score diff
## 1            1    1     1     2   -4
## 3            2    1     1     6    4
## 5            3    2     1     4    3
## 8            4    2     1     1   -3
## 11           5    3     1     4    1
## 12           6    3     1     3   -1
## 2            1    1     2     3    0
## 4            2    1     2     3    0
## 6            3    2     2     7   -1
## 9            4    2     2     8    1
## 7            3    2     3     3   -2
## 10           4    2     3     5    2

I assumed you wanted the sign to capture the direction of the difference. So, for instance, if a participant has a score 4 points below the other participant in the same trial-pair, then I assumed you would want -4. If you want all-positive values, you can remove the multiplication by c(-1L,1L) and add a call to abs() :

data$diff <- rep(abs(diff(data$score)[c(T,F)]),each=2L);
data;
##    participant pair trial score diff
## 1            1    1     1     2    4
## 3            2    1     1     6    4
## 5            3    2     1     4    3
## 8            4    2     1     1    3
## 11           5    3     1     4    1
## 12           6    3     1     3    1
## 2            1    1     2     3    0
## 4            2    1     2     3    0
## 6            3    2     2     7    1
## 9            4    2     2     8    1
## 7            3    2     3     3    2
## 10           4    2     3     5    2

Here's a solution built around ave() that doesn't require reordering the whole data.frame first:

data$diff <- ave(data$score,data$trial,data$pair,FUN=function(x) abs(diff(x)));
data;
##    participant pair trial score diff
## 1            1    1     1     2    4
## 2            1    1     2     3    0
## 3            2    1     1     6    4
## 4            2    1     2     3    0
## 5            3    2     1     4    3
## 6            3    2     2     7    1
## 7            3    2     3     3    2
## 8            4    2     1     1    3
## 9            4    2     2     8    1
## 10           4    2     3     5    2
## 11           5    3     1     4    1
## 12           6    3     1     3    1

Here's how you can get the score of the other participant in the same trial-pair:

data$other <- ave(data$score,data$trial,data$pair,FUN=rev);
data;
##    participant pair trial score other
## 1            1    1     1     2     6
## 2            1    1     2     3     3
## 3            2    1     1     6     2
## 4            2    1     2     3     3
## 5            3    2     1     4     1
## 6            3    2     2     7     8
## 7            3    2     3     3     5
## 8            4    2     1     1     4
## 9            4    2     2     8     7
## 10           4    2     3     5     3
## 11           5    3     1     4     3
## 12           6    3     1     3     4

Or, assuming the data.frame has been reordered as per the initial solution:

data$other <- c(rbind(data$score[c(F,T)],data$score[c(T,F)]));
data;
##    participant pair trial score other
## 1            1    1     1     2     6
## 3            2    1     1     6     2
## 5            3    2     1     4     1
## 8            4    2     1     1     4
## 11           5    3     1     4     3
## 12           6    3     1     3     4
## 2            1    1     2     3     3
## 4            2    1     2     3     3
## 6            3    2     2     7     8
## 9            4    2     2     8     7
## 7            3    2     3     3     5
## 10           4    2     3     5     3

Alternative, using matrix() instead of rbind() :

data$other <- c(matrix(data$score,2L)[2:1,]);
data;
##    participant pair trial score other
## 1            1    1     1     2     6
## 3            2    1     1     6     2
## 5            3    2     1     4     1
## 8            4    2     1     1     4
## 11           5    3     1     4     3
## 12           6    3     1     3     4
## 2            1    1     2     3     3
## 4            2    1     2     3     3
## 6            3    2     2     7     8
## 9            4    2     2     8     7
## 7            3    2     3     3     5
## 10           4    2     3     5     3

Here is an option using data.table :

library(data.table)
setDT(data)[,difference := abs(diff(score)), by = .(pair, trial)]
data
#    participant pair trial score difference
# 1:           1    1     1     2          4
# 2:           1    1     2     3          0
# 3:           2    1     1     6          4
# 4:           2    1     2     3          0
# 5:           3    2     1     4          3
# 6:           3    2     2     7          1
# 7:           3    2     3     3          2
# 8:           4    2     1     1          3
# 9:           4    2     2     8          1
#10:           4    2     3     5          2
#11:           5    3     1     4          1
#12:           6    3     1     3          1

A slightly faster option would be:

setDT(data)[, difference := abs((score - shift(score))[2]) , by = .(pair, trial)]

If we need the value of the other pair:

data[, other:= rev(score) , by = .(pair, trial)]
data
#    participant pair trial score difference other
# 1:           1    1     1     2          4     6
# 2:           1    1     2     3          0     3
# 3:           2    1     1     6          4     2
# 4:           2    1     2     3          0     3
# 5:           3    2     1     4          3     1
# 6:           3    2     2     7          1     8
# 7:           3    2     3     3          2     5
# 8:           4    2     1     1          3     4
# 9:           4    2     2     8          1     7
#10:           4    2     3     5          2     3
#11:           5    3     1     4          1     3
#12:           6    3     1     3          1     4

Or using dplyr :

library(dplyr)
data %>%
    group_by(pair, trial) %>% 
    mutate(difference = abs(diff(score)))
#   participant  pair trial score difference
#         <dbl> <dbl> <dbl> <dbl>      <dbl>
#1            1     1     1     2          4
#2            1     1     2     3          0
#3            2     1     1     6          4
#4            2     1     2     3          0
#5            3     2     1     4          3
#6            3     2     2     7          1
#7            3     2     3     3          2
#8            4     2     1     1          3
#9            4     2     2     8          1
#10           4     2     3     5          2
#11           5     3     1     4          1
#12           6     3     1     3          1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM