2012-06-07 15 views
5

Dado el siguiente problema con el redondeo de milisegundos en R. ¿Cómo lo soluciono para que los tiempos sean los correctos?Problema R con el redondeo de milisegundos

> options(digits.secs=3) 
> as.POSIXlt("13:29:56.061", format='%H:%M:%OS', tz='UTC') 
[1] "2012-06-07 13:29:56.060 UTC" 
> as.POSIXlt("13:29:56.062", format='%H:%M:%OS', tz='UTC') 
[1] "2012-06-07 13:29:56.061 UTC" 
> as.POSIXlt("13:29:56.063", format='%H:%M:%OS', tz='UTC') 
[1] "2012-06-07 13:29:56.063 UTC" 

me di cuenta de que esta URL proporciona información de fondo, pero no resuelve mi problema: Milliseconds puzzle when calling strptime in R.

También esta URL toca el problema pero no lo resuelve: R xts: .001 millisecond in index.

En estos casos lo hago ver lo siguiente:

> x <- as.POSIXlt("13:29:56.061", format='%H:%M:%OS', tz='UTC') 
> print(as.numeric(x), digits=20) 
[1] 1339075796.0610001087 

La URL también parece indicar que esto es sólo un problema de presentación, pero me he dado cuenta de que el uso de declaraciones como "%OS3" sin la línea de opciones no hacer parece recoger el número correcto de dígitos.

La versión que estoy usando es de 32 bits 2.15.0 bajo Windows, pero esto parece existir en otras situaciones para R.

Tenga en cuenta que los datos de mi original es que estas cadenas de fecha y hora dentro de un archivo CSV debo encontrar una forma de convertirlos en el tiempo de milisegundos correcto desde una cadena.

+1

El uso de formato() aquí es innecesario y molesto. . . – mdsumner

+0

Bueno, sí, pero sí necesitamos 'format = '% H:% M:% OS''. –

+0

Véase también http://stackoverflow.com/a/7730759/210673 – Aaron

Respuesta

5

no veo que:

> options(digits.secs = 4) 
> as.POSIXlt("13:29:56.061", format = '%H:%M:%OS', tz='UTC') 
[1] "2012-06-07 13:29:56.061 UTC" 
> as.POSIXlt("13:29:56.062", format = '%H:%M:%OS', tz='UTC') 
[1] "2012-06-07 13:29:56.062 UTC" 
> as.POSIXlt("13:29:56.063", format = '%H:%M:%OS', tz='UTC') 
[1] "2012-06-07 13:29:56.063 UTC" 
> options(digits.secs = 3) 
> as.POSIXlt("13:29:56.061", format = '%H:%M:%OS', tz='UTC') 
[1] "2012-06-07 13:29:56.061 UTC" 
> as.POSIXlt("13:29:56.062", format = '%H:%M:%OS', tz='UTC') 
[1] "2012-06-07 13:29:56.062 UTC" 
> as.POSIXlt("13:29:56.063", format = '%H:%M:%OS', tz='UTC') 
[1] "2012-06-07 13:29:56.063 UTC" 

con

> sessionInfo() 
R version 2.15.0 Patched (2012-04-14 r59019) 
Platform: x86_64-unknown-linux-gnu (64-bit) 

locale: 
[1] LC_CTYPE=en_GB.utf8  LC_NUMERIC=C    
[3] LC_TIME=en_GB.utf8  LC_COLLATE=en_GB.utf8  
[5] LC_MONETARY=en_GB.utf8 LC_MESSAGES=en_GB.utf8 
[7] LC_PAPER=C    LC_NAME=C     
[9] LC_ADDRESS=C    LC_TELEPHONE=C   
[11] LC_MEASUREMENT=en_GB.utf8 LC_IDENTIFICATION=C  

attached base packages: 
[1] stats  graphics grDevices utils  datasets methods 
[7] base 

Con los "%OSn" cadenas de formato, uno fuerzas truncamiento. Si el segundo fraccionario no se puede representar exactamente en puntos flotantes, entonces el truncamiento puede ir muy bien. Si usted ve las cosas van a manera incorrecta también se puede redondear explícitamente a la unidad que desea o añadir una mitad de la fracción que desea operar a (en el caso que se muestra 0.0005):

> t1 <- as.POSIXlt("13:29:56.061", format = '%H:%M:%OS', tz='UTC') 
> t1 
[1] "2012-06-07 13:29:56.061 UTC" 
> t1 + 0.0005 
[1] "2012-06-07 13:29:56.061 UTC" 

(pero me dijo , No veo el problema aquí.)

Este último punto fue hecho por Simon Urbanek on the R-Devel mailing list on 30-May-2012.

+0

Pruébelo con la versión de 32 bits. –

+0

@AndrewStern No puedo no tener un sistema de 32 bits para probarlo. He actualizado mi respuesta. Intenta agregar una pequeña fracción (0,0005 en tu caso) a tus tiempos * después de * los tienes como objetos '' POSIXlt ''y ve si eso mejora la situación. Sigue ese hilo R-Devel para más detalles. –

+1

Puedo reproducir - Tengo tanto 32 bits como 64 bits R instalados en un sistema Win7 de 64 bits. Parece que el problema es específico de 32bit R. – Fhnuzoag

1

Los milisegundos están ahí:

unclass(as.POSIXlt("13:29:56.061", '%H:%M:%OS', tz='UTC')) 
$sec 
[1] 56.061 
... 

(No hay necesidad de llamada formato de aquí, es el nombre de un argumento no requiere la entrada de alguna otra función).

lo contrario, no se pueden reproducir (en Windows de 64 bits R 2.15.0):

options(digits.secs = 3) 
as.POSIXlt("13:29:56.061", '%H:%M:%OS', tz='UTC') 
[1] "2012-06-07 13:29:56.061 UTC" 

sessionInfo() 
R version 2.15.0 Patched (2012-05-05 r59321) 
Platform: x86_64-pc-mingw32/x64 (64-bit) 
... 
+0

Parece ser correcto cuando lo desclasto utilizando lo siguiente: unclass (como.POSIXlt ("13: 29: 56.061", "% H:% M:% OS", tz = 'UTC')) pero la pantalla todavía muestra los milisegundos incorrectos cuando se visualiza usando: as.POSIXlt ("13: 29: 56.061", "% H:% M:% OS", tz = 'UTC').Tenga en cuenta que estoy en la versión de 32 bits y que la versión de 64 bits podría ser más precisa ya que los registros son más grandes. –

+1

Debe ser una pantalla defectuosa. – mdsumner

3

Este es el mismo problema que Milliseconds puzzle when calling strptime in R.

Su ejemplo:

> x <- as.POSIXlt("13:29:56.061", format='%H:%M:%OS', tz='UTC') 
> print(as.numeric(x), digits=20) 
[1] 1339075796.0610001087 

no es representativa del problema. as.numeric(x) convierte su objeto POSIXlt a POSIXct antes de convertirlo a numérico, por lo que obtiene diferentes errores de redondeo con precisión de coma flotante.

No es así como funciona print.POSIXlt (que llama a format.POSIXlt). format.POSIXlt formatos de cada elemento de la lista POSIXlt constructo de forma individual, por lo que tendría que mirar:

print(x$sec, digits=20) 
[1] 56.060999999999999943 

Y ese número se trunca en el tercer decimal, por lo que se ve 56.060. Se puede ver esto llamando format directamente:

> format(x, "%H:%M:%OS6") 
[1] "13:29:56.060999" 
1

En las pruebas que han señalado que todavía existe este número por 32 bits R 3.01 y que esto se debe a un truncamiento de datos de coma flotante que es específico de la aplicación de 32 bits de imprimir, formatear y operadores de caracteres para las fechas POSIXlt.

Los datos subyacentes no se han almacenado en un tipo diferente que conduce al truncamiento en un caso (32 bits) y no en el otro (64 bits), sino en "impresión", "formato" y "como.caracter "funciones específicamente para el tipo POSIXlt que se utilizan para mostrar los datos POSIXlt como una cadena visualizable.

Aunque el comportamiento documentado es que estas funciones truncan (ignoran) los dígitos adicionales (como lo menciona @Gavin Simpson), esto no es cierto del mismo modo para las versiones de 32 y 64 bits. Demostrar; generaremos 1000 veces diferentes y realizar algunas operaciones comparaciones:

> options(digits.sec=3) 
> x = as.POSIXlt("13:29:56.061", format='%H:%M:%OS', tz='UTC') 

> for (i in 0:999) { 
>  x[i+1] = as.POSIXlt(paste0("13:29:56.",sprintf("%03d",i)),format='%H:%M:%OS',tz='UTC') 
> } 

> sum(x[2:1000]>x[1:999]) 
[1] 999 

Bajo ambos de 32 bits y 64 bits de los operadores de comparación son consistentes, sin embargo, bajo 32 bits que ver:

> x[1:6] 
[1] "2015-10-16 13:29:56.000 UTC" "2015-10-16 13:29:56.000 UTC" 
[3] "2015-10-16 13:29:56.002 UTC" "2015-10-16 13:29:56.003 UTC" 
[5] "2015-10-16 13:29:56.003 UTC" "2015-10-16 13:29:56.005 UTC" 

Por lo tanto, es claramente un problema de visualización. En cuanto a los números reales en el tipo de datos POSIXlt, particularmente los segundos podemos ver lo que parece suceder:

> y = (x[1:6]$sec) 
> y 
[1] 56.000 56.001 56.002 56.003 56.004 56.005 
> trunc(y*1000)/1000 
[1] 56.000 56.001 56.002 56.003 56.004 56.005 
> trunc((y-floor(y))*1000)/1000 
[1] 0.000 0.000 0.002 0.003 0.003 0.005 

Yo sugeriría que este es un error que debe ser corregido en la biblioteca de base subyacente, como una solución temporal sin embargo, puede sobrescribir las funciones "imprimir", "como.caracter" y "formatear" para cambiar la salida a la salida deseada, por ejemplo

format.POSIXlt = function(posix) { 
    return(paste0(posix$year+1900,"-",sprintf("%02d",posix$mon+1),"-",sprintf("%02d",posix$mday)," ", 
     sprintf("%02d",posix$hour),":",sprintf("%02d",posix$min),":",sprintf("%002.003f",posix$sec))) 
    } 

print.POSIXlt = function(posix) { 
    print(paste0(posix$year+1900,"-",sprintf("%02d",posix$mon+1),"-",sprintf("%02d",posix$mday)," ", 
     sprintf("%02d",posix$hour),":",sprintf("%02d",posix$min),":",sprintf("%002.003f",posix$sec))) 
    } 

as.character.POSIXlt = function(posix) { 
    return(paste0(posix$year+1900,"-",sprintf("%02d",posix$mon+1),"-",sprintf("%02d",posix$mday)," ", 
     sprintf("%02d",posix$hour),":",sprintf("%02d",posix$min),":",sprintf("%002.003f",posix$sec))) 
    } 
Cuestiones relacionadas