nouse
nouse

Reputation: 3461

Subsetting a data.frame based on factor levels in a second data.frame

I have two data.frames:

df.1 <- data.frame(A=runif(10), B=runif(10), C=runif(10), D=runif(10))
df.2 <- data.frame(Var=factor(c("A", "B", "C", "D")), Info=c("X1", "X2", "X1", "X2"))

In df.1, i want to select all columns which are associated with one factor level in df.2$Info

i can only do this in a very clumsy way by merging the two data.frames first, then subsetting, then rearraging the desired output:

tmp <- as.data.frame(t(df.1))
tmp$Var=row.names(tmp)
tmp.m <- merge(tmp, df.2, by="Var")

df.X1 <- tmp.m[tmp.m$Info == "X1", ]
df.X1$Info <- factor(df.X1$Info) # drop unused factor levels

desired.output <- as.data.frame(t(df.X1))
names(desired.output) <- lapply(desired.output[1, ], as.character)
desired.output <- desired.output[-c(1,11),] 

My question is if there is a better, faster and less complicated way (i am sure there is!). Thank you.

Upvotes: 1

Views: 170

Answers (4)

DeduciveR
DeduciveR

Reputation: 1702

A tidyverse solution, maybe not quite as elegant as the others, but could open up some other possibilities:

library(tidyverse)
df.2sub <- df.2 %>% 
  filter(Info == "X1")

df.1sub <- df.1 %>% 
  select_if(colnames(.) %in% df.2sub$Var)


df.1sub

    A         C
1  0.99561926 0.6661509
2  0.68340388 0.5952997
3  0.21700589 0.6677539
4  0.07276628 0.2027971
5  0.70201107 0.4015561
6  0.86886930 0.7653709
7  0.71247007 0.1007955
8  0.96024317 0.7130610
9  0.04268316 0.9754990
10 0.67787175 0.8897161

EDIT:

There's a more parsimonious way with tidyverse:

df.1sub <- df.1 %>% 
  select_if(colnames(.) %in% filter(df.2, Info == "X1")[["Var"]])

Upvotes: 1

akrun
akrun

Reputation: 887118

We can also loop through the unique elements in 'Info' column, compare with the 'Info', extract the 'Var' elements and subset

lapply(unique(df.2$Info), function(nm) df.1[df.2$Var[df.2$Info == nm]])

Upvotes: 1

Sixiang.Hu
Sixiang.Hu

Reputation: 1019

df.1[,unique(df.2$Var[which(df.2$Info=="X1")])]

           A            C
1  0.8924861 0.7149490854
2  0.5711894 0.7200819517
3  0.7049629 0.0004052017
4  0.9188677 0.5007302717
5  0.3440664 0.9138259818
6  0.8657903 0.2724015017
7  0.7631228 0.5686033906
8  0.8388003 0.7377064163
9  0.0796059 0.6196693045
10 0.5029824 0.8717568610

Upvotes: 1

Sotos
Sotos

Reputation: 51592

You can split and subset, i.e.

lapply(split(df.2$Var, df.2$Info), function(i) df.1[i])

which gives,

$X1
           A          C
1  0.4666410 0.24030906
2  0.3246221 0.55153654
3  0.2042521 0.75376685
4  0.1130009 0.03761851
5  0.9979631 0.77633112
6  0.3611264 0.61717196
7  0.1535525 0.89337225
8  0.7068574 0.92468517
9  0.6951691 0.33549641
10 0.1637878 0.70826630

$X2
            B          D
1  0.06560149 0.24576981
2  0.23798129 0.53494840
3  0.62587837 0.08097668
4  0.38462826 0.98415256
5  0.94772413 0.85647140
6  0.90655926 0.97475473
7  0.48175364 0.24743947
8  0.65016599 0.75966646
9  0.19430794 0.82114764
10 0.97282206 0.19113057

Upvotes: 1

Related Questions