0

I am running the following code:

 disc<-for (i in 1:33) {
 m=n[i]
 xbar<-sum(data[i,],na.rm=TRUE)/m 
 Sx <- sqrt(sum((data[i,]-xbar)^2,na.rm=TRUE)/(m-1))
 Sx
 i=i+1}

Running it:

 >disc
 NULL

Why is it giving me NULL?

Ay_M
  • 193
  • 1
  • 2
  • 8
  • What is `n`? What is `data`? –  Jul 16 '13 at 23:14
  • When I don't use the loop, I have to run them one-by-one. Running them one-by-one, I get Sx=4.5,3.5,.... – Ay_M Jul 16 '13 at 23:14
  • Wait....why are you trying to assign a `for` loop to a variable? I'm not certain that that's a valid assignment, and even if it is, it's quite a bizarre thing to do. –  Jul 16 '13 at 23:18
  • length of 'n' is 44. dim(data) = 33 x 25 – Ay_M Jul 16 '13 at 23:25
  • If I change my 5th line to print(Sx) I get the desired answer but nothing gets stored in dics – Ay_M Jul 16 '13 at 23:31
  • 1
    Yes, but **why are you trying to assign a `for` loop to a variable**? –  Jul 17 '13 at 00:05

3 Answers3

5

This is from the documentation for for, accessible via ?`for`:

‘for’, ‘while’ and ‘repeat’ return ‘NULL’ invisibly.

Perhaps you are looking for something along the following lines:

library(plyr)
disc <- llply(1:33, function(i) {
  m=n[i]
  xbar<-sum(data[i,],na.rm=TRUE)/m 
  Sx <- sqrt(sum((data[i,]-xbar)^2,na.rm=TRUE)/(m-1))
  Sx
})

Other variants exists -- the ll in llply stands for "list in, list out". Perhaps your intended final result is a data frame or an array -- appropriate functions exist.

The code above is a plain transformation of your example. We might be able to do better by splitting data right away and forgetting the otherwise useless count variable i (untested, as you have provided no data):

disc <- daply(cbind(data, n=n), .(), function(data.i) {
  m=data.i$n
  xbar<-sum(data.i,na.rm=TRUE)/m 
  sqrt(sum((data.i-xbar)^2,na.rm=TRUE)/(m-1))
})

See also the plyr website for more information.

Related (if not a duplicate): R - How to turn a loop to a function in R

Community
  • 1
  • 1
krlmlr
  • 25,056
  • 14
  • 120
  • 217
  • Ah, sorry. Should have realized you weren't going to leave it there. – Marius Jul 16 '13 at 23:22
  • @ayeshamalik: That's just because `for` doesn't return anything, as the docs read and I have indicated at the very top of my answer. – krlmlr Jul 16 '13 at 23:32
  • @krlmlr - The 2nd code you wrote didn't give the right answers. – Ay_M Jul 16 '13 at 23:53
  • @ayeshamalik: Could you please `dput` your data? See also http://stackoverflow.com/q/5963269/946850 – krlmlr Jul 16 '13 at 23:57
  • @krlmlr why are you using extra package here? I see also that you give a base solution (with a spelling mistake) in an another comment. – agstudy Jul 17 '13 at 00:34
  • @agstudy: `laply` is from `plyr`, `lapply` is from `base`. I prefer `plyr`, it's clean, simple, powerful. By all means, please do provide a "base" answer, too. – krlmlr Jul 17 '13 at 00:39
  • @krlmlr the problem here is not using lapply or plyr! That'said( even I know that plyr is a good package), but clearly here no need to use it. It is slower than a simple lapply. – agstudy Jul 17 '13 at 01:05
2

krlmlr's answer shows you how to fix your code, but to explain your original problem in more abstract terms: A for loop allows you to run the same piece of code multiple times, but it doesn't store the results of running that code for you- you have to do that yourself.

Your current code only really assigns a single value, Sx, for each run of the for loop. On the next run, a new value is put into the Sx variable, so you lose all the previous values. At the end, you'll just end up with whatever the value of Sx was on the last run through the loop.

To save the results of a for loop, you generally need to add them to a vector as you go through, e.g.

# Create the empty results vector outside the loop
results = numeric(0)
for (i in 1:10) {
  current_result = 3 + i
  results = c(results, current_result)
}
Marius
  • 58,213
  • 16
  • 107
  • 105
  • I got it. This really helped. Removing Sx does the job in my case. Thanks a lot! – Ay_M Jul 16 '13 at 23:34
  • 1
    @ayeshamalik: Just for the sake of completeness, the `plyr` equivalent of the code above: `results <- laply(10, function(i) 3+i)` – krlmlr Jul 16 '13 at 23:40
  • @ayeshamalik: No, wrong: `results <- laply(1:10, function(i) 3+i)` is the correct version. – krlmlr Jul 17 '13 at 00:13
  • @Marius you should know that it is better to preallocate before looping! – agstudy Jul 17 '13 at 00:36
1

In R for can't return a value. The unique manner to return a value is within a function. So the solution here, is to wrap your loop within a function. For example:

getSx <- function(){
  Sx <- 0
  disc <- for (i in 1:33) {
    m=n[i]
    xbar <- sum(data[i,],na.rm=TRUE)/m 
    Sx <- sqrt(sum((data[i,]-xbar)^2,na.rm=TRUE)/(m-1))
  }
  Sx
}

Then you call it:

 getSx()

Of course you can avoid the side effect of using a for by lapply or by giving a vectorized But this is another problem: You should maybe give a reproducible example and explain a little bit what do you try to compute.

agstudy
  • 119,832
  • 17
  • 199
  • 261