Solo leer columnas seleccionadas

134

¿Alguien puede decirme cómo leer solo los primeros 6 meses (7 columnas) para cada año de los datos a continuación, por ejemplo utilizando read.table()?

Year   Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  Nov  Dec   
2009   -41  -27  -25  -31  -31  -39  -25  -15  -30  -27  -21  -25
2010   -41  -27  -25  -31  -31  -39  -25  -15  -30  -27  -21  -25 
2011   -21  -27   -2   -6  -10  -32  -13  -12  -27  -30  -38  -29
StarCub
fuente
55
¿Es un duplicado de Formas de leer solo columnas seleccionadas de un archivo en R? , Dirk menciona NULLcomo una clase de columna en su respuesta .
Marek
stats.stackexchange.com/questions/16796/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
2
@CiroSantilli 包子 露 宪 六四 事件 法轮功 seguro pero ... pregunté primero?
StarCub
No estaba implicando una relación mejor / peor. Además, no hay duplicados entre sitios, la red de intercambio de pila inconsistente los permite, a menos que se publique de forma cruzada :-)
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Respuestas:

157

Digamos que los datos están en el archivo data.txt, puede usar el colClassesargumento de read.table()para omitir columnas. Aquí los datos en las primeras 7 columnas son "integer"y configuramos las 6 columnas restantes para "NULL"indicar que deben omitirse

> read.table("data.txt", colClasses = c(rep("integer", 7), rep("NULL", 6)), 
+            header = TRUE)
  Year Jan Feb Mar Apr May Jun
1 2009 -41 -27 -25 -31 -31 -39
2 2010 -41 -27 -25 -31 -31 -39
3 2011 -21 -27  -2  -6 -10 -32

Cambie "integer"a uno de los tipos aceptados según se detalla en ?read.tablefunción del tipo real de datos.

data.txt Se ve como esto:

$ cat data.txt 
"Year" "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"
2009 -41 -27 -25 -31 -31 -39 -25 -15 -30 -27 -21 -25
2010 -41 -27 -25 -31 -31 -39 -25 -15 -30 -27 -21 -25
2011 -21 -27 -2 -6 -10 -32 -13 -12 -27 -30 -38 -29

y fue creado usando

write.table(dat, file = "data.txt", row.names = FALSE)

donde datesta

dat <- structure(list(Year = 2009:2011, Jan = c(-41L, -41L, -21L), Feb = c(-27L, 
-27L, -27L), Mar = c(-25L, -25L, -2L), Apr = c(-31L, -31L, -6L
), May = c(-31L, -31L, -10L), Jun = c(-39L, -39L, -32L), Jul = c(-25L, 
-25L, -13L), Aug = c(-15L, -15L, -12L), Sep = c(-30L, -30L, -27L
), Oct = c(-27L, -27L, -30L), Nov = c(-21L, -21L, -38L), Dec = c(-25L, 
-25L, -29L)), .Names = c("Year", "Jan", "Feb", "Mar", "Apr", 
"May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"), class = "data.frame",
row.names = c(NA, -3L))

Si el número de columnas no se conoce de antemano, la función de utilidad count.fieldsleerá el archivo y contará el número de campos en cada línea.

## returns a vector equal to the number of lines in the file
count.fields("data.txt", sep = "\t")
## returns the maximum to set colClasses
max(count.fields("data.txt", sep = "\t"))
Gavin Simpson
fuente
1
@Benjamin Lea el primer par de líneas del archivo utilizando argumentos nrows. Luego calcule cuántas columnas está usando ncol(), o de lo contrario desea calcular la cantidad de columnas para leer / ignorar. Luego lea el archivo completo con esta información.
Gavin Simpson
1
?? Si no conoce el número de columnas, ¿de qué otra manera lo determinará sin leer un poco para deducir cuántas hay?
Gavin Simpson
1
@BlueMagister Gracias por la edición y la mención de lo count.fields()que automatiza el proceso que sugerí en los comentarios.
Gavin Simpson
1
@ LéoLéopoldHertz 준영 No, y no estoy seguro de cómo funcionaría tal cosa para las clases de fila como en un marco de datos, mientras que cada columna puede ser de un tipo diferente, cada fila es, por definición y como resultado, sin restricciones. Deberá filtrar las filas en blanco, etc. al importar.
Gavin Simpson
1
@rmf puede pasar count.fields()una conexión de texto, entonces, lea un subconjunto de las filas usando txt <- readLines(....), luego cree una conexión a la lectura en líneas con <- textConnection(txt), luego haga count.fields(txt). Asegúrese de utilizar skipen count.fields()saltarse la fila de encabezado si hay uno; no puede omitir filas en el archivo usando readLines().
Gavin Simpson el
82

Para leer un conjunto específico de columnas de un conjunto de datos, hay varias otras opciones:

1) Con freaddesde el data.tablepaquete:

Puede especificar las columnas que desee con el selectparámetro a partir freaddel data.tablepaquete. Puede especificar las columnas con un vector de nombres de columna o números de columna.

Para el conjunto de datos de ejemplo:

library(data.table)
dat <- fread("data.txt", select = c("Year","Jan","Feb","Mar","Apr","May","Jun"))
dat <- fread("data.txt", select = c(1:7))

Alternativamente, puede usar el dropparámetro para indicar qué columnas no deben leerse:

dat <- fread("data.txt", drop = c("Jul","Aug","Sep","Oct","Nov","Dec"))
dat <- fread("data.txt", drop = c(8:13))

Todo resulta en:

> data
  Year Jan Feb Mar Apr May Jun
1 2009 -41 -27 -25 -31 -31 -39
2 2010 -41 -27 -25 -31 -31 -39
3 2011 -21 -27  -2  -6 -10 -32

ACTUALIZACIÓN: cuando no desee freaddevolver una tabla de datos , use el parámetro -pordata.table = FALSE ejemplo:fread("data.txt", select = c(1:7), data.table = FALSE)

2) Con read.csv.sqldesde el sqldfpaquete:

Otra alternativa es la read.csv.sqlfunción del sqldfpaquete:

library(sqldf)
dat <- read.csv.sql("data.txt",
                    sql = "select Year,Jan,Feb,Mar,Apr,May,Jun from file",
                    sep = "\t")

3) Con las read_*-funciones del -paquete readr:

library(readr)
dat <- read_table("data.txt",
                  col_types = cols_only(Year = 'i', Jan = 'i', Feb = 'i', Mar = 'i',
                                        Apr = 'i', May = 'i', Jun = 'i'))
dat <- read_table("data.txt",
                  col_types = list(Jul = col_skip(), Aug = col_skip(), Sep = col_skip(),
                                   Oct = col_skip(), Nov = col_skip(), Dec = col_skip()))
dat <- read_table("data.txt", col_types = 'iiiiiii______')

De la documentación, una explicación de los caracteres utilizados con col_types:

cada carácter representa una columna: c = carácter, i = entero, n = número, d = doble, l = lógico, D = fecha, T = fecha y hora, t = hora,? = adivinar, o _ / - para omitir la columna

Jaap
fuente
freadSin embargo, no admite archivos comprimidos. Los archivos grandes generalmente están comprimidos.
CoderGuy123
Hay una solicitud de función para habilitar esto en fread. Vale la pena notar que freades muy probable que lea el archivo sin comprimir considerablemente más rápido que read.tableel archivo comprimido. Ver aquí para un ejemplo .
Jaap
Algunos archivos sin comprimir son demasiado grandes. Por ejemplo, estoy trabajando con 1000 archivos Genomes. Pueden ser 60 GB sin comprimir.
CoderGuy123
1
Como probablemente sepa, R lee los datos en la memoria. Si lees el archivo comprimido o el archivo descomprimido no hace una diferencia en el tamaño de los datos resultantes en la memoria. Si tiene 60 GB en archivos, read.tableno lo salvará. En ese caso, es posible que desee ver el ffpaquete.
Jaap
2
@Deleet Se puede usar freadpara leer grandes archivos comprimidos como esto: fread("gunzip -c data.txt.gz", drop = c(8:13)).
arekolek
8

También podría usar JDBC para lograr esto. Creemos un archivo csv de muestra.

write.table(x=mtcars, file="mtcars.csv", sep=",", row.names=F, col.names=T) # create example csv file

Descargue y guarde el controlador CSV JDBC desde este enlace: http://sourceforge.net/projects/csvjdbc/files/latest/download

> library(RJDBC)

> path.to.jdbc.driver <- "jdbc//csvjdbc-1.0-18.jar"
> drv <- JDBC("org.relique.jdbc.csv.CsvDriver", path.to.jdbc.driver)
> conn <- dbConnect(drv, sprintf("jdbc:relique:csv:%s", getwd()))

> head(dbGetQuery(conn, "select * from mtcars"), 3)
   mpg cyl disp  hp drat    wt  qsec vs am gear carb
1   21   6  160 110  3.9  2.62 16.46  0  1    4    4
2   21   6  160 110  3.9 2.875 17.02  0  1    4    4
3 22.8   4  108  93 3.85  2.32 18.61  1  1    4    1

> head(dbGetQuery(conn, "select mpg, gear from mtcars"), 3)
   MPG GEAR
1   21    4
2   21    4
3 22.8    4
Rahul Premraj
fuente
0

Lo haces así:

df = read.table("file.txt", nrows=1, header=TRUE, sep="\t", stringsAsFactors=FALSE)
colClasses = as.list(apply(df, 2, class))
needCols = c("Year", "Jan", "Feb", "Mar", "Apr", "May", "Jun")
colClasses[!names(colClasses) %in% needCols] = list(NULL)
df = read.table("file.txt", header=TRUE, colClasses=colClasses, sep="\t", stringsAsFactors=FALSE)
tedtoal
fuente