3

This post is based on this question: Running ifelse statement by a variable

Given some data

  col1 col2
1    B   10
2    B    7
3    C    7
4    D    1
5    A    3
6    D    2

to which we want to add a new column that indicates whether the value of 'col2' is the maximum of 'col2' grouped by 'col1'.

In base R one can use transform and ave

transform(df, new_col = ave(col2, col1, FUN = function(x) x == max(x)))
  col1 col2 new_col
1    B   10       1
2    B    7       0
3    C    7       1
4    D    1       0
5    A    3       1
6    D    2       1

My question is why 'new_col' is of type integer and not logical?

@RichScriven pointed out in the comments that that's because 'col2' is already numeric but I don't understand that.

Thanks!

data

df <- structure(list(col1 = c("B", "B", "C", "D", "A", "D"), col2 = c(10L, 
7L, 7L, 1L, 3L, 2L)), .Names = c("col1", "col2"), row.names = c(NA, 
-6L), class = "data.frame")
markus
  • 25,843
  • 5
  • 39
  • 58

1 Answers1

4

ave will return an object of the same class as x if it can be coerced

with(df, ave(col2, col1, FUN = function(x) T))
# [1] 1 1 1 1 1 1
with(df, ave(col2, col1, FUN = function(x) 'a'))
# [1] "a" "a" "a" "a" "a" "a"

df$col2 <- as.logical(df$col2)
with(df, ave(col2, col1, FUN = function(x) T))
# [1] TRUE TRUE TRUE TRUE TRUE TRUE



df$col2 <- as.factor(df$col2)
with(df, ave(col2, col1, FUN = function(x) T))
# [1] TRUE TRUE TRUE TRUE TRUE TRUE
# Levels: TRUE

Edit: It appears that it will coerce to a "higher" class but not a "lower" class. Where "higher" and "lower" is determined by the ordering given in ?c (below).

df$col2 <- as.logical(df$col2)
with(df, ave(col2, col1, FUN = function(x) 1))
# [1] 1 1 1 1 1 1

NULL < raw < logical < integer < double < complex < character < list < expression

IceCreamToucan
  • 28,083
  • 2
  • 22
  • 38
  • 1
    The rules for mixed types in arithmetic are described in `?Arithmetic`. The rules for combining different types using `c()` are given in `?c`. Not sure which set of rules determines results in `ave()`. – user2554330 Jun 22 '18 at 16:24
  • 1
    if you want to see something funny try `with(df, ave(as.character(col2), col1, FUN = function(x) T))` – moodymudskipper Jun 22 '18 at 16:30
  • 1
    The documentation states that the first parameter should be numeric, and then states that the output will be numeric, but as we've seen it's true only if the input is as expected by the function. – moodymudskipper Jun 22 '18 at 16:35