У меня есть такой фрейм данных, и я делаю это на R. Мои проблемы можно разделить на два этапа.
Я хочу создать новую переменную, содержащую список имен столбцов с отрицательным значением для каждого SUBID. Вывод должен выглядеть примерно так:
И затем, на втором этапе, я хотел бы свернуть SUBID в более общий идентификатор и получить количество уникальных строк из выходной переменной для каждого идентификатора (мне просто нужно число, конкретные строки в скобках только для иллюстрацию).
Это два шага, которые, как я думаю, должны быть выполнены, но, возможно, есть способ пропустить первый шаг и сразу перейти ко второму шагу, которого я не знаю. Я был бы признателен за любую помощь, так как сейчас я не уверен, с чего начать. Спасибо!
Это отвечает на первую часть вашего вопроса, вторую я не понял
df$output <-apply(df[,-1], 1, function(x) paste(names(df)[-1][x<0], collapse = ","))
df
SUBID ABC BCD DEF output
1 192838 4 3 -2 DEF
2 193928 -6 -2 6 ABC,BCD
3 205829 4 -5 9 BCD
4 201837 3 4 4
Для второй части попробуйте следующее:
id <- sapply(strsplit(sub("\\W+", "", df$output), split = ""), function(x){
sum(!(duplicated(x) | duplicated(x, fromLast = TRUE)))
} )
data.frame(SUBID = substr(df$SUBID, 1,2), output = id, string = df$output)
SUBID output string
1 19 3 DEF
2 19 2 ABC,BCD
3 20 3 BCD
4 20 0
Я добавил переменную string
, чтобы убедиться, что с вашим количеством уникальных значений все в порядке.
Пожалуйста, добавьте некоторое объяснение того, что делают apply
, collapse
, sapply
.
Другой путь:
library(dplyr)
library(tidyr)
df <- df %>% pivot_longer(-SUBID)
df1 <- df %>%
group_by(SUBID) %>%
summarise(output = paste(name[value < 0L], collapse = ','))
df2 <- df %>%
group_by(SUBID = substr(SUBID, 1, 2)) %>%
summarise(output_count = n_distinct(name[value < 0L]),
output = paste0(output_count, ' (', paste(name[value < 0L], collapse = ','), ')'))
Выходы (во втором случае создаются два столбца, один только со счетом, а другой по вашему примеру):
df1
# A tibble: 4 x 2
SUBID output
<int> <chr>
1 192838 "BCD"
2 193928 "ABC,BCD"
3 201837 ""
4 205829 "BCD"
df2
# A tibble: 2 x 3
SUBID output_count output
<chr> <int> <chr>
1 19 2 2 (BCD,ABC,BCD)
2 20 1 1 (BCD)
Красивый! Я думаю, что OP просто искал счет в финале, а не вектор значений.
Спасибо! Я увидел комментарий сейчас и изменил.
Что делает collapse
? Кстати, ваш ответ намного легче понять, поэтому спасибо за это.
это аргумент функции paste()
и указывает разделитель, который следует использовать при объединении вектора строк в одну строку. См. ?paste
в Rstudio.
Действительно, как объяснил @DanAdams. Вы также можете использовать, например, toString(name[value < 0L])
, но paste
с collapse
дает больше свободы в отношении разделителя.
Один из вариантов — воспользоваться dplyr::cur_data() для доступа к names()
данным и подмножеству на основе ваших критериев. Затем вы можете воспользоваться tibble
list-columns, чтобы сохранить набор имен столбцов произвольной длины и, наконец, вычислить количество уникальных значений в этом списке.
library(tidyverse)
d <- structure(list(SUBID = c(192838, 193928, 205829, 201837), ABC = c(4, -6, 4, 3), BCD = c(-3, -2, -5, 4), DEF = c(2, 6, 9, 4)), row.names = c(NA, -4L), class = "data.frame")
d %>%
rowwise() %>%
mutate(neg_col_names = list(names(cur_data())[cur_data() < 0])) %>%
group_by(ID_grp = str_sub(SUBID, 1, 2)) %>%
summarize(neg_col_count = n_distinct(unlist(c(neg_col_names))))
#> # A tibble: 2 × 2
#> ID_grp neg_col_count
#> <chr> <int>
#> 1 19 2
#> 2 20 1
Created on 2022-11-22 with reprex v2.0.2
Спасибо! Во второй части я хотел свернуть 6-значный subid в 2-значный идентификатор на основе первых двух цифр (19,20), а затем получить количество уникальных строк в выводе, созданном в части 1. , У меня есть опечатка в исходных данных вопроса, так что, возможно, вы запутались.