smaug
smaug

Reputation: 936

Count of unique elements of each row in a data frame in R

I have a data frame like below:

Group1  Group2  Group3  Group4
A       B       A       B   
A       C       B       A   
B       B       B       B   
A       C       B       D   
A       D       C       A   

I want to add a new column to the data frame which will have the count of unique elements in each row. Desired output:

Group1  Group2  Group3  Group4  Count
A       B       A       B       2
A       C       B       A       3
B       B       B       B       1
A       C       B       D       4
A       D       C       A       3

I am able to find such a count for each row using

length(unique(c(df[,c(1,2,3,4)][1,])))

I want to do the same thing for all rows in the data frame. I tried apply() with var=1 but without success. Also, it would be great if you could provide a more elegant solution to this.

Upvotes: 6

Views: 3994

Answers (3)

akrun
akrun

Reputation: 886938

We can use apply with MARGIN =1 to loop over the rows

df1$Count <- apply(df1, 1, function(x) length(unique(x)))
df1$Count
#[1] 2 3 1 4 3

Or using tidyverse

library(dplyr)
df1 %>%
    rowwise() %>%
    do(data.frame(., Count = n_distinct(unlist(.))))
# A tibble: 5 × 5
#   Group1 Group2 Group3 Group4 Count
#*  <chr>  <chr>  <chr>  <chr> <int>
#1      A      B      A      B     2
#2      A      C      B      A     3
#3      B      B      B      B     1
#4      A      C      B      D     4
#5      A      D      C      A     3

We can also use regex to do this in a faster way. It is based on the assumption that there is only a single character per each cell

nchar(gsub("(.)(?=.*?\\1)", "", do.call(paste0, df1), perl = TRUE))
#[1] 2 3 1 4 3

More detailed explanation is given here

Upvotes: 9

PKumar
PKumar

Reputation: 11128

Athough there are some pretty great solutions mentioned over here, You can also use, data.table :

DATA:

df <- data.frame(g1 = c("A","A","B","A","A"),g2 = c("B", "C", "B","C","D"),g3 = c("A","B","B","B","C"),g4 = c("B","A","B","D","A"),stringsAsFactors = F)

Code:

EDIT: After the David Arenberg's comment,added (.I) instead of 1:nrow(df). Thanks for valuable comments

library(data.table)
setDT(df)[, id := .I ]
df[, count := uniqueN(c(g1, g2, g3, g4)), by=id ]
df

Output:

> df
   g1 g2 g3 g4 id count
1:  A  B  A  B  1     2
2:  A  C  B  A  2     3
3:  B  B  B  B  3     1
4:  A  C  B  D  4     4
5:  A  D  C  A  5     3

Upvotes: 2

989
989

Reputation: 12937

duplicated in base R:

df$Count <- apply(df,1,function(x) sum(!duplicated(x)))

#  Group1 Group2 Group3 Group4 Count
#1      A      B      A      B     2
#2      A      C      B      A     3
#3      B      B      B      B     1
#4      A      C      B      D     4
#5      A      D      C      A     3

Upvotes: 3

Related Questions