Существует фрейм данных raw_df, как показано ниже:
library(tidyverse)
detail <- data.frame(cat = c("a","a","a","b","b","b","b","c","c"),
single_amount = c(1,3,7,2,1,4,6,1,6))
total <- data.frame(cat = c("a","b","c"),
total_amount = c(20,10,9))
raw_df <- detail %>% left_join(total, by = 'cat')
Я определил функцию self allocate_data_m для выделения total_amount, когда cumsum(single_data) меньше total_amount
allocate_data_m <- function(data, single_data, total_data) {
out <- cumsum_single_data <- rep('NA', nrow(data))
for (grouprow in seq_len(nrow(data))) {
cumsum_single_data[grouprow] <-
if_else(grouprow == 1, data[grouprow, single_data],
cumsum_single_data[grouprow-1] + data[grouprow, single_data])
out[grouprow] <- if_else(cumsum_single_data[grouprow] < data[grouprow, total_data], data[grouprow, single_data], 0)
}
out
}
при запуске allocate_data_m в mutate возникает ошибка. Кто-нибудь может помочь? Спасибо!
raw_df %>%
group_by(cat) %>%
mutate(amount_x_all = allocate_data_m(cur_data(), single_amount, total_amount))
Желаемый результат показан ниже, мне просто интересно, почему функция allocate_data_m не может работать.
raw_df %>%
group_by(cat) %>%
mutate(amount_x_all = if_else(cumsum(single_amount) < total_amount, single_amount, 0))
Вы пытаетесь ссылаться на несуществующие столбцы ваших данных. Ошибки находятся в вашем первом утверждении if_else.
@Эдвард Спасибо. В изменяемой переменной single_amount совпадает с Single_data, который находится в функции. Мне интересно, как возникает ошибка и как ее исправить?
@Limey Спасибо, я отредактировал сообщение и добавил желаемый результат.





Минимальная доработка вашей функции:
"NA" на NA. Первое представляет собой буквальную строку символов, а второе относится к отсутствующему значению в R.ifelse() на if (...) {...} else {...}. В противном случае cumsum_single_data[grouprow-1] выдаст ошибку, когда grouprow равно 1.ifelse() за пределы цикла for, поскольку его можно вычислить векторно.allocate_data_m <- function(single_data, total_data) {
cumsum_single_data <- rep(NA, length(single_data))
for (grouprow in seq_len(length(single_data))) {
cumsum_single_data[grouprow] <- if (grouprow == 1) {
single_data[grouprow]
} else {
cumsum_single_data[grouprow-1] + single_data[grouprow]
}
}
out <- ifelse(cumsum_single_data < total_data, single_data, 0)
out
}
raw_df %>%
group_by(cat) %>%
mutate(amount_x_all = allocate_data_m(single_amount, total_amount)) %>%
ungroup()
# # A tibble: 9 × 4
# cat single_amount total_amount amount_x_all
# <chr> <dbl> <dbl> <dbl>
# 1 a 1 20 1
# 2 a 3 20 3
# 3 a 7 20 7
# 4 b 2 10 2
# 5 b 1 10 1
# 6 b 4 10 4
# 7 b 6 10 0
# 8 c 1 9 1
# 9 c 6 9 6
Используйте имена столбцов вместо векторов-столбцов. В этом случае вы должны использовать имена столбцов в двойных кавычках при вызове allocate_data_m() внутри mutate().
allocate_data_m <- function(data, single_data, total_data) {
if (is(data, "tbl")) data <- as.data.frame(data)
cumsum_single_data <- rep(NA, nrow(data))
for (grouprow in seq_len(nrow(data))) {
cumsum_single_data[grouprow] <- if (grouprow == 1) {
data[grouprow, single_data]
} else {
cumsum_single_data[grouprow-1] + data[grouprow, single_data]
}
}
out <- ifelse(cumsum_single_data < data[, total_data], data[, single_data], 0)
out
}
raw_df %>%
group_by(cat) %>%
mutate(amount_x_all = allocate_data_m(cur_data(), "single_amount", "total_amount")) %>%
ungroup()
Спасибо, это здорово! в вашем коде «single_data» и «total_data» являются векторными? В моем коде строка для имен переменных, я не знаю, почему она не работает.
@anderwyang, см. мою обновленную версию 2. В этом случае при вызове allocate_data_m() вам нужно использовать имена столбцов, заключенные в двойные кавычки.
, спасибо за ваши две версии, очень полезно!
Каков ваш ожидаемый результат на основе ваших тестовых данных?