Here's a tidyverse option, where I put into long form, then filter to keep only the values with 4 and only the first and last occurrence. Then, I create a new column to denote whether it is the first or last value, then pivot back to the wide format.
library(tidyverse)
df %>%
pivot_longer(-ID) %>%
group_by(ID) %>%
filter(value == 4) %>%
filter(row_number()==1 | row_number()==n()) %>%
mutate(col = c("First", "Last")) %>%
pivot_wider(names_from = "col", values_from = "name") %>%
select(-value)
Output
<int> <chr> <chr>
1 1 WZ_2 WZ_3
2 2 WZ_1 WZ_2
3 3 WZ_1 WZ_4
Data
df <- structure(list(ID = 1:3, WZ_1 = c(5L, 4L, 4L), WZ_2 = c(4L, 4L,
4L), WZ_3 = c(4L, 3L, 4L), WZ_4 = c(3L, 3L, 4L)), class = "data.frame", row.names = c(NA,
-3L))