Infamous Inf – Part II

R’s Inf keyword – Have you’ve ever wondered what to do with it? If so, this is the second in series of posts that explore how we can exploit the keyword’s interesting properties to get the answers we need and improve code robustness. If you want to catch up on the first post where we look at Inf and the cut() function, please see Infamous Inf – Part I

For those unfamiliar with R’s Inf keyword, it is defined as a positive or negative number divided by zero yielding positive or negative infinity, respectively.

c(plus_inf = 1/0, minus_inf = -1/0)

# plus_inf minus_inf 
#      Inf      -Inf

Sounds very theoretical. So how we can make practical use of infinity in R? In this first post, we’ll be discussing how Inf can make binning data with cut() a more robust process.

Inf with integrate()

For many of us, Integration ranks low in the fun category, but sometimes its necessary. For example, to get the probability of a normally distributed event between two limits you would need to integrate the normal distribution density function between limits a and b. The functions are detailed below along with their R function equivalent.

f(x |\mu, \sigma^2) = \frac{1}{\sqrt{2\pi\sigma^2}} e^{-\frac{(x - \mu)^2}{2\sigma^2}} \qquad \mathrm{Density\ Function\ (aka.\ dnorm)} \\ P(x |\mu, \sigma^2) = \int\limits_a^b \frac{1}{\sqrt{2\pi\sigma^2}} e^{-\frac{(x - \mu)^2}{2\sigma^2}} \qquad \mathrm{Proability\ Function \space (aka.\ pnorm)}

 

The total area under the Density Function should be 1. So if we integrate dnorm(x) from negative to positive infinity we should get 1. Let’s see

LongDF <- function(x, mu = 0 , sigma = 1){
            1/sqrt(2*pi*sigma^2) * exp(-(x-mu)^2/(2*sigma^2))
          }

#dnorm and the long function are the same...
#dnorm(0) == LongDF(0)
#TRUE

integrate(dnorm, -Inf,  Inf)

The result:

1 with absolute error < 9.4e-05

As expected the answer is 1. The same result you’d get if you ran.

pnorm(q = Inf, mean = 0, sd = 1)

Which also yields, 1

Infamous Inf – Part I

R’s Inf keyword – Have you’ve ever wondered what to do with it? If so, this is the first in series of posts that explore how we can exploit the keyword’s interesting properties to get the answers we need and improve code robustness.

For those unfamiliar with R’s Inf keyword, it is defined as a positive or negative number divided by zero yielding positive or negative infinity, respectively.

c(plus_inf = 1/0, minus_inf = -1/0)

# plus_inf minus_inf 
#      Inf      -Inf

Sounds very theoretical. So how we can make practical use of infinity in R? In this first post, we’ll be discussing how Inf can make binning data with cut() a more robust process.

Inf with cut()

Suppose you want to bin the following set of numbers into five discrete levels. Take note of the extreme values on the positive and negative end of the vector.

{-100,-1,1,1,1,2,2,2,5,5,5,10,10,10,100,1000}

You might do something like,

numbers <- c(-100, -1,1,1,1,2,2,2,5,5,5,10,10,10,100,1000)
bins <- cut(numbers, breaks = c(-101,-2,2,5,11, 1001))
xtabs(~bins)

bins Freq
(-101,-2] 1
(-2,2] 7
(2,5] 3
(5,11] 3
(11,1e+03] 2

The above code and data explicitly shows how we might bin the data including the extreme values -100, 100, and 1000. But with real data, extreme values can change when new data is added. For example, what if we received the following new pieces of data: -102 and 1002? Below, we’ve added them to our list and re-binned them as before to see what happens.

numbers <- c(-102, -100, -1,1,1,1,2,2,2,5,5,5,10,10,10,100,1000,1002)
  bins <- cut(numbers, breaks = c(-101,-2,2,5,11, 1001))
  xtabs(~bins)
bins Freq
(-101,-2] 1
(-2,2] 7
(2,5] 3
(5,11] 3
(11,1e+03] 2

Oops! The new data was not included in the binning. We need to manually expand our limits, or we could perhaps do something clever with the max and min functions.

Alternatively, we can solve this problem with R’s \pm Inf keyword by placing \pm Inf in the breaks argument of the cut function (see line 2 below)

numbers <- c(-102, -100, -1,1,1,1,2,2,2,5,5,5,10,10,10,100,1000,1002)
bins <- cut(numbers, breaks = c(-Inf,-2,2,5,11, Inf))
xtabs(~bins)
bins Freq
(-Inf,-2] 2
(-2,2] 7
(2,5] 3
(5,11] 3
(11, Inf] 3

Now, when new data is collected that is less than -2 or greater than 11 there will be a bin to catch it, no mater how big or how small.