Alex Zhang
2011-Dec-27 19:14 UTC
[R] sapply Call Returning " the condition has length > 1" Error
Dear all, Happy new year! I have a question re using sapply. Below is a dummy example that would replicate the error I saw. ##Code Starts here DummyFunc <- function(x) { if (x > 0) { return (x) } else { return (-x) } } Y = data.frame(val = c(-3:7)) sapply(Y, FUN = DummyFunc) ##Code ends here When I run it, I got: val [1,] 3 [2,] 2 [3,] 1 [4,] 0 [5,] -1 [6,] -2 [7,] -3 [8,] -4 [9,] -5 [10,] -6 [11,] -7 Warning message: In if (x > 0) { : the condition has length > 1 and only the first element will be used The result is different from what I would expect plus there is such an error message. I guess if the DummyFunc I provided is compatible with vectors, the problem would go away. But let's suppose I cannot change DummyFunc. Is there still a way to use sapply or alike without actually writing a loop? Thanks. - Alex [[alternative HTML version deleted]]
R. Michael Weylandt
2011-Dec-27 20:04 UTC
[R] sapply Call Returning " the condition has length > 1" Error
You are right that the problem is that "DummyFunc" isn't vectorized. R looks for a single logical value in an "if" statement but "x>0" gives it a whole vector's worth -- as the warning indicates, it only uses the first and pushes the whole vector through the loop in the return(-x) branch, which explains the values you saw. The correct way to do it would be something like: ifelse(x < 0, -x, x) If, as you suggest, you can't modify the function (for whatever reason), you can use the higher-order-function Vectorize() as follows: vDummyFunc <- Vectorize(DummyFunc) vDummyFunc(-3:7) This isn't real vectorization, but it hides some *apply family stuff nicely. Note that this doesn't act as you might expect on Y since data.frames are taken column wise by default (you'll get the same problem). Michael On Tue, Dec 27, 2011 at 1:14 PM, Alex Zhang <alex.zhang at ymail.com> wrote:> Dear all, > > Happy new year! > > I have a question re using sapply. Below is a dummy example that would replicate the error I saw. > > ##Code Starts here > DummyFunc <- function(x) { > > if (x > 0) { > return (x) > } else > { > return (-x) > } > > } > > Y = data.frame(val = c(-3:7)) > sapply(Y, FUN = DummyFunc) > ##Code ends here > > When I run it, I got: > ? ? ?val > ?[1,] ? 3 > ?[2,] ? 2 > ?[3,] ? 1 > ?[4,] ? 0 > ?[5,] ?-1 > ?[6,] ?-2 > ?[7,] ?-3 > ?[8,] ?-4 > ?[9,] ?-5 > [10,] ?-6 > [11,] ?-7 > Warning message: > In if (x > 0) { : > ? the condition has length > 1 and only the first element will be used > > The result is different from what I would expect plus there is such an error message. > > I guess if the DummyFunc I provided is compatible with vectors, the problem would go away. But let's suppose I cannot change DummyFunc. Is there still a way to use sapply or alike without actually writing a loop? Thanks. > > - Alex > ? ? ? ?[[alternative HTML version deleted]] > > > ______________________________________________ > R-help at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code. >
John Fox
2011-Dec-27 20:10 UTC
[R] sapply Call Returning " the condition has length > 1" Error
Dear Alex,> -----Original Message----- > From: r-help-bounces at r-project.org [mailto:r-help-bounces at r- > project.org] On Behalf Of Alex Zhang > Sent: December-27-11 2:14 PM > To: r-help at r-project.org > Subject: [R] sapply Call Returning " the condition has length > 1" > Error > > Dear all, > > Happy new year! > > I have a question re using sapply. Below is a dummy example that would > replicate the error I saw. > > ##Code Starts here > DummyFunc <- function(x) { > > if (x > 0) { > return (x) > } else > { > return (-x) > } > > } > > Y = data.frame(val = c(-3:7)) > sapply(Y, FUN = DummyFunc) > ##Code ends here > > When I run it, I got: > val > [1,] 3 > [2,] 2 > [3,] 1 > [4,] 0 > [5,] -1 > [6,] -2 > [7,] -3 > [8,] -4 > [9,] -5 > [10,] -6 > [11,] -7 > Warning message: > In if (x > 0) { : > the condition has length > 1 and only the first element will be used > > The result is different from what I would expect plus there is such an > error message.This is a warning, not really an error message. A data frame is essentially a list of variables (columns), and sapply() applies its FUN argument to each list element, that is, each variable -- the one variable val in your case. That produces a warning because val > 0 is a vector of 11 elements, and the first comparison, 3 > 0, which is TRUE, controls the result.> > I guess if the DummyFunc I provided is compatible with vectors, the > problem would go away. But let's suppose I cannot change DummyFunc. Is > there still a way to use sapply or alike without actually writing a > loop? Thanks.Well, you could just use> abs(Y$val)[1] 3 2 1 0 1 2 3 4 5 6 7 but I suppose that you didn't really want to write your own version of the absolute-value function as something more than an exercise. An alternative is> with(Y, ifelse(val > 0, val, -val))[1] 3 2 1 0 1 2 3 4 5 6 7 I hope this helps, John -------------------------------- John Fox Senator William McMaster Professor of Social Statistics Department of Sociology McMaster University Hamilton, Ontario, Canada http://socserv.mcmaster.ca/jfox> > - Alex > [[alternative HTML version deleted]]