Оператор If () в R - PullRequest
       3

Оператор If () в R

0 голосов
/ 12 марта 2019

Я не очень опытен в операторах if и циклах в R.

Возможно, вы поможете мне решить мою проблему.

Моя задача - добавить +1 к df $ fz, если сумма (df $ fz) <450, но в то же время мне нужно добавить +1 только к максимальным значениям в df $ fz до того момента, когдакогда сумма (df $ fz) меньше чем 450 </p>

Вот мой df

ID_PP <- c(3,6, 22, 30, 1234456)
z <- c(12325, 21698, 21725, 8378, 18979)
fz <- c(134, 67, 70, 88, 88)

df <- data.frame(ID_PP,z,fz)

После изменения нового столбца df $ new_value он должен выглядеть как 134 68 71 88 89

В данный момент у меня есть этот код, но он добавляет +1 ко всем значениям.

if (sum(df$fz ) < 450) {
  mutate(df, new_value=fz+1)
 }

Я знаю, что могу выбрать top_n (3, z) и добавить +1только к этой вершине, но это не то, что я хочу, потому что в этом случае я должен выбрать вершину вручную после проверки суммы (df $ fz)

Ответы [ 2 ]

1 голос
/ 12 марта 2019

Из того, что я понял из вопроса и комментариев @ Оксаны, мы, вероятно, можем сделать это следующим образом:

library(tidyverse)

# data
vru <- data.frame(
  id = c(3, 6, 22, 30, 1234456),
  z  = c(12325, 21698, 21725, 8378, 18979),
  fz = c(134, 67, 70, 88, 88)
)

# solution
vru %>%                             #
  top_n(450 - sum(fz), z) %>%       # subset by top z, if sum(fz) == 450 -> NULL
  mutate(fz = fz + 1) %>%           # increase fz by 1 for the subset
  bind_rows(                        #
    anti_join(vru, ., by = "id"),   # take rows from vru which are not in subset
    .                               # take subset with transformed fz 
  ) %>%                             # bind thous subsets
  arrange(id)                       # sort rows by id

# output
       id     z  fz
1       3 12325 134
2       6 21698  68
3      22 21725  71
4      30  8378  88
5 1234456 18979  89
1 голос
/ 12 марта 2019

Разъяснения в комментариях помогли. Дайте мне знать, если это работает для вас. Конечно, вы можете удалить столбцы cumsum_fz и leftover.

# Making variables to use in the calculation
df <- df %>%
  arrange(fz) %>%
  mutate(cumsum_fz = cumsum(fz),
         leftover = 450 - cumsum_fz)

# Find the minimum, non-negative value to use for select values that need +1
min_pos <- min(df$leftover[df$leftover > 0])

# Creating a vector that adds 1 using the min_pos value and keeps
# the other values the same
df$new_value <- c((head(sort(df$fz), min_pos) + 1), tail(sort(df$fz), length(df$fz) - min_pos))

# Checking the sum of the new value
> sum(df$new_value)
[1] 450
> 
> df
    ID_PP     z  fz cumsum_fz leftover new_value
1       6 21698  67        67      383        68
2      22 21725  70       137      313        71
3      30  8378  88       225      225        89
4 1234456 18979  88       313      137        88
5       3 12325 134       447        3       134

EDIT:

Так как utubun уже опубликовал отличное решение для Tidyverse, я собираюсь полностью перевести мой первый вариант на базовый (в любом случае смешивать их было немного неаккуратно). Та же логика, что и выше, с использованием предоставленных данных OP.

 > # Using base
> df <- df[order(fz),]
> 
> leftover <- 450 - cumsum(fz)
> min_pos <- min(leftover[leftover > 0])
> df$new_value <- c((head(sort(df$fz), min_pos) + 1), tail(sort(df$fz), length(df$fz) - min_pos))
> 
> sum(df$new_value)
[1] 450
> df
    ID_PP     z  fz new_value
2       6 21698  67        68
3      22 21725  70        71
4      30  8378  88        89
5 1234456 18979  88        88
1       3 12325 134       134
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...