Here's another approach that uses rowwise()
, like @nirgrahamuk's solution, but with list columns:
library(tidyverse)
set.seed(123)
datos <- data.frame(idi = 1:9, Gr = rep(letters[1:3], each = 3),
X = rpois(9,5), stringsAsFactors = F)
datos$X[datos$X==8] <- NA
# step 1: add group-related columns
datos |>
group_by(Gr) |>
mutate(
# create a list column with vector of group members
class = list(X),
# add an in-group id column
id_in_group = row_number()
) |>
ungroup() |>
# convert to row-based table for later row-based calculations
rowwise() |>
# convert class values to strings, for ease of viewing results
mutate(
class_txt =
# use -1 to encode NA as string
list(if_else(class |> is.na(), -1, class)),
class_txt =
# coerce class vector to character
class_txt |> str_flatten(collapse = ', ')
) -> datos_temp
datos_temp
#> # A tibble: 9 × 6
#> # Rowwise:
#> idi Gr X class id_in_group class_txt
#> <int> <chr> <int> <list> <int> <chr>
#> 1 1 a 4 <int [3]> 1 4, 7, 4
#> 2 2 a 7 <int [3]> 2 4, 7, 4
#> 3 3 a 4 <int [3]> 3 4, 7, 4
#> 4 4 b NA <int [3]> 1 -1, 9, 2
#> 5 5 b 9 <int [3]> 2 -1, 9, 2
#> 6 6 b 2 <int [3]> 3 -1, 9, 2
#> 7 7 c 5 <int [3]> 1 5, -1, 5
#> 8 8 c NA <int [3]> 2 5, -1, 5
#> 9 9 c 5 <int [3]> 3 5, -1, 5
# step 2: exclude individual from group
datos_temp |>
# remove individual from group vector
mutate(
rest = list(class[-id_in_group])
) |>
# convert class values to strings, for ease of viewing results
mutate(
rest_txt =
# use -1 to encode NA as string
list(if_else(rest |> is.na(), -1, rest)),
rest_txt =
# coerce class vector to character
rest_txt |> str_flatten(collapse = ', ')
) -> datos_temp
datos_temp
#> # A tibble: 9 × 8
#> # Rowwise:
#> idi Gr X class id_in_group class_txt rest rest_txt
#> <int> <chr> <int> <list> <int> <chr> <list> <chr>
#> 1 1 a 4 <int [3]> 1 4, 7, 4 <int [2]> 7, 4
#> 2 2 a 7 <int [3]> 2 4, 7, 4 <int [2]> 4, 4
#> 3 3 a 4 <int [3]> 3 4, 7, 4 <int [2]> 4, 7
#> 4 4 b NA <int [3]> 1 -1, 9, 2 <int [2]> 9, 2
#> 5 5 b 9 <int [3]> 2 -1, 9, 2 <int [2]> -1, 2
#> 6 6 b 2 <int [3]> 3 -1, 9, 2 <int [2]> -1, 9
#> 7 7 c 5 <int [3]> 1 5, -1, 5 <int [2]> -1, 5
#> 8 8 c NA <int [3]> 2 5, -1, 5 <int [2]> 5, 5
#> 9 9 c 5 <int [3]> 3 5, -1, 5 <int [2]> 5, -1
# step 3: calculate average of rest
datos_temp |>
# calculate mean of rest
mutate(avg_rest = list(mean(rest, na.rm = T))) |>
# remove unneeded columns
select(!(class:rest)) -> datos_temp
datos_temp
#> # A tibble: 9 × 5
#> # Rowwise:
#> idi Gr X rest_txt avg_rest
#> <int> <chr> <int> <chr> <list>
#> 1 1 a 4 7, 4 <dbl [1]>
#> 2 2 a 7 4, 4 <dbl [1]>
#> 3 3 a 4 4, 7 <dbl [1]>
#> 4 4 b NA 9, 2 <dbl [1]>
#> 5 5 b 9 -1, 2 <dbl [1]>
#> 6 6 b 2 -1, 9 <dbl [1]>
#> 7 7 c 5 -1, 5 <dbl [1]>
#> 8 8 c NA 5, 5 <dbl [1]>
#> 9 9 c 5 5, -1 <dbl [1]>
# extract value of avg_rest
datos_temp |>
# since each avg_rest value is a single number, can use unnest to extract
unnest(avg_rest)
#> # A tibble: 9 × 5
#> idi Gr X rest_txt avg_rest
#> <int> <chr> <int> <chr> <dbl>
#> 1 1 a 4 7, 4 5.5
#> 2 2 a 7 4, 4 4
#> 3 3 a 4 4, 7 5.5
#> 4 4 b NA 9, 2 5.5
#> 5 5 b 9 -1, 2 2
#> 6 6 b 2 -1, 9 9
#> 7 7 c 5 -1, 5 5
#> 8 8 c NA 5, 5 5
#> 9 9 c 5 5, -1 5
All together from the beginning:
datos |>
group_by(Gr) |>
mutate(
# create a list column with vector of group members
class = list(X),
# add an in-group id column
id_in_Gr = row_number()
) |>
ungroup() |>
# convert to row-based table for later row-based calculations
rowwise() |>
# remove individual from group vector
mutate(rest = list(class[-id_in_Gr])) |>
# calculate mean of rest
mutate(avg_rest = list(mean(rest, na.rm = T))) |>
# remove unneeded columns
select(!(class:rest)) |>
# since each avg_rest value is a single number, can use unnest to extract
unnest(avg_rest)
#> # A tibble: 9 × 4
#> idi Gr X avg_rest
#> <int> <chr> <int> <dbl>
#> 1 1 a 4 5.5
#> 2 2 a 7 4
#> 3 3 a 4 5.5
#> 4 4 b NA 5.5
#> 5 5 b 9 2
#> 6 6 b 2 9
#> 7 7 c 5 5
#> 8 8 c NA 5
#> 9 9 c 5 5
Created on 2024-04-05 with reprex v2.0.2
full reprex (click here to open)
library(tidyverse)
set.seed(123)
datos <- data.frame(idi = 1:9, Gr = rep(letters[1:3], each = 3),
X = rpois(9,5), stringsAsFactors = F)
datos$X[datos$X==8] <- NA
# step 1: add group-related columns
datos |>
group_by(Gr) |>
mutate(
# create a list column with vector of group members
class = list(X),
# add an in-group id column
id_in_group = row_number()
) |>
ungroup() |>
# convert to row-based table for later row-based calculations
rowwise() |>
# convert class values to strings, for ease of viewing results
mutate(
class_txt =
# use -1 to encode NA as string
list(if_else(class |> is.na(), -1, class)),
class_txt =
# coerce class vector to character
class_txt |> str_flatten(collapse = ', ')
) -> datos_temp
datos_temp
#> # A tibble: 9 × 6
#> # Rowwise:
#> idi Gr X class id_in_group class_txt
#> <int> <chr> <int> <list> <int> <chr>
#> 1 1 a 4 <int [3]> 1 4, 7, 4
#> 2 2 a 7 <int [3]> 2 4, 7, 4
#> 3 3 a 4 <int [3]> 3 4, 7, 4
#> 4 4 b NA <int [3]> 1 -1, 9, 2
#> 5 5 b 9 <int [3]> 2 -1, 9, 2
#> 6 6 b 2 <int [3]> 3 -1, 9, 2
#> 7 7 c 5 <int [3]> 1 5, -1, 5
#> 8 8 c NA <int [3]> 2 5, -1, 5
#> 9 9 c 5 <int [3]> 3 5, -1, 5
# step 2: exclude individual from group
datos_temp |>
# remove individual from group vector
mutate(
rest = list(class[-id_in_group])
) |>
# convert class values to strings, for ease of viewing results
mutate(
rest_txt =
# use -1 to encode NA as string
list(if_else(rest |> is.na(), -1, rest)),
rest_txt =
# coerce class vector to character
rest_txt |> str_flatten(collapse = ', ')
) -> datos_temp
datos_temp
#> # A tibble: 9 × 8
#> # Rowwise:
#> idi Gr X class id_in_group class_txt rest rest_txt
#> <int> <chr> <int> <list> <int> <chr> <list> <chr>
#> 1 1 a 4 <int [3]> 1 4, 7, 4 <int [2]> 7, 4
#> 2 2 a 7 <int [3]> 2 4, 7, 4 <int [2]> 4, 4
#> 3 3 a 4 <int [3]> 3 4, 7, 4 <int [2]> 4, 7
#> 4 4 b NA <int [3]> 1 -1, 9, 2 <int [2]> 9, 2
#> 5 5 b 9 <int [3]> 2 -1, 9, 2 <int [2]> -1, 2
#> 6 6 b 2 <int [3]> 3 -1, 9, 2 <int [2]> -1, 9
#> 7 7 c 5 <int [3]> 1 5, -1, 5 <int [2]> -1, 5
#> 8 8 c NA <int [3]> 2 5, -1, 5 <int [2]> 5, 5
#> 9 9 c 5 <int [3]> 3 5, -1, 5 <int [2]> 5, -1
# step 3: calculate average of rest
datos_temp |>
# calculate mean of rest
mutate(avg_rest = list(mean(rest, na.rm = T))) |>
# remove unneeded columns
select(!(class:rest)) -> datos_temp
datos_temp
#> # A tibble: 9 × 5
#> # Rowwise:
#> idi Gr X rest_txt avg_rest
#> <int> <chr> <int> <chr> <list>
#> 1 1 a 4 7, 4 <dbl [1]>
#> 2 2 a 7 4, 4 <dbl [1]>
#> 3 3 a 4 4, 7 <dbl [1]>
#> 4 4 b NA 9, 2 <dbl [1]>
#> 5 5 b 9 -1, 2 <dbl [1]>
#> 6 6 b 2 -1, 9 <dbl [1]>
#> 7 7 c 5 -1, 5 <dbl [1]>
#> 8 8 c NA 5, 5 <dbl [1]>
#> 9 9 c 5 5, -1 <dbl [1]>
# extract value of avg_rest
datos_temp |>
# since each avg_rest value is a single number, can use unnest to extract
unnest(avg_rest)
#> # A tibble: 9 × 5
#> idi Gr X rest_txt avg_rest
#> <int> <chr> <int> <chr> <dbl>
#> 1 1 a 4 7, 4 5.5
#> 2 2 a 7 4, 4 4
#> 3 3 a 4 4, 7 5.5
#> 4 4 b NA 9, 2 5.5
#> 5 5 b 9 -1, 2 2
#> 6 6 b 2 -1, 9 9
#> 7 7 c 5 -1, 5 5
#> 8 8 c NA 5, 5 5
#> 9 9 c 5 5, -1 5
# all together from the beginning
datos |>
group_by(Gr) |>
mutate(
# create a list column with vector of group members
class = list(X),
# add an in-group id column
id_in_Gr = row_number()
) |>
ungroup() |>
# convert to row-based table for later row-based calculations
rowwise() |>
# remove individual from group vector
mutate(rest = list(class[-id_in_Gr])) |>
# calculate mean of rest
mutate(avg_rest = list(mean(rest, na.rm = T))) |>
# remove unneeded columns
select(!(class:rest)) |>
# since each avg_rest value is a single number, can use unnest to extract
unnest(avg_rest)
#> # A tibble: 9 × 4
#> idi Gr X avg_rest
#> <int> <chr> <int> <dbl>
#> 1 1 a 4 5.5
#> 2 2 a 7 4
#> 3 3 a 4 5.5
#> 4 4 b NA 5.5
#> 5 5 b 9 2
#> 6 6 b 2 9
#> 7 7 c 5 5
#> 8 8 c NA 5
#> 9 9 c 5 5
Created on 2024-04-05 with reprex v2.0.2