R Programming - convert numeric to MM:SS - r

This may be a silly question, but I can't find anything on this.
I have a numeric value that represents seconds. How can I convert it to MM:SS
For example
My number is 96
Represented in MM:SS it should be 01:36.
Any help is appreciated.

The %/% (integer division) and %% (modulo) operators are your friends:
x <- 96
paste(x %/% 60, x %% 60, sep = ":")
which gives
> paste(x %/% 60, x %% 60, sep = ":")
[1] "1:36"
Here it is in a function:
d2ms <- function(x) {
paste(x %/% 60, x %% 60, sep = ":")
}
> xx <- c(120, 96, 45, 30)
> d2ms(xx)
[1] "2:0" "1:36" "0:45" "0:30"
Which shows we need a little help to get exactly the format you need; see ?sprint for ways to format numbers [as characters] with leading 0s etc:
d2ms <- function(x) {
sprintf("%02d:%02d", x %/%60, x %% 60)
}
> d2ms(xx)
[1] "02:00" "01:36" "00:45" "00:30"
Note that the : in the string above is a literal, the %xxy bits are the formats for the values specified in the next two arguments and include formatting details for the number of zeros to pad (i.e. pad with zeroes until number uses two digits.) The template for this usage here is:
%[flag][width]specifier,
where here we used:
0 as the flag --- pad with 0s
width was 2, we want MM or SS
specifier was d for integers (could also have been i)
Whether you need that or not is up to your end use case.
These operators are quite useful for these sorts of operations; another example would be converting from degrees, minutes, seconds notation to decimal degrees for spatial coordinates.

Try:
x<-96
sprintf("%02d:%02d",x%/%60,x%%60)
#[1] "01:36"

Related

Weighted sum of digits in R

I am trying to figure out the most efficient way to calculate the weighted sum of digits for a numeric string (where the weight is equal to the position of the digit in the numeric string).
Example: For the number 1059, the weighted sum of digits is calculated as 1 * 1 + 0 * 2 + 5 * 3 + 9 * 4 = 52
I would like to allow for the input to be of any length, but if there are more efficient ways when there is a limit to the string length (e.g. knowing that the number is no more 10 digits allows for a more efficient program) I am open to that too. Also, if it is preferred that the input is a of type numeric rather than character that is acceptable too.
What I have right now is an old fashioned for loop:
wsod <- function(str) {
output <- 0
for (pos in 1:nchar(str)) {
digit <- as.numeric(substr(str, pos , pos))
output <- output + pos * digit
}
output
}
A few solutions have been proposed for Python (using a numeric input) but I don't think they apply to R directly.
> number <- 1059
> x <- strsplit(as.character(number), "")[[1]]
> y <- seq_len(nchar(number))
> as.numeric(as.numeric(x) %*% y)
[1] 52
weighted.digit <- function(str) {
splitted.nums <- as.numeric(strsplit(str, '')[[1]])
return(sum(splitted.nums * 1:length(splitted.nums)))
}
weighted.digit('1059')
[1] 52
One could modify this to accept a numeric input, and then simply convert that to character as a first step.

Efficient way to perform cell-wise calculation in a large matrix

I am trying to get 2 bits of 8-bit value from the cloud mask intermediate product of the NASA.
The matrix has a dimension of 3200 x 3248. I have to do this conversion for thousands of data sets.
Here is one of the dataset that I want to do this conversion. dataset
Here is my code:
library(binaryLogic)
test = as.logical(c(0,0))
#n_row <- nrow(cmask_1)
n_row <- 100
cmask_2bits <- matrix(nrow=n_row, ncol=ncol(cmask_1))
t1 <- Sys.time()
for(i in 1:n_row){
cmask_2bits[i,] <- sapply(cmask_1[i,], function (x) ifelse(identical(as.logical(as.binary(x, n=8)[5:6]), test), 0, 1))
}
t2 <- Sys.time()
time <- difftime(t2, t1)
t1_mthd2 <- Sys.time()
cmask_2bits_mthd2 <- matrix(nrow=n_row, ncol=ncol(cmask_1))
cmask_2bits_mthd2 <- mapply(function (x)
ifelse(identical(as.logical(as.binary(x, n=8)[5:6]), test), 0, 1), cmask_1[1:n_row,])
cmask_2bits_mthd2 <- matrix(cmask_2bits_mthd2, nrow=n_row, ncol=ncol(cmask_1))
t2_mthd2 <- Sys.time()
time_mthd2 <- difftime(t2_mthd2, t1_mthd2)
time_mthd2 - time
I have tried these two lines of code with mapply and sapply with for loop. I am wondering whether ifelse statement can be also improved for faster result.
My second question is whether this job (getting thousands of matrices) should be done on Hadoop platform or not.
My result should be like this for the first 10 rows and 10 columns:
Any suggestion would be appreciated.
Edit: As an example, as.binary(15, n=8) gives me the result as
0 0 0 0 1 1 1 1 as an 8-bit unsigned character. This binary value is read from the right, so that my 2 bits of interest are 3rd and 4th bits, which are 1 1. Since as.binary(15, n=8) gives me a "binary" "logical" vector, I can get these bits by requesting 5th and 6th values of this code result.
For the broader question, the most efficient method for cell-wise operations on a large matrix, when the operation is identical for every cell, is to use the built-in vectorized operations. A matrix in R is really just a vector with some metadata about dimensions. For your specific question, in addition to vectorization, it looks like that binaryLogic.asBinary is not computationally efficient. For your simple case of bits 5 and 6 being zero in an 8 bit integer, just do it with integer math:
(((cmask_1 %% 128) %% 64) < 16) + 0
The modulos clear out bits 7 and 8, and from there all values with bits 5 and 6 equal to zero will be less than 16. Adding 0 to the result converts from a logical vector to 0/1.
Edit: looking back at your example it looks like you want the result to be zero when bits 5 and 6 are both zero. That would be:
(((cmask_1 %% 128) %% 64) > 15) + 0
I think the fastest method is to use bitwise logical operators. If you want to extract bit 3 and 4 from an integer X you can use "X AND 12" (4 + 8 = 12). As result you get "4" if the 3rd bit is set, "8" for the 4th bit and "12" if the 3rd and 4th bit are set.
In R there is the package "bitops" which support the operations you need:
library(bitops)
mat_cmask = as.matrix(df_cmask)
v = as.vector(mat_cmask, mode="integer")
v1 = bitAnd(v, 12) # there are still values 4, 8 and 12
v2 = as.integer(v1>0)
result = matrix(v2, nrow=nrow(cmask), ncol(cmask))
result[1:10, 1:10]
Best, Stefan
Thanks to #W. Murphy for this simple and clear answer. The correct answer following integer division should be
(((((((cmask_1 %% 256) %% 128) %% 64) %% 32) %% 16) < 16) & (3 < (((((cmask_1 %% 256) %% 128) %% 64) %% 32) %% 16))) + 0,
where I wanted to restrict the remainder between 3 and 16, so that the number will fall in this interval will be divided by either 8 or 4 or both.
Thanks again.

Avoiding rounding with formatC

I am using formatC to ensure that a bunch of numbers are all printed to the same length. Some numbers are shorter than the desired length and padded with 0s, and some are longer and truncated. The issue is that formatC rounds in the last digit.
This is fine
> formatC(1, digits = 5, format = 'f')
[1] "1.00000"
I do not like the rounding, I would rather truncate it at the nth digit without rounding.
> formatC(1.234567, digits = 5, format = 'f')
[1] "1.23457"
Is there a way to truncate numbers without rounding in R? I understand that it could be possible to first convert to character and then grab a certain substring of that, but that feels clunky.
It's a little hacky, but you can use trunc with a little multiplication:
trunc(1.234567 * 1e5) / 1e5
# [1] 1.23456
Functionalize it:
trunc2 = function(x, d) trunc(x * 10 ^ d) / 10 ^ d
Then you can
formatC(trunc2(1.234567, 5), digits = 5, format = 'f')
# [1] "1.23456"

How to round a number and make it show zeros?

The common code in R for rounding a number to say 2 decimal points is:
> a = 14.1234
> round(a, digits=2)
> a
> 14.12
However if the number has zeros as the first two decimal digits, R suppresses zeros in display:
> a = 14.0034
> round(a, digits=2)
> a
> 14
How can we make R to show first decimal digits even when they are zeros? I especially need this in plots. I've searched here and some people have suggested using options(digits=2), but this makes R to have a weird behavior.
We can use format
format(round(a), nsmall = 2)
#[1] "14.00"
As #arvi1000 mentioned in the comments, we may need to specify the digits in round
format(round(a, digits=2), nsmall = 2)
data
a <- 14.0034
Try this:
a = 14.0034
sprintf('%.2f',a) # 2 digits after decimal
# [1] "14.00"
The formatC function works nicely if you apply it to the vector after rounding. Here the inner function round rounds to two decimal places then the outer function formatC formats to the same number of decimal places as the number were rounded to. This essentially re-adds zeros to the number that would otherwise end without the decimal places (e.g., 14.0034 is rounded to 14, which becomes 14.00).
a=c(14.0034, 14.0056)
formatC(round(a,2),2,format="f")
#[1] "14.00", "14.01"
You can use this function instead of round and just use it like you use round function.
import decimal
def printf(x, n):
d = decimal.Decimal(str(x))
d0 = -(d.as_tuple().exponent)
if d0 < n:
print("x = ", x)
else:
d1 = decimal.Decimal(str(round(x, n)))
d2 = d1.as_tuple().exponent
MAX = n + d2
if MAX == 0:
print("x = ", round(x, n))
else:
i = 0
print("x = ", round(x, n), end = '')
while i != MAX:
if i == (MAX - 1):
print("0")
else:
print("0", end = '')
i = i + 1
So you must have something like this.
>>> printf(0.500000000000001, 13)
>>> 0.5000000000000

Splitting a number in R

In R I have a number, say 1293828893, called x.
I wish to split this number so as to remove the middle 4 digits 3828 and return them, pseudocode is as follows:
splitnum <- function(number){
#check number is 10 digits
if(nchar(number) != 10){
stop("number not of right size");
}
middlebits <- middle 4 digits of number
return(middlebits);
}
This is a pretty simple question but the only solutions I have found apply to character strings, rather than numeric ones.
If of interest, I am trying to create an implementation in R of the Middle-square method, but this step is particularly tricky.
You can use substr(). See its help page ?substr. In your function I would do:
splitnum <- function(number){
#check number is 10 digits
stopifnot(nchar(number) == 10)
as.numeric(substr(number, start = 4, stop = 7))
}
which gives:
> splitnum(1293828893)
[1] 3828
Remove the as.numeric(....) wrapping on the last line you want the digits as a string.
Just use integer division:
> x <- 1293828893
> (x %/% 1e3) %% 1e4
[1] 3828
Here's a function that completely avoids converting the number to a character
splitnum <- function(number){
#check number is 10 digits
if(trunc(log10(X))!=9) {
stop("number not of right size")
}
(number %/% 1e3) %% 1e4
}
splitnum(1293828893)
# [1] 3828

Resources