У меня есть фрейм данных в R с результатами спортивных матчей. Каждая строка представляет один матч между двумя игроками со столбцами для даты матча, имен игроков и очков каждого игрока.
df <- tibble(
event.date=c('2024-06-15','2024-06-14','2024-06-13'),
home.name=c('A','B','C'),
away.name=c('B','C','C'),
home.score=c(7,7,3),
away.score=c(5,2,7)
)
Я хочу превратить эту «обобщенную» таблицу в таблицу, в которой будет указан общий счет каждого игрока в каждом матче, превратив столбцы home.score и away.score в двоичные ответы. Например, для матча между A и B 15 июня 2024 г. всего должно быть 12 строк: 7 с home.score = 1 и away.score = 0 и 5 с home.score = 0 и away.score. = 1.
В приведенном выше примере итоговая таблица, созданная с помощью df, должна содержать 31 строку — по одной на каждое «очко» в результатах всех матчей.
Я думал, что могу использовать tidyr::uncount(), чтобы увеличить строки моей таблицы на значения home.score и away.score, но аргумент weights принимает в качестве параметра только один столбец — я не могу использовать его одновременно для home.score и away.score.
> uncount(df,weights=home.score)
# A tibble: 17 × 4
event.date home.name away.name away.score
<chr> <chr> <chr> <dbl>
1 2024-06-15 A B 5
2 2024-06-15 A B 5
3 2024-06-15 A B 5
4 2024-06-15 A B 5
5 2024-06-15 A B 5
6 2024-06-15 A B 5
7 2024-06-15 A B 5
8 2024-06-14 B C 2
9 2024-06-14 B C 2
10 2024-06-14 B C 2
11 2024-06-14 B C 2
12 2024-06-14 B C 2
13 2024-06-14 B C 2
14 2024-06-14 B C 2
15 2024-06-13 C C 7
16 2024-06-13 C C 7
17 2024-06-13 C C 7





reframe кажется хорошим кандидатом для этого. Моя первая попытка была:
df |> reframe(
home.score = rep(c(1, 0), c(home.score, away.score)),
away.score = rep(c(0, 1), c(home.score, away.score)),
.by = c(event.date, home.name, away.name)
)
Я считаю, что это хороший и читаемый код. Но, к сожалению, значение home.score уже было изменено, когда мы хотим вычислить away.score, поэтому нам приходится использовать более запутанную версию, в которой мы используем сумму домашнего счета (т. е. сумму вектора 0 и 1):
df |> reframe(
home.score = rep(c(1, 0), c(home.score, away.score)),
away.score = rep(c(0, 1), c(sum(home.score), away.score)),
.by = c(event.date, home.name, away.name)
)
Который дает:
# A tibble: 31 × 5 event.date home.name away.name home.score away.score <chr> <chr> <chr> <dbl> <dbl> 1 2024-06-15 A B 1 0 2 2024-06-15 A B 1 0 3 2024-06-15 A B 1 0 4 2024-06-15 A B 1 0 5 2024-06-15 A B 1 0 6 2024-06-15 A B 1 0 7 2024-06-15 A B 1 0 8 2024-06-15 A B 0 1 9 2024-06-15 A B 0 1 10 2024-06-15 A B 0 1 # ℹ 21 more rows # ℹ Use `print(n = ...)` to see more rows
Еще один вариант (с использованием pivot_*), но не такой эффективный и лаконичный, как решение @Axeman
df %>%
pivot_longer(
cols = c(home.score, away.score),
names_to = "home_away",
values_to = "score"
) %>%
uncount(weights = score, .remove = FALSE) %>%
mutate(id = row_number(), .by = event.date) %>%
pivot_wider(
names_from = home_away,
values_from = score,
values_fill = 0,
values_fn = length
) %>%
select(-id)
который дает
# A tibble: 31 × 5
event.date home.name away.name home.score away.score
<chr> <chr> <chr> <int> <int>
1 2024-06-15 A B 1 0
2 2024-06-15 A B 1 0
3 2024-06-15 A B 1 0
4 2024-06-15 A B 1 0
5 2024-06-15 A B 1 0
6 2024-06-15 A B 1 0
7 2024-06-15 A B 1 0
8 2024-06-15 A B 0 1
9 2024-06-15 A B 0 1
10 2024-06-15 A B 0 1
# ℹ 21 more rows
# ℹ Use `print(n = ...)` to see more rows
Свяжите ряды и uncount() их:
library(dplyr)
library(tidyr)
bind_rows(
df %>% select(event.date,home.name,away.name,count=home.score) %>%
mutate(home.score = 1, away.score = 0),
df %>% select(event.date,home.name,away.name,count=away.score) %>%
mutate(home.score = 0, away.score = 1)
) %>% uncount(count)
Полученные результаты:
## event.date home.name away.name home.score away.score
##1 2024-06-15 A B 1 0
##2 2024-06-15 A B 1 0
##3 2024-06-15 A B 1 0
##4 2024-06-15 A B 1 0
##5 2024-06-15 A B 1 0
##6 2024-06-15 A B 1 0
##7 2024-06-15 A B 1 0
##8 2024-06-14 B C 1 0
##9 2024-06-14 B C 1 0
##10 2024-06-14 B C 1 0
##11 2024-06-14 B C 1 0
##12 2024-06-14 B C 1 0
##13 2024-06-14 B C 1 0
##14 2024-06-14 B C 1 0
##15 2024-06-13 C C 1 0
##16 2024-06-13 C C 1 0
##17 2024-06-13 C C 1 0
##18 2024-06-15 A B 0 1
##19 2024-06-15 A B 0 1
##20 2024-06-15 A B 0 1
##21 2024-06-15 A B 0 1
##22 2024-06-15 A B 0 1
##23 2024-06-14 B C 0 1
##24 2024-06-14 B C 0 1
##25 2024-06-13 C C 0 1
##26 2024-06-13 C C 0 1
##27 2024-06-13 C C 0 1
##28 2024-06-13 C C 0 1
##29 2024-06-13 C C 0 1
##30 2024-06-13 C C 0 1
##31 2024-06-13 C C 0 1