ChristianD
ChristianD

Reputation: 101

apply a function to a vector grouping by factor and returning a logical value

I have the following df

df <- data.frame(group=c("a","a","a","b","b","b","b","b","c","c","c","c"), 
                 length=c(1.2,1.4,1.1,1.0,2.1,1.4,1.3,1.3,1.1,1.0,1.8,1.4),
                 weight = c(.3,.2,.3,.5,.7,.4,.3,.4,.7,.8,.4,.1))

i would like to be able to produce a logical vector of the same length based on the minimum "weight" value in each "group". For the above example the result should be

[1] FALSE TRUE FALSE  FALSE  FALSE  FALSE TRUE  FALSE  FALSE  FALSE  FALSE TRUE

I apologize if possibly the question is very simple, but i cant work my way around it.

Upvotes: 2

Views: 126

Answers (2)

Rich Scriven
Rich Scriven

Reputation: 99361

You could write a short is.min function (if you're into that sort of thing), and then use by with is.min.

This is somewhat similar to the answer given by @sgibb. Actually, since the edit of is.min, it's almost exactly the same. But I'll leave it here in case you've never seen unlist, with, and/or by.

> is.min <- function(x){ x == min(x) }
> unlist(with(df, by(weight, group, is.min)))
##    a1    a2    a3    b1    b2    b3    b4    b5    c1    c2    c3    c4 
## FALSE  TRUE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE  TRUE 

Upvotes: 1

sgibb
sgibb

Reputation: 25736

Try ave (for details see ?ave):

d <- ave(df$weight, df$group, FUN=function(x){min(x) == x})
d
# [1] 0 1 0 0 0 0 1 0 0 0 0 1
as.logical(d)
# [1] FALSE  TRUE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE  TRUE

Upvotes: 1

Related Questions