Search code examples
rprecisionnumericcbind

R: is there a way to cbind non-numeric columns


library(Rmpfr)
mynumber <- new("mpfr", .Data = list(new("mpfr1", prec = 50L, exp = c(1045L, 
0L), sign = 1L, d = c(151748608L, -358118319L)), new("mpfr1", 
    prec = 50L, exp = c(20L, 0L), sign = 1L, d = c(-1114947584L, 
    -1905679017L)), new("mpfr1", prec = 50L, exp = c(-55L, -1L
), sign = 1L, d = c(-1449918464L, -906197701L)), new("mpfr1", 
    prec = 50L, exp = c(221L, 0L), sign = 1L, d = c(819707904L, 
    -1329031570L))))

mynumber is a class mpfr object with 4 numbers in it. I want to cbind mynumber with a column of 0s, i.e.

> cbind(rep(0, 4), mynumber)
       mynumber
[1,] 0 ?       
[2,] 0 ?       
[3,] 0 ?       
[4,] 0 ?  

This gives me ???? in the second column, so I tried to change mynumber to class numeric first

mydata <- cbind(rep(0, 4), sapply(mynumber, asNumeric))
> mydata
     [,1]         [,2]
[1,]    0          Inf
[2,]    0 5.833223e+05
[3,]    0 2.189941e-17
[4,]    0 2.327185e+66

However, since the first number in mynumber is really big, using asNumeric changed it into Inf instead.

Edit: My ultimate goal is to run:

mydata <- cbind(rep(0, 4), sapply(mynumber, asNumeric))
> mydata/rowSums(mydata)
     [,1] [,2]
[1,]    0  NaN
[2,]    0    1
[3,]    0    1
[4,]    0    1

and not have it print out NaN.


Solution

  • One option is to wrap with list and then create a tibble/data.frame object as cbind converts to a matrix and matrix can hold only a single class

    library(tibble)
    tibble(col1 = 0, col2 = list(mynumber))
    # A tibble: 1 x 2
    #   col1 col2  
    #  <dbl> <list>
    #1     0 <mpfr>
    

    cbind on even a character and numeric class returns character for all the columns and this is not a good option when the vectors to bind are of different class

    cbind(letters[1:4], 1:4)
    

    By checking the methods for cbind after loading the package

    methods('cbind')
    #[1] cbind,ANY-method     cbind,Mnumber-method cbind.bigq*          cbind.bigz*         
    #[5] cbind.data.frame     cbind.grouped_df*    cbind.ts*       
    

    So, if it was using the correct cbind methods for Mnumber, it should not have given Inf

    cbind(rep(0,4),  mynumber)
    #'mpfrMatrix' of dim(.) =  (4, 2) of precision  50 .. 53  bits 
    #     [,1] [,2]                   
    #[1,]   0. 3.4556867084990952e+314
    #[2,]   0.      583322.33392099757
    #[3,]   0.  2.1899410233914937e-17
    #[4,]   0.  2.3271850367397449e+66
    

    Or make use of the recycling of value

    cbind(0,  mynumber)
    #'mpfrMatrix' of dim(.) =  (4, 2) of precision  50 .. 53  bits 
    #     [,1] [,2]                   
    #[1,]   0. 3.4556867084990952e+314
    #[2,]   0.      583322.33392099757
    #[3,]   0.  2.1899410233914937e-17
    #[4,]   0.  2.3271850367397449e+66
    

    Also, if we check the masked the functions, when we load the package, it says

    The following objects are masked from ‘package:base’:

    cbind, pmax, pmin, rbind

    By using the cbind from base, the ? can be replicated. It is possible that for the OP, the cbind is from base

    base::cbind(0, mynumber)
    #       mynumber
    #[1,] 0 ?       
    #[2,] 0 ?       
    #[3,] 0 ?       
    #[4,] 0 ?       
    

    If the cbind from Rmpfr got masked, then use ::

    mydata <- Rmpfr::cbind(0, mynumber)
    mydata
    #'mpfrMatrix' of dim(.) =  (4, 2) of precision  50 .. 53  bits 
    #     [,1] [,2]                   
    #[1,]   0. 3.4556867084990952e+314
    #[2,]   0.      583322.33392099757
    #[3,]   0.  2.1899410233914937e-17
    #[4,]   0.  2.3271850367397449e+66
    
    
    
    
    mydata/rowSums(mydata)
    #'mpfrMatrix' of dim(.) =  (4, 2) of precision  53   bits 
    #     [,1] [,2]              
    #[1,]   0. 1.0000000000000000
    #[2,]   0. 1.0000000000000000
    #[3,]   0. 1.0000000000000000
    #[4,]   0. 1.0000000000000000