Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I avoid loops in R?

Tags:

loops

r

apply

I understand that in R it is best to avoid loops where possible. In that regard, I would like to perform the function of the code below but without using the nested loops.

The loops check whether the f'th element of the vector things_I_want_to_find is present in the i'th row of thing_to_be_searched. For example, when both i and f are 1, the code checks whether "vocals" is present in john's row. Because "vocals" is present in john's row, the name and instrument are added to vectors instrument and name. When both loops are complete these two vectors can be combined in a data.frame.

I know that there is the apply() family of functions in R but I don't know if they are able to be used in this case. Has anyone got any helpful hints or suggestions?

instrument<-c()

name<-c()

things_I_want_to_find<-c("vocals","drums","rhythm guitar","bass")

thing_to_be_searched<-
data.frame(
id=c("john","paul","george","ringo"),
a=c("vocals","bass","rhythm guitar","oboe"),
b=c("vocals","basoon","piano","clarinet"),
c=c("violin","vocals","french horn","drums"))
for(f in 1:length(things_I_want_to_find))
{
  for(i in 1:nrow(thing_to_be_searched))
  {
    n<-which(thing_to_be_searched[i,]==things_I_want_to_find[f])
    if(length(n)>0)
    {
      instrument<-c(instrument,as.character(thing_to_be_searched[i,][n][,1][1]))
      name<-c(name,as.character(thing_to_be_searched$id[i]))
    }

    
  }
}

desired_output<-data.frame(name=name,instrument=instrument)
desired_output
    name    instrument
1   john        vocals
2   paul        vocals
3  ringo         drums
4 george rhythm guitar
5   paul          bass
like image 274
John Avatar asked Dec 30 '22 14:12

John


2 Answers

library(tidyverse)
thing_to_be_searched %>%
  # Melt wide data to long
  pivot_longer(-1) %>%
  # Drop unwanted column
  select(-name) %>%
  # Filter wanted values only
  filter( value %in% things_I_want_to_find) %>%
  # Only keep unique rows
  unique()

output

# A tibble: 5 x 2
  id     value        
  <chr>  <chr>        
1 john   vocals       
2 paul   bass         
3 paul   vocals       
4 george rhythm guitar
5 ringo  drums 
like image 140
Wimpel Avatar answered Jan 17 '23 19:01

Wimpel


Using base R with reshape (with R 4.1.0)

thing_to_be_searched |>
   setNames(c('id', paste0('a', 1:3))) |>
   reshape(direction = 'long',  varying  = 2:4, sep="") |>
   subset(a %in% things_I_want_to_find, select = c(id, a)) |>
   unique() |>
   `row.names<-`(NULL)
#      id             a
#1   john        vocals
#2   paul          bass
#3 george rhythm guitar
#4   paul        vocals
#5  ringo         drums
like image 31
akrun Avatar answered Jan 17 '23 17:01

akrun