2010-01-12 30 views
23

¿Qué opciones de tipos de datos tenemos para manejar números grandes en R? De forma predeterminada, el tamaño de un entero parece ser de 32 bits, por lo que los números grandes del servidor SQL y cualquier número grande pasado de Python a través de rpy2 se destruyen.tipo de datos long/bigint/decimal equivalente en R

> 123456789123 
[1] 123456789123 
> 1234567891234 
[1] 1.234568e+12 

Cuando se lee un valor BIGINT del 123456789123456789 usando RODBC, se va recuperando a medida 123456789123456784 (véase el último dígito), y el mismo número cuando deserialized través RJSONIO, vuelve como -1395630315L (que parece un error adicional/limitación de RJSONIO).

> fromJSON('[1234567891]') 
[1] 1234567891 
> fromJSON('[12345678912]') 
[1] -539222976 

En realidad, yo no necesito ser capaz de manejar grandes cantidades procedentes de JSON, por lo que con la limitación de RJSONIO, puedo no tener una solución a excepción de la búsqueda de una mejor biblioteca JSON (que parece como un no-opción correcta ahora). Me gustaría saber qué opinan los expertos sobre esto y en general.

Respuesta

16

Ver help(integer):

Note that on almost all implementations of R the range of 
representable integers is restricted to about +/-2*10^9: ‘double’s 
can hold much larger integers exactly. 

así que recomendaría el uso de numeric (es decir, 'doble') - un número de doble precisión.

+0

Miré la función as.numeric(), pero me confundí por el hecho de que el modo (1) también da el tipo "numérico", así que pensé que ya estaba tratando con ellos. Luego probé como .numeric ("123456789123456789") y solo vi unos pocos números impresos, por lo que supuse que había perdido la precisión. No sabía sobre opciones ("dígitos") antes. – haridsv

+0

Ah, sí, lo de los dígitos. Además, si necesita mayor precisión o números grandes, CRAN tiene paquetes para eso, como p. el (extrañamente nombrado :-) paquete Brobdingnag para grandes cantidades, y también está el paquete gmp para interconectar GNU gmp. –

+0

(Sé que Dirk lo sabe pero estoy comenzando a alertar a otros buscadores). Las versiones más nuevas de R permiten una transición más uniforme al almacenamiento de enteros como dobles. Sin embargo, la dimensión de la matriz todavía no está usando ese cambio de modo automático. –

7

Dirk tiene razón. Debería utilizar el tipo numeric (que debe establecerse en el doble). La otra cosa a tener en cuenta es que es posible que no recuperes todos los dígitos. Mira el ajuste dígitos:

> options("digits") 
$digits 
[1] 7 

Se puede extender esto:

options(digits=14) 

Alternativamente, puede volver a formatear el número:

format(big.int, digits=14) 

Probé su número y estoy recibiendo el mismo comportamiento (incluso utilizando el tipo de datos double), por lo que puede ser un error:

> as.double("123456789123456789") 
[1] 123456789123456784 
> class(as.double("123456789123456789")) 
[1] "numeric" 
> is.double(as.double("123456789123456789")) 
[1] TRUE 
+0

Gracias por señalar las opciones() y el formato(), son útiles. Sin embargo, estas opciones parecen controlar solo cómo se formatea el número para su visualización, por lo que no debe cambiar la forma en que se analiza el número al usar as.double() o as.numeric(). El comportamiento podría ser un error. – haridsv

+0

No creo que funcione, está convirtiendo un entero en un doble y perdiendo precisión, por lo que no podrá volver a indexar en una matriz que haga referencia. – evolvedmicrobe

21

Entendí su pregunta un poco diferente frente a los dos que publicaron antes que yo.

Si el valor predeterminado más grande de R no es lo suficientemente grande para usted, tiene algunas opciones (descargo de responsabilidad: He utilizado cada una de las bibliotecas que menciono a continuación, pero no a través de las vinculaciones R, a biblioteca)

El paquete Brobdingnag: usa registros naturales para almacenar los valores; (como Rmpfr, implementado usando la nueva estructura de clases de R). Siempre me impresiona cualquier persona cuyo trabajo requiera números de esta escala.

library(Brobdingnag) 

googol <- as.brob(1e100) 

El paquete gmp: R fijaciones a la venerable GMP (biblioteca GNU de precisión múltiple). Esto debe remontarse a 20 años porque lo usé en la Universidad. El lema de esta biblioteca es "Aritmética sin límites", que es una afirmación creíble: enteros, racionales, flotantes, lo que sea, hasta los límites de la memoria RAM en su caja.

library(gmp) 

x = as.bigq(8000, 21) 

El Rmpfr paquete: enlaces de R que interfaz para ambos gmp (arriba) y MPFR, (MPFR es a su vez la aplicación contemporánea de gmp he utilizado los enlaces Python ('bigfloat') y la CAN. lo recomiendo altamente. Esta podría ser su mejor opción de las tres, dado su alcance, dado que parece ser el más activamente mantenido y, finalmente, dado lo que parece ser la documentación más completa.

Nota: para usar cualquiera de los dos últimos, deberá instalar las bibliotecas nativas, GMP y MPFR.

+0

Gracias, pero actualmente estoy satisfecho con las limitaciones del tipo de datos numéricos, aunque realmente no cumplió con mi pregunta original. Tendré en cuenta tu sugerencia y los examinaré en caso de que necesite manejar valores más grandes. – haridsv

2

He reparado algunos problemas relacionados con los enteros en rpy2 (Python puede cambiar de int a long cuando sea necesario, pero R does no parece poder hacer eso. Los desbordamientos de enteros ahora deberían devolver NA_integer_.

L.

12

Después de que se hizo esta pregunta, paquetes int64 por Romain Francois y bit64 por Jens Oehlschlägel están ahora disponibles.

+0

parece que int64 ya no está – evolvedmicrobe

+1

@evolvedmicrobe usamos bit64 en data.table y funciona bien –

2

Estaba tratando de encontrar una solución para este problema en los últimos dos días y finalmente lo encontré hoy. Tenemos identificaciones largas de 19 dígitos en nuestra base de datos SQL y antes usé RODBC para obtener datos de gran tamaño del servidor. Probé int64 y bit64, también definí las opciones (dígitos = 19), pero RODBC siguió dando problemas. Reemplacé RODBC con RJDBC, y mientras recuperaba los datos de bigint del servidor SQL, manipulé la consulta SQL mediante el uso de datos bigint en cadena.

Así que aquí es código de ejemplo:

#Include stats package 
require(stats); 
library(RJDBC); 
#set the working directory 
setwd("W:/Users/dev/Apps/R/Data/201401_2"); 

#Getting JDBC Driver 
driver <- JDBC("com.microsoft.sqlserver.jdbc.SQLServerDriver", "W:/Users/dev/Apps/R/Data/sqljdbc/enu/sqljdbc4.jar"); 

#Connect with DB 
connection <- dbConnect(driver, "jdbc:sqlserver://DBServer;DatabaseName=DB;", "BS_User", "BS_Password"); 
#Query string 


    sqlText <- paste("SELECT DISTINCT Convert(varchar(19), ID) as ID 
FROM tbl_Sample", sep=""); 

#Execute query 
queryResults <- dbGetQuery(connection, sqlText); 

Con esta solución, tengo los datos BIGINT sin ninguna modificación, pero no funcionó con RODBC. Ahora la velocidad de la interacción del servidor SQL con R se ha visto afectada porque RJDBC es más lento que RODBC, pero no está tan mal.

1

Hay muchas opciones que puede usar para R para números grandes. También puedes usar as.numeric(). El problema con as.numeric() es que encontré un error en la función para la versión R 3.02. Si multiplica los números usando el tipo de datos as.numeric() y los números producen un resultado de alrededor de 16 dígitos, obtendrá un resultado de error. Este error de as.numeric() se ha probado en muchas bibliotecas.

Hay otra opción.

Escribí dos programas para R, uno se llama infiX y el otro es infiXF para R. Esta biblioteca actualmente solo admite cálculos de multiplicación. Ambos calculan números con el decimal preciso. Ha sido probado más de 100,000 veces. infiX se ocupará del número en formato de cadena donde infiXF lo llevará a la base del sistema de archivos.

Cuando almacena el número en la memoria, está limitado a 8 - 128 Gb dependiendo de su memoria. A veces, incluso menos si el compilador no le permite utilizar todos los recursos disponibles. Cuando calcule los números en una base de archivos de texto, puede calcular 1/5 del tamaño del disco duro. El único problema es el tiempo que necesitaría para un cálculo.

Por ejemplo, si estaba calculando 1 terabyte de dígitos a otro terabyte de dígitos. Eso es alrededor de 2 billones de dígitos. Eso es factible en un disco duro de 8 terabytes. Sin embargo, ¿tengo tiempo para hacer el cálculo?

InfiX for R se puede encontrar aquí.http://kevinhng86.iblog.website/2017/02/21/working-with-number-infinity-multiplication-optimised-the-code-r/