Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compare two rows of a data.table and show only columns with differences [duplicate]

I am given a large data.table, which has columns of different types: e.g. numeric or character. E.g.

 data.table(name=c("A","A"),val1=c(1,2),val2=c(3,3),cat=c("u","v"))

       name val1 val2 cat
   1:    A    1    3   u
   2:    A    2    3   v

As a results, I would like a data.table just with the columns, where the entries are different between the two rows:

 data.table(val1=c(1,2),cat=c("u","v"))

       val1 cat
   1:    1   u
   2:    2   v
like image 741
Strickland Avatar asked Jul 03 '19 06:07

Strickland


People also ask

How do I compare two columns for duplicate values?

Navigate to the "Home" option and select duplicate values in the toolbar. Next, navigate to Conditional Formatting in Excel Option. A new window will appear on the screen with options to select "Duplicate" and "Unique" values. You can compare the two columns with matching values or unique values.


2 Answers

With base R you could do:

library(data.table)

dt <- data.table(name=c("A","A"),val1=c(1,2),val2=c(3,3),cat=c("u","v"))

Filter(function(x) length(unique(x)) > 1, dt)   
#>    val1 cat
#> 1:    1   u
#> 2:    2   v
like image 195
Joris C. Avatar answered Nov 28 '22 03:11

Joris C.


You can check whether there is only one value in the column and return only the ones with more than one value:

mydt <- data.table(name=c("A", "A"), val1=c(1, 2), val2=c(3, 3), cat=c("u", "v"))
mydt_red <- mydt[, lapply(.SD, function(x) if(length(unique(x))!=1) x else NULL)]
mydt_red
#   val1 cat
#1:    1   u
#2:    2   v

EDIT
As mentionned by @kath, a more efficient way to get your result is to use min and max functions and to combine them with Filter:

mydt_red2 <- Filter(function(x) min(x)!=max(x), mydt)

Some basic benchmarking

# Data (inspired by https://stackoverflow.com/a/35746513/680068)
nrow=10000
ncol=10000
mydt <- data.frame(matrix(sample(1:(ncol*nrow),ncol*nrow,replace = FALSE), ncol = ncol))
setDT(mydt)

system.time(mydt_redUni <- mydt[, lapply(.SD, function(x) if(length(unique(x))>1) x else NULL)])
#utilisateur     système      écoulé 
#       2.31        0.52        2.83 
system.time(mydt_redFilt <- Filter(function(x) length(unique(x)) > 1, mydt))
#utilisateur     système      écoulé 
#     1.65        0.22        1.87 
system.time(mydt_redSort <- mydt[, lapply(.SD, function(x) {xs <- sort(x); if(xs[1]!=tail(xs, 1)) x else NULL})])
#utilisateur     système      écoulé 
#    3.87        0.00        3.87 
system.time(mydt_redMinMax <- mydt[, lapply(.SD, function(x) if(min(x)!=max(x)) x else NULL)])
#utilisateur     système      écoulé 
#    0.67        0.00        0.67 
system.time(mydt_redFiltminmax <- Filter(function(x) min(x)!=max(x), mydt))
#utilisateur     système      écoulé 
#    0.13        0.01        0.14 
system.time(mydt_redSotos <- Filter(function(i)var(as.numeric(as.factor(i))) != 0, mydt))
#utilisateur     système      écoulé
#  100.76        0.05      100.84
like image 41
4 revs Avatar answered Nov 28 '22 05:11

4 revs