k6ashok
k6ashok

Reputation: 45

column-wise operations depending on data on a data frame in R

I have a data frame with negative values in one column. something like this

df <- data.frame("a" = 1:6,"b"= -(5:10), "c" = rep(8:6,2))

  a   b c
1 1  -5 8
2 2  -6 7
3 3  -7 6
4 4  -8 8
5 5  -9 7
6 6 -10 6

I want to convert this to a data frame with no negative values in "b" keeping row totals unchanged. I can use column "a" only if "c" is not big enough to absorb the negative values in "b".

The end result should look like this

  a   b  c
1 1   0  3
2 2   0  1
3 2   0  0
4 4   0  0
5 3   0  0
6 2   0  0

I feel that sapply could be used. But I don't know how ?

Upvotes: 2

Views: 66

Answers (3)

GKi
GKi

Reputation: 39717

You can use pmin and pmax to get the new values for a, b and c.

df$c <- df$c + pmin(0, df$b)
df$b <- pmax(0, df$b)
df$a <- df$a + pmin(0, df$c)
df$c <- pmax(0, df$c)
df
#  a b c
#1 1 0 3
#2 2 0 1
#3 2 0 0
#4 4 0 0
#5 3 0 0
#6 2 0 0

Upvotes: 1

www
www

Reputation: 39174

Here is a base R solution.

df2 <- df

df2$c <- df$c + df$b
df2$a <- ifelse(df2$c < 0, df2$a + df2$c, df2$a)
df2[df2 < 0 ] <- 0

df2
#   a b c
# 1 1 0 3
# 2 2 0 1
# 3 2 0 0
# 4 4 0 0
# 5 3 0 0
# 6 2 0 0

Upvotes: 0

Martin Gal
Martin Gal

Reputation: 16998

You could use dplyr:

df %>%
  mutate(total=rowSums(.)) %>%
  rowwise() %>%
  mutate(c=max(b+c, 0), 
         b=max(b,0), 
         a=total - c - b) %>%
  select(-total)

which returns

# A tibble: 6 x 3
# Rowwise: 
      a     b     c
  <dbl> <dbl> <dbl>
1     1     0     3
2     2     0     1
3     2     0     0
4     4     0     0
5     3     0     0
6     2     0     0

Upvotes: 1

Related Questions