0

So, I built a function called sort.song.

My goal with this function is to randomly sample the rows of a data.frame (DATA) and then filter it out (DATA.NEW) to analyse it. I want to do it multiple times (let's say 10 times). By the end, I want that each object (mantel.something) resulted from this function to be saved in my workspace with a name that I can relate to each cycle (mantel.something1, mantel.somenthing2...mantel.something10).

I have the following code, so far:

 sort.song<-function(DATA){
  require(ade4)
  for(i in 1:10){ # Am I using for correctly here?

   DATA.NEW <- DATA[sample(1:nrow(DATA),replace=FALSE),]
   DATA.NEW <- DATA.NEW[!duplicated(DATA.NEW$Point),]

   coord.dist<-dist(DATA.NEW[,4:5],method="euclidean")
   num.notes.dist<-dist(DATA.NEW$Num_Notes,method="euclidean")
   songdur.dist<-dist(DATA.NEW$Song_Dur,method="euclidean")
   hfreq.dist<-dist(DATA.NEW$High_Freq,method="euclidean")
   lfreq.dist<-dist(DATA.NEW$Low_Freq,method="euclidean")
   bwidth.dist<-dist(DATA.NEW$Bwidth_Song,method="euclidean")
   hfreqlnote.dist<-dist(DATA.NEW$HighFreq_LastNote,method="euclidean")

   mantel.numnotes[i]<<-mantel.rtest(coord.dist,num.notes.dist,nrepet=1000)
   mantel.songdur[i]<<-mantel.rtest(coord.dist,songdur.dist,nrepet=1000)
   mantel.hfreq[i]<<-mantel.rtest(coord.dist,hfreq.dist,nrepet=1000)
   mantel.lfreq[i]<<-mantel.rtest(coord.dist,lfreq.dist,nrepet=1000)
   mantel.bwidth[i]<<-mantel.rtest(coord.dist,bwidth.dist,nrepet=1000)
   mantel.hfreqlnote[i]<<-mantel.rtest(coord.dist,hfreqlnote.dist,nrepet=1000)
   }
}

Could someone please help me to do it the right way?

I think I'm not assigning the cycles correctly for each mantel.somenthing object.

Many thanks in advance!

Mohr
  • 323
  • 1
  • 3
  • 9
  • Consider making the whole process a function, then you can repeat it multiple times using the replicate function. – Thomas Apr 16 '14 at 19:50
  • Could you please be more specific about it? What do you mean by "making the whole process a function"? – Mohr Apr 16 '14 at 20:09
  • 1
    Sorry for the long delay in response, but see my answer. – Thomas Apr 21 '14 at 15:04

2 Answers2

2

The best way to implement what you are trying to do is through a list. You can even make it take two indices, the first for the iterations, the second for the type of analysis.

mantellist <- as.list(1:10)   ## initiate list with some values
for (i in 1:10){
...
mantellist[[i]] <- list(numnotes=mantel.rtest(coord.dist,num.notes.dist,nrepet=1000),
                        songdur=mantel.rtest(coord.dist,songdur.dist,nrepet=1000),
                        hfreq=mantel.rtest(coord.dist,hfreq.dist,nrepet=1000),
                        ...)
}
return(mantellist)

In this way you can index your specific analysis for each iteration in an intuitive way:

mantellist[[2]][['hfreq']]
mantellist[[2]]$hfreq       ## alternative

EDIT by Mohr: Just for clarification...

So, according to your suggestion the code should be something like this:

sort.song<-function(DATA){
  require(ade4)
  mantellist <- as.list(1:10) 
  for(i in 1:10){
    DATA.NEW <- DATA[sample(1:nrow(DATA),replace=FALSE),]
    DATA.NEW <- DATA.NEW[!duplicated(DATA.NEW$Point),]

    coord.dist<-dist(DATA.NEW[,4:5],method="euclidean")
    num.notes.dist<-dist(DATA.NEW$Num_Notes,method="euclidean")
    songdur.dist<-dist(DATA.NEW$Song_Dur,method="euclidean")
    hfreq.dist<-dist(DATA.NEW$High_Freq,method="euclidean")
    lfreq.dist<-dist(DATA.NEW$Low_Freq,method="euclidean")
    bwidth.dist<-dist(DATA.NEW$Bwidth_Song,method="euclidean")
    hfreqlnote.dist<-dist(DATA.NEW$HighFreq_LastNote,method="euclidean")

    mantellist[[i]] <- list(numnotes=mantel.rtest(coord.dist,num.notes.dist,nrepet=1000),
                       songdur=mantel.rtest(coord.dist,songdur.dist,nrepet=1000),
                       hfreq=mantel.rtest(coord.dist,hfreq.dist,nrepet=1000),
                       lfreq=mantel.rtest(coord.dist,lfreq.dist,nrepet=1000),
                       bwidth=mantel.rtest(coord.dist,bwidth.dist,nrepet=1000),
                       hfreqlnote=mantel.rtest(coord.dist,hfreqlnote.dist,nrepet=1000)
                       )
  }
  return(mantellist)
}
ilir
  • 3,236
  • 15
  • 23
  • Hey, I edited your post just to check if I got it right...did I? – Mohr Apr 16 '14 at 20:31
  • Yup, that's why I approved it. Sorry I missed your earlier message. – ilir Apr 16 '14 at 20:33
  • Many thanks! If I had at least 15 points I would vote for your answer! :) EDIT: Well..now I got it! Thanks one more time. – Mohr Apr 16 '14 at 20:35
  • Thanks. I removed the question at the end, you know, for posterity :-) – ilir Apr 16 '14 at 20:39
  • Just one more thing... How do I use this information: mantellist[[2]][['hfreq']]...I always get NULL mantellist[[2]]$hfreq – Mohr Apr 16 '14 at 20:58
  • If the object generates correctly in the loop you should be able to access it and plug it into a function: `summary(mantellist[[2]]$hfreq)` – ilir Apr 16 '14 at 21:09
  • Probably I didn't understood it correctly. I'm running the function exactly as it is in your message. I'm doing this: a<-sort.song(DATA) Then when I try a[[2]]$hfreq it gives me NULL. – Mohr Apr 16 '14 at 21:47
  • Fixed the syntax on the `list()`. Try now please. – ilir Apr 16 '14 at 22:03
  • It worked. But, what's the difference between <- and = ? I always thought it was the same thing! – Mohr Apr 16 '14 at 22:16
  • It's subtle, and explained best [here](http://stackoverflow.com/questions/1741820/assignment-operators-in-r-and). In this case you don't want the list elements to exist as separate variables in the function environment. – ilir Apr 16 '14 at 22:20
1

You can achieve your objective of repeating this exercise 10 (or more times) without using an explicit for-loop. Rather than have the function run the loop, write the sort.song function to run one iteration of the process, then you can use replicate to repeat that process however many times you desire.

It is generally good practice not to create a bunch of named objects in your global environment. Instead, you can hold of the results of each iteration of this process in a single object. replicate will return an array (if possible) otherwise a list (in the example below, a list of lists). So, the list will have 10 elements (one for each iteration) and each element will itself be a list containing named elements corresponding to each result of mantel.rtest.

sort.song<-function(DATA){
   DATA.NEW <- DATA[sample(1:nrow(DATA),replace=FALSE),]
   DATA.NEW <- DATA.NEW[!duplicated(DATA.NEW$Point),]

   coord.dist <- dist(DATA.NEW[,4:5],method="euclidean")
   num.notes.dist <- dist(DATA.NEW$Num_Notes,method="euclidean")
   songdur.dist <- dist(DATA.NEW$Song_Dur,method="euclidean")
   hfreq.dist <- dist(DATA.NEW$High_Freq,method="euclidean")
   lfreq.dist <- dist(DATA.NEW$Low_Freq,method="euclidean")
   bwidth.dist <- dist(DATA.NEW$Bwidth_Song,method="euclidean")
   hfreqlnote.dist <- dist(DATA.NEW$HighFreq_LastNote,method="euclidean")

   return(list(
      numnotes = mantel.rtest(coord.dist,num.notes.dist,nrepet=1000),
      songdur = mantel.rtest(coord.dist,songdur.dist,nrepet=1000),
      hfreq = mantel.rtest(coord.dist,hfreq.dist,nrepet=1000),
      lfreq = mantel.rtest(coord.dist,lfreq.dist,nrepet=1000),
      bwidth = mantel.rtest(coord.dist,bwidth.dist,nrepet=1000),
      hfreqlnote = mantel.rtest(coord.dist,hfreqlnote.dist,nrepet=1000)
   ))
}

require(ade4)
replicate(10, sort.song(DATA))
Thomas
  • 43,637
  • 12
  • 109
  • 140