Pregunta

¿Hay un cierto R-Gotcha que tenía realmente sorprendido un día? Creo que a todos nos ganancia de compartir estos.

Esta es la mía: en la lista de indexación, my.list[[1]] no es my.list[1]. Aprendido esto en los primeros días de R.

¿Fue útil?

Solución

Extracción de filas en una trama de datos causará-no singularmente filas con nombre que se añade, que luego errores hacia fuera:

> a<-data.frame(c(1,2,3,4),c(4,3,2,1))
> a<-a[-3,]
> a
  c.1..2..3..4. c.4..3..2..1.
1             1             4
2             2             3
4             4             1
> a[4,1]<-1
> a
Error in data.frame(c.1..2..3..4. = c("1", "2", "4", "1"), c.4..3..2..1. = c(" 4",  : 
  duplicate row.names: 4

Entonces, ¿qué está pasando aquí es:

  1. A data.frame de cuatro filas se crea, por lo que los rownames son c (1,2,3,4)

  2. Se suprime la tercera fila, así que los rownames son c (1,2,4)

  3. Se añade una cuarta fila, y R establece automáticamente el nombre de la fila igual al índice es decir, 4, por lo que los nombres de las filas son c (1,2,4,4). Esto es ilegal porque los nombres de fila debe ser único. No veo por qué este tipo de comportamiento se debe permitir por R. Me parece que R debe proporcionar un nombre único de la fila.

Otros consejos

[Hadley señaló este a cabo en un comentario .]

Cuando se utiliza una secuencia como un índice de iteración, es mejor utilizar la función seq_along() en lugar de algo así como 1:length(x).

A continuación, se crea un vector y ambos enfoques devolver la misma cosa:

> x <- 1:10
> 1:length(x)
 [1]  1  2  3  4  5  6  7  8  9 10
> seq_along(x)
 [1]  1  2  3  4  5  6  7  8  9 10

Ahora que el vector NULL:

> x <- NULL
> seq_along(x) # returns an empty integer; good behavior
integer(0)
> 1:length(x) # wraps around and returns a sequence; this is bad
[1] 1 0

Esto puede causar cierta confusión en un bucle:

> for(i in 1:length(x)) print(i)
[1] 1
[1] 0
> for(i in seq_along(x)) print(i)
>

La creación automática de factores al cargar los datos. Usted sin pensarlo, se trata una columna en una trama de datos como caracteres, y esto funciona bien hasta que haga algo como tratar de cambiar a un valor que no es un nivel. Esto generará una advertencia, pero salir de su marco de datos con AN en ella ...

Cuando algo va mal inesperadamente en su script R, compruebe que los factores no son los culpables.

El olvido de la caída = argumento falso en subconjuntos matrices hacia abajo para sola dimensión y dejando caer de ese modo la clase de objeto, así:

R> X <- matrix(1:4,2)
R> X
     [,1] [,2]
[1,]    1    3
[2,]    2    4
R> class(X)
[1] "matrix"
R> X[,1]
[1] 1 2
R> class(X[,1])
[1] "integer"
R> X[,1, drop=FALSE]
     [,1]
[1,]    1
[2,]    2
R> class(X[,1, drop=FALSE])
[1] "matrix"
R> 

En primer lugar, permítanme decir que entiendo los problemas fundamentales de representarlos en un sistema binario. Sin embargo, un problema que creo que podría mejorarse fácilmente es la representación de los números cuando el valor decimal está fuera del alcance típico de R de presentación.

x <- 10.2 * 100
x
1020
as.integer(x)
1019

No me importa si el resultado se representa como un entero, cuando en realidad se puede representar como un entero. Por ejemplo, si el valor de verdad era 1020 y luego la impresión de que para x estaría bien. Sin embargo, algo tan simple como 1020,0 en este caso, cuando se imprime x habría hecho más evidente que el valor no era un entero y no representable como uno. R debe defecto a algún tipo de indicación cuando hay un componente extremadamente pequeño decimal que no se presenta.

Puede ser molesto tener que permitir combinaciones de NA, NaN y Inf. Se comportan de manera diferente, y las pruebas para uno no necesariamente funciona para los demás:

> x <- c(NA,NaN,Inf)
> is.na(x)
[1]  TRUE  TRUE FALSE
> is.nan(x)
[1] FALSE  TRUE FALSE
> is.infinite(x)
[1] FALSE FALSE  TRUE

Sin embargo, la forma más segura de probar cualquiera de estos alborotadores es:

> is.finite(x)
[1] FALSE FALSE FALSE

Siempre pruebe lo que sucede cuando se tiene una NA!

Una cosa que siempre hay que prestar especial atención a (después de muchas experiencias dolorosas) es NA valores. R funciones son fáciles de usar, pero no hay manera de superar los problemas de la programación estarán con sus datos.

Por ejemplo, cualquier operación vector neto con un NA es igual a NA. Esto es "sorprendente" en la cara de ella:

> x <- c(1,1,2,NA)
> 1 + NA
[1] NA
> sum(x)
[1] NA
> mean(x)
[1] NA

Esto se extrapola a cabo en otras funciones de nivel superior.

En otras palabras, valores que faltan con frecuencia tengo tanta importancia como los valores medidos de forma predeterminada . Muchas de las funciones tienen valores por defecto na.rm=TRUE/FALSE; vale la pena pasar algún tiempo para decidir cómo interpretar esta configuración predeterminada.

Editar 1: Marek hace un gran punto. NA valores también pueden causar un comportamiento confuso en los índices. Por ejemplo:

> TRUE && NA
[1] NA
> FALSE && NA
[1] FALSE
> TRUE || NA
[1] TRUE
> FALSE || NA
[1] NA

Esto también es cierto cuando se está tratando de crear una expresión condicional (para una sentencia if):

> any(c(TRUE, NA))
[1] TRUE
> any(c(FALSE, NA))
[1] NA
> all(c(TRUE, NA))
[1] NA

Cuando estos valores NA terminan como sus índices vectoriales, muchas cosas inesperadas pueden seguir. Todo esto es el buen comportamiento de R, ya que significa que usted tiene que tener cuidado con los valores que faltan. Pero puede causar grandes dolores de cabeza al principio.

El olvido que strptime() y amigos regresan POSIXt POSIXlt donde length() siempre es nueve - convertir a POSIXct ayuda:

R> length(strptime("2009-10-07 20:21:22", "%Y-%m-%d %H:%M:%S"))
[1] 9
R> length(as.POSIXct(strptime("2009-10-07 20:21:22", "%Y-%m-%d %H:%M:%S")))
[1] 1
R> 

La función round siempre redondea al número par.

> round(3.5)
[1] 4  

> round(4.5)
[1] 4

matemáticas en números enteros es sutilmente diferente de los dobles (y, a veces compleja es raro también)

Actualizar Lo arreglaron algunas cosas en I 2.15

1^NA      # 1
1L^NA     # NA
(1+0i)^NA # NA 

0L %/% 0L # 0L  (NA from R 2.15)
0 %/% 0   # NaN
4L %/% 0L # 0L  (NA from R 2.15)
4 %/% 0   # Inf

Me sorprende que nadie menciona esto, pero:

T y F puede ser anulación, TRUE y FALSE no lo hacen.

Ejemplo:

x <- sample(c(0,1,NA), 100, T)
T <- 0:10

mean(x, na.rm=T)
# Warning in if (na.rm) x <- x[!is.na(x)] :
#   the condition has length > 1 and only the first element will be used
# Calls: mean -> mean.default
# [1] NA

plot(rnorm(7), axes=T)
# Warning in if (axes) { :
#   the condition has length > 1 and only the first element will be used
# Calls: plot -> plot.default
# Warning in if (frame.plot) localBox(...) :
#   the condition has length > 1 and only the first element will be used
# Calls: plot -> plot.default

[editar] ctrf+F engañarme. Shane menciona acerca de esto en su comentario .

Lectura de datos puede ser más problemático de lo que piensa. Hoy he encontrado que si se utiliza read.csv () , si una línea en el archivo .csv está en blanco, read.csv () se salta automáticamente. Esto tiene sentido para la mayoría de las aplicaciones, pero si usted está extrayendo automáticamente los datos a partir de (por ejemplo) la fila 27 de varios miles de archivos, y algunas de las filas anteriores puede o no puede estar en blanco, si no estás cosas pueden ir muy cuidadosas incorrecto.

ahora uso

data1 <- read.table(file_name, blank.lines.skip = F, sep = ",")

Cuando se va a importar los datos, verificar que se está haciendo lo que realmente cree que está haciendo una y otra vez y otra vez ...

El comportamiento complicado de la función all.equal().

Una de mis errores continuos está comparando un conjunto de números de punto flotante. Tengo un CSV como:

... mu,  tau, ...
... 0.5, 1.7, ...

La lectura del archivo y tratar de crear un subconjunto de datos funciona a veces, a veces falla - por supuesto, debido a la caída en los hoyos de la trampa de punto flotante y otra vez. En un primer momento, los datos contienen sólo valores enteros, y más tarde en la que siempre se transforma en valores reales, que conoce la historia. Comparando se debe hacer con la función all.equal() en lugar del operador ==, pero por supuesto, el código escribí por primera vez utiliza este último método.

Sí, bueno, pero all.equal() devuelve TRUE para igual número, sino un mensaje de error si no textual:

> all.equal(1,1)
[1] TRUE
> all.equal(1:10, 1:5)
[1] "Numeric: lengths (10, 5) differ"
> all.equal(1:10, c(1:5,1:5))
[1] "Mean relative difference: 0.625"

La solución es utilizar la función isTRUE():

if (!isTRUE(all.equal(x, y, tolerance=doubleErrorRate))) {
    ...
}

¿Cuántas veces llegué a leer la descripción all.equals() ...

Éste dolía tanto que me pasé horas añadir comentarios a un bug-informe. No he tenido mi deseo, pero al menos la próxima versión de R generará un error.

R> nchar(factor(letters))
 [1] 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2

Actualización: A partir de R 3.2.0 (probablemente antes), este ejemplo ahora genera un mensaje de error. Como se mencionó en los comentarios a continuación, un factor que no es un vector y nchar () requiere un vector.

R> nchar(factor(letters))
Error in nchar(factor(letters)) : 'nchar()' requires a character vector
R> is.vector(factor(letters))
[1] FALSE
  1. accidentalmente listado de código fuente de una función por olvidar incluir paréntesis vacíos: por ejemplo, "LS" frente a "ls ()"

  2. true y false no la corte como constantes predefinidas, como en Matlab, C ++, Java, Python; debe utilizar VERDADERO Y FALSO

  3. valores de retorno invisibles: por ejemplo, ".Packages ()" devuelve nada, mientras que "(.packages ())" devuelve un vector de caracteres de los nombres de base de paquetes

Por ejemplo, el número 3,14 es una constante numérica, pero las expresiones +3,14 y -3,14 son las llamadas a las funciones + y -:

> class(quote(3.14))
[1] "numeric"
> class(quote(+3.14))
[1] "call"
> class(quote(-3.14))
[1] "call"

Vea la sección 13.2 en el libro de John Chambers software de Análisis de datos - Programación con R

vectores de longitud cero tienen algunas peculiaridades:

R> kk=vector(mode="numeric",length=0)
R> kk
numeric(0)
R> sum(kk)
[1] 0
R> var(kk)
[1] NA

coincidencia parcial en el operador $: Esto se aplica a las listas, sino también en data.frame

df1 <- data.frame(foo=1:10, foobar=10:1)
df2 <- data.frame(foobar=10:1)

df1$foo # Correctly gets the foo column
df2$foo # Expect NULL, but this returns the foobar column!!!

# So, should use double bracket instead:
df1[["foo"]]
df2[["foo"]]

El operador [[ también tiene una bandera exact, pero afortunadamente se TRUE por defecto.

coincidencia parcial también afecta attr:

x1 <- structure(1, foo=1:10, foobar=10:1)
x2 <- structure(2, foobar=10:1)

attr(x1, "foo") # Correctly gets the foo attribute
attr(x2, "foo") # Expect NULL, but this returns the foobar attribute!!!

# So, should use exact=TRUE
attr(x1, "foo", exact=TRUE)
attr(x2, "foo", exact=TRUE)

Trabajar con listas, hay un par de cosas poco intuitivos:

Por supuesto, la diferencia entre [ y [[ toma algún tiempo para acostumbrarse. Para las listas, la [ devuelve una lista de (1 potencialmente) elementos mientras que el [[ devuelve el elemento dentro de la lista.

Creación de lista:

# When you're used to this:
x <- numeric(5) # A vector of length 5 with zeroes
# ... this might surprise you
x <- list(5)    # A list with a SINGLE element: the value 5
# This is what you have to do instead:
x <- vector('list', 5) # A vector of length 5 with NULLS

Por lo tanto, la forma de insertar NULL en una lista?

x <- list("foo", 1:3, letters, LETTERS) # A sample list
x[[2]] <- 1:5        # Put 1:5 in the second element
# The obvious way doesn't work: 
x[[2]] <- NULL       # This DELETES the second element!
# This doesn't work either: 
x[2] <- NULL       # This DELETES the second element!

# The solution is NOT very intuitive:
x[2] <- list(NULL) # Put NULL in the second element

# Btw, now that we think we know how to delete an element:
x <- 1:10
x[[2]] <- NULL  # Nope, gives an ERROR!
x <- x[-2]    # This is the only way for atomic vectors (works for lists too)

Finalmente, algunas cosas avanzadas como la indexación a través de una lista anidada:

x <- list(a=1:3, b=list(c=42, d=13, e="HELLO"), f='bar')
x[[c(2,3)]] # HELLO (first selects second element and then it's third element)
x[c(2,3)]   # The second and third elements (b and f)

Una de las grandes confusiones en I es que [i, drop = TRUE] hace niveles del factor de caída, pero no lo hace [i, j, drop = TRUE]!

> df = data.frame(a = c("europe", "asia", "oceania"), b = c(1, 2, 3))
> df$a[1:2, drop = TRUE]
[1] europe asia  
Levels: asia europe          <---- drops factor levels, works fine
> df[1:2,, drop = TRUE]$a
[1] europe asia  
Levels: asia europe oceania  <---- does not drops factor levels!

Para más información ver: = TRUE no baja los niveles de factor de hoja.de.datos mientras que en el vector que hace

automática de repetición de vectores ( "reciclaje" ) utilizados como índices:

R> all.numbers <- c(1:5)
R> all.numbers
[1] 1 2 3 4 5
R> good.idxs <- c(T,F,T)
R> #note unfortunate length mismatch
R> good.numbers <- all.numbers[good.idxs]
R> good.numbers
[1] 1 3 4
R> #wtf? 
R> #why would you repeat the vector used as an index 
R> #without even a warning?

Desde lenguaje compilado y Matlab, que he recibido en ocasiones confundido acerca de un aspecto fundamental de las funciones de lenguajes funcionales: tienen que ser definido antes de que estén utiliza ! No es suficiente sólo para que puedan ser analizados por el intérprete de R. Esto levanta su cabeza sobre todo cuando se utiliza funciones anidadas.

En Matlab se puede hacer:

function f1()
  v1 = 1;
  v2 = f2();
  fprintf('2 == %d\n', v2);

  function r1 = f2()
    r1 = v1 + 1 % nested function scope
  end
end

Si intenta hacer lo mismo en R, usted tiene que poner en primer lugar la función anidada, o se produce un error! El hecho de que haya definido la función, que no está en el espacio de nombres hasta que se asigna a una variable! Por otro lado, la función puede hacer referencia a una variable que tiene no ha definido todavía.

f1 <- function() {
  f2 <- function() {
    v1 + 1
  }

  v1 <- 1

  v2 = f2()

  print(sprintf("2 == %d", v2))
}

mina a partir de hoy:. Qnorm () toma probabilidades y Pnorm () toma cuantiles

Para mí es la forma intuitiva de contador en el que al exportar un hoja.de.datos a un archivo de texto usando write.csv, a continuación, importarlo posteriormente necesita añadir un argumento adicional para obtener exactamente el mismo hoja.de.datos, como este :

write.csv(m, file = 'm.csv')
read.csv('m.csv', row.names = 1) # Note the row.names argument

También publicado esta pregunta en SO y fue sugerido como una respuesta a esta Q por @BenBolker.

El conjunto de funciones apply no sólo funciona para las matrices, pero escala hasta gama de multi-dimensional. En mi investigación que a menudo tienen un conjunto de datos de, por ejemplo, la temperatura de la atmósfera. Este se almacena en una matriz multidimensional con dimensiones x,y,level,time, de ahora en adelante llamado multi_dim_array. Un ejemplo maqueta sería:

multi_dim_array = array(runif(96 * 48 * 6 * 100, -50, 50), 
                        dim = c(96, 48, 6, 100))
> str(multi_dim_array)
#     x     y     lev  time    
 num [1:96, 1:48, 1:6, 1:100] 42.4 16 32.3 49.5 24.9 ...

El uso de apply uno puede fácilmente obtener el:

# temporal mean value
> str(apply(multi_dim_array, 4, mean))
 num [1:100] -0.0113 -0.0329 -0.3424 -0.3595 -0.0801 ...
# temporal mean value per gridcell (x,y location)
> str(apply(multi_dim_array, c(1,2), mean))
 num [1:96, 1:48] -1.506 0.4553 -1.7951 0.0703 0.2915 ...
# temporal mean value per gridcell and level (x,y location, level)
> str(apply(multi_dim_array, c(1,2,3), mean))
 num [1:96, 1:48, 1:6] -3.839 -3.672 0.131 -1.024 -2.143 ...
# Spatial mean per level
> str(apply(multi_dim_array, c(3,4), mean))
 num [1:6, 1:100] -0.4436 -0.3026 -0.3158 0.0902 0.2438 ...

Esto hace que el argumento margin a apply parece mucho menos contrario a la intuición. En primer lugar, sin embargo, por qué no usar "fila" y "col" en lugar de 1 y 2. Sin embargo, el hecho de que también trabaja para gran variedad de con más dimensiones deja claro por qué el uso se prefiere margin como este.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top