Rounding significant figures in R
Asked Answered
O

1

6

So basically I am doing a physics experiment, and in my table I want to have my data rounded to the same accuracy as the error is, which is rounded to 1 sig fig.

So for example if I have the following:

angle <- c(4, 4.1, 4.2)
angle.error <- c(0.024, 0.3, 0.113)
data <- data.frame(angle,angle.error)

want I want to end up with is the angle error rounded to 1 sig fig, and the angle rounded to the corresponding number of decimal places as the angle error, to give

angle <- c(4.00, 4.1, 4.2)
angle.error <- c(0.02,0.3,0.1)
data <- data.frame(angle, angle.error)

Hope this makes sense!! This is the standard way we are taught to present data, and as such I am surprised how difficult I am finding it to find a proper way of doing this. Any contributions would be great!!

EDIT:

If I want to turn this into a UDR where say the data is in column 5 and the errors in column 6 of my data frame, I write:

Conv2 <- function(x) {
x[6] <- signif(x[6],1)
exp <- floor(log10(x[6]))
man <- x[6]/10^exp         
x[5] <- round(x[5], -exp)   # Error associated with this line I think
sapply(seq_along(x[5]), function(i) format(x[i,5], nsmall=-exp[i]))

return(x)
}

When I implement it I get the error 'Error in FUN(X[[i]], ...) : non-numeric argument to mathematical function'

Oersted answered 22/3, 2017 at 18:12 Comment(2)
I might need a little clarification. Are you using "1dp" to mean 1 significant figure or 1 decimal place. If you are not using 1dp interchangeably with 1 sig fig, then your output doesn't seem quite right. Also, you say you want angle rounded to the same number of sigfigs as angle.error, but your output uses two sigfigs for angle while angle.error only has one.Vendetta
yes sorry I got this the wrong way around - I have now edited it to make senseOersted
D
19

This can be done with signif(). In contrast to round(), which rounds to a number of decimal places, signif() rounds to a specific number of significant places.

x <- c(1,1.0001,0.00001)
round(x,1) # rounds to the specified number of decimal places
signif(x,1) # rounds to the specified number of significant digits

Let's apply this to your case. Note that signif is vectorized over both arguments.

> signif(c(1.111,2.222,3.333),c(1,2,3))
[1] 1.00 2.20 3.33

This would mean the following for your case:

angle.error <- c(0.024, 0.3, 0.113)
cor <- signif(angle.error,1)

Rounding the angles is slightly more difficult. We need to round angle to the same number of decimal places as angle.error_corr. Therefore we will extract the mantissa and exponent of this number.

exp <- floor(log10(cor)) 
man <- cor/10^exp

Now it is possible to use the exponents to round your angles.

angle <- c(4, 4.1, 4.2)
angle_cor <- round(angle, -exp)

However, this does not give the intended result since R shows the number of digits of the most precise double and drops trailing zeros. We can solve this with the nsmall argument of format, which is unfortunately not vectorized.

sapply(seq_along(angle), function(i) format(angle[i], nsmall = -exp[i]))

Which should give you the answer you were looking for.

Dalessio answered 22/3, 2017 at 18:24 Comment(3)
@Nick Siemons, slightly updated the answer such that it also describes your specific case.Dalessio
thanks for this, I gave it a go. Ideally I want this as a UDF, which I have tried to do. Unfortunately I get an error when I implement it - see the edit on my post. Any ideas?Oersted
Ok sorted it! had to add in exp <- as.matrix(exp)Oersted

© 2022 - 2024 — McMap. All rights reserved.