9

I have data with a grouping variable ("from") and values ("number"):

from number
   1      1
   1      1
   2      1
   2      2
   3      2
   3      2

I want to subset the data and select groups which have two or more unique values. In my data, only group 2 has more than one distinct 'number', so this is the desired result:

from number
   2      1
   2      2
Henrik
  • 65,555
  • 14
  • 143
  • 159
DK2
  • 651
  • 1
  • 7
  • 34
  • I have a doubt about your question. Suppose in the `from` =2, the numbers are `1 2 1`. Would that fit into the subset criteria? – akrun Jul 27 '15 at 10:56

3 Answers3

7

Several possibilities, here's my favorite

library(data.table)
setDT(df)[, if(+var(number)) .SD, by = from]
#    from number
# 1:    2      1
# 2:    2      2

Basically, per each group we are checking if there is any variance, if TRUE, then return the group values


With base R, I would go with

df[as.logical(with(df, ave(number, from, FUN = var))), ]
#   from number
# 3    2      1
# 4    2      2

Edit: for a non numerical data you could try the new uniqueN function for the devel version of data.table (or use length(unique(number)) > 1 instead

setDT(df)[, if(uniqueN(number) > 1) .SD, by = from]
David Arenburg
  • 91,361
  • 17
  • 137
  • 196
  • my real data is not nubmer. it's name string. it can be same problem? – DK2 Jul 27 '15 at 09:49
  • 1
    If it isn't numeric, use the `uniqueN` function from the devel version, such as `setDT(df)[, if(uniqueN(number) > 1) .SD, by = from]`. If you don't have the devel version, try `setDT(df)[, if(length(unique(number)) > 1) .SD, by = from]` instead. [Link for the devel version](https://github.com/Rdatatable/data.table/wiki/Installation) – David Arenburg Jul 27 '15 at 09:53
6

You could try

 library(dplyr)
 df1 %>% 
     group_by(from) %>%
     filter(n_distinct(number)>1)
 #    from number
 #1    2      1
 #2    2      2

Or using base R

 indx <- rowSums(!!table(df1))>1
 subset(df1, from %in% names(indx)[indx])
 #   from number
 #3    2      1
 #4    2      2

Or

  df1[with(df1, !ave(number, from, FUN=anyDuplicated)),]
  #   from number
  #3    2      1
  #4    2      2
akrun
  • 874,273
  • 37
  • 540
  • 662
  • 1
    Nice alternatives (i was thinking `n_distinct` but left it for you :)), though the last one is probably misleading, so I wouldn't use it – David Arenburg Jul 27 '15 at 10:58
1

Using concept of variance shared by David but doing it dplyr way:

library(dplyr) 
df %>% 
   group_by(from) %>% 
   mutate(variance=var(number)) %>% 
   filter(variance!=0) %>% 
   select(from,number)

    #Source: local data frame [2 x 2]
    #Groups: from

       #from number
   #1    2      1
   #2    2      2
Community
  • 1
  • 1
Atish
  • 174
  • 3
  • 9