Возможно, что-то вроде этого:
library(dplyr)
library(tidyr)
df %>%
mutate_at(vars(ColB:ColC), ~replace(., . == '-', 'X')) %>%
pivot_wider(names_from = ColB, values_from = ColC, values_fill = list(ColC = 0))
# ColA X Y
# <fct> <chr> <chr>
#1 A 0 0
#2 B 3 0
#3 C 0 4
#4 D 51 32
данные
df <- structure(list(ColA = structure(c(1L, 2L, 3L, 4L, 4L), .Label = c("A",
"B", "C", "D"), class = "factor"), ColB = structure(c(1L, 2L,
3L, 2L, 3L), .Label = c("-", "X", "Y"), class = "factor"), ColC = c(0L,
3L, 4L, 51L, 32L)), class = "data.frame", row.names = c(NA, -5L))