Jiang Du
Jiang Du

Reputation: 189

Select rows of data frame based on a vector with duplicated values

What I want can be described as: give a data frame, contains all the case-control pairs. In the following example, y is the id for the case-control pair. There are 3 pairs in my data set. I'm doing a resampling with respect to the different values of y (the pair will be both selected or neither).

sample_df = data.frame(x=1:6, y=c(1,1,2,2,3,3))
> sample_df
  x y
1 1 1
2 2 1
3 3 2
4 4 2
5 5 3
6 6 3
select_y = c(1,3,3)
select_y
> select_y
[1] 1 3 3

Now, I have computed a vector contains the pairs I want to resample, which is select_y above. It means the case-control pair number 1 will be in my new sample, and number 3 will also be in my new sample, but it will occur 2 times since there are two 3. The desired output will be:

x y
1 1
2 1
5 3
6 3
5 3
6 3

I can't find out an efficient way other than writing a for loop...

Solution: Based on @HubertL , with some modifications, a 'vectorized' approach looks like:

sel_y <- as.data.frame(table(select_y))
> sel_y
  select_y Freq
1        1    1
2        3    2
sub_sample_df = sample_df[sample_df$y%in%select_y,]
> sub_sample_df
  x y
1 1 1
2 2 1
5 5 3
6 6 3
match_freq = sel_y[match(sub_sample_df$y, sel_y$select_y),]
> match_freq
    select_y Freq
1          1    1
1.1        1    1
2          3    2
2.1        3    2
sub_sample_df$Freq = match_freq$Freq
rownames(sub_sample_df) = NULL
sub_sample_df
> sub_sample_df
  x y Freq
1 1 1    1
2 2 1    1
3 5 3    2
4 6 3    2
selected_rows = rep(1:nrow(sub_sample_df), sub_sample_df$Freq)
> selected_rows
[1] 1 2 3 3 4 4
sub_sample_df[selected_rows,]
    x y Freq
1   1 1    1
2   2 1    1
3   5 3    2
3.1 5 3    2
4   6 3    2
4.1 6 3    2

Upvotes: 1

Views: 613

Answers (2)

Kunal Puri
Kunal Puri

Reputation: 3427

Another method of doing the same without a loop:

sample_df = data.frame(x=1:6, y=c(1,1,2,2,3,3))

row_names <- split(1:nrow(sample_df),sample_df$y)

select_y = c(1,3,3)

row_num <- unlist(row_names[as.character(select_y)])

ans <- sample_df[row_num,]

Upvotes: 1

HubertL
HubertL

Reputation: 19544

I can't find a way without a loop, but at least it's not a for loop, and there is only one iteration per frequency:

sample_df = data.frame(x=1:6, y=c(1,1,2,2,3,3))
select_y = c(1,3,3)
sel_y <- as.data.frame(table(select_y))
do.call(rbind, 
        lapply(1:max(sel_y$Freq), 
               function(freq) sample_df[sample_df$y %in% 
                              sel_y[sel_y$Freq>=freq, "select_y"],]))

   x y
1  1 1
2  2 1
5  5 3
6  6 3
51 5 3
61 6 3

Upvotes: 0

Related Questions