Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Introducción
Un data frame es un objeto de R que permite almacenar datos bidimensionales. Tienen
en común con las matrices que son objetos rectangulares, donde todas las columnas
deben tener la misma longitud pero, a diferencia de ellas, cada columna puede ser de
tipo numérico, carácter o lógico. De igual forma, pueden verse como una lista donde
todos sus elementos deben tener la misma longitud.
Un data frame, como un dataset de SPSS o de SAS, es un fichero rectangular con forma
de matriz donde la primera columna puede contener los nombres de los individuos y
la primera fila los nombres de las variables que se miden en cada caso. Sin embargo,
un data frame no es un fichero, sino un objeto.
Las columnas (variables) no numéricas en un data frame, son consideradas como
factores, con tantos niveles como valores distintos haya en los datos, salvo que se
indique otra cosa.
1
df<-data.frame(edad=EDAD,caso=CASO,sexo=SEXO)
df
## edad caso sexo
## 1 12 1 M
## 2 15 2 M
## 3 17 3 H
## 4 10 4 H
## 5 45 5 H
Ejemplo 2
resultados <- data.frame(
talla = c(185,172,165,177,168),
peso = c( 82, 70, 76, 52, 72),
QI = c(110,120, 92,120,142),
sexo = c("H","M","M", "M","H"),
row.names= c("Pablo", "Marta","Lola","Genoveva",
"Luis"))
resultados
## talla peso QI sexo
## Pablo 185 82 110 H
## Marta 172 70 120 M
## Lola 165 76 92 M
## Genoveva 177 52 120 M
## Luis 168 72 142 H
2
## peso sexo
## Genoveva 52 M
Como lista
Para trabajar con las variables (columnas) de un data.frame se puede utilizar la
notación estándar de las listas:
nombre_data_frame$nombre_columna
nombre_data_frame[[ ]]
Las dos formas son equivalentes, en el sentido de que muestran la misma información.
Sin embargo, no se obtiene el mismo objeto:
Ejemplo 3
df[3]
## sexo
## 1 M
## 2 M
## 3 H
## 4 H
## 5 H
dim(df[3])
## [1] 5 1
dim(df$sexo)
## NULL
3
## [1] -0.5438479 -0.3346756 -0.1952275 -0.6832961 1.7570471
detach(df)
IMPORTANTE
Una vez vinculado un data frame por medio de la función attach(), las
modificaciones hechas a las columnas por medio de las referencia de sus nombres no
afectan al data frame original. A efectos prácticos, al ejecutar attach(df), R realiza
una copia del data frame ‘df’ y es en esta copia donde se trabaja.
Por ejemplo, si se ejecuta
attach(df)
edad <- 2*edad
edad
## [1] 24 30 34 20 90
detach(df)
df$edad
## [1] 12 15 17 10 45
La función subset()
Permite seleccionar casos (filas). Su sintaxis es:
subset( data.frame, condición lógica, select=vector con nombres de
variables)
Ejemplo 5
df.2 <- subset(df,edad>14,select=c(edad,sexo))
df.2
## edad sexo
## 2 15 M
## 3 17 H
## 5 45 H
4
La función transform()
Para transformar unas determinadas columnas, o crear nuevas variables, se puede
utilizar la función transform(). Su sintaxis es:
transform(data.frame,variable1=f(variables),variable3=f(variables)...)
Ejemplo 6
En este ejemplo se transforma la variable edad y el resultado se almacena en un nuevo
data.frame llamado, ‘fd.3’.
df.3 <- transform(df,edad=edad*2)
df.3
## edad caso sexo
## 1 24 1 M
## 2 30 2 M
## 3 34 3 H
## 4 20 4 H
## 5 90 5 H
Para realizar la misma operación sin la función transform() bastaría con escribir
df$edad <- df$edad*2
Sin transform():
1. Construimos la variable: edad.n <- df$edad + 23
2. Añadimos la variable por medio del operador de asignación, “<-”:
df$edad.nueva <- edad.n
edad.n <- df$edad + 23
df$edad.nueva <- edad.n
df
## edad caso sexo edad.nueva
## 1 12 1 M 35
5
## 2 15 2 M 38
## 3 17 3 H 40
## 4 10 4 H 33
## 5 45 5 H 68
6
## 3 3 -0.373289418
## 4 4 1.454865506
## 5 5 2.337865196
## 6 6 0.755754004
## 7 7 -0.002642747
## 8 8 0.089793885
## 9 9 -0.751993936
## 10 10 -1.120777156
7
misdatos[,1] <- NULL
misdatos
## y
## 1 2.03991909
## 2 -1.03573444
## 3 -0.47634582
## 4 -0.13223154
## 5 -1.58930992
## 6 0.32940481
## 7 -0.08143549
## 8 0.20285406
## 9 0.19525307
## 10 -0.85672058
Los efectos de los dos métodos no son exactamente iguales. Estudia las diferencias.
Sintaxis
order(..., na.last = TRUE, decreasing = FALSE)
sort.list(x, partial = NULL, na.last = TRUE, decreasing = FALSE,
method = c("shell", "quick", "radix"))
Argumentos
… Una secuencia de vectores numéricos, complejos, de caracter o lógicos
todos de igual longitud o un objeto de clase R.x Un vector.
partial Vector de índices para una ordenación parcial. (Los valores nulos no se
utilizan)
decreasing Lógica. Determina si el orden es creciente o decreciente.
na.last Controla el tratamiento de los NAs. Si es TRUE, los valores missing se
colocan al final de los datos, si es FALSE, se colocan al principio de los
datos, si NA, se eliminan de los datos.
method El método a emplear. Los emparejamientos parciales están permitidos.
8
Detalles
En el caso de empates en el primer vector, se utilizarán los valores del segundo vector
para deshacer los empates. Si permanece el empate, los valores de los siguientes
argumentos se utilizaran para romper el empate. El tipo de ordenación (sort)
empleado es “stable” salvo para el método “quick” ( method = “quick”). Si quedara
algún empate sin resolver se dejarán en su orden original.
Los números complejos se ordenan primero según su parte real y luego por la parte
imaginaria. El orden de los vectores carácter dependerá de la secuencia local: ver
comparison.
El método por defecto para sort.list es un compromiso. El método “quick” se utiliza
únicamente para valores numéricos con la opción na.last=NA, y no es estable, sin
embargo es el más rápido en vectores grandes. El metodo “radix” esta únicamente
implementado para valores enteros menores de 100.000. En esta situación, es (muy)
estable. Es el método de elección para ordenar factores.
El método “partial” se mantiene para permitir la compatibilidad de otras
implementaciones de R, pero no permite otros valores y la ordenación será siempre
completa.
Ejemplo 9
# La función order() da como resultado los índices de ordenación.
# La función sort() da como resultado el objeto ordenado
# Vector carácter
c1 <- c("A","B","C","D")
sort(c1,decreasing = TRUE)
## [1] "D" "C" "B" "A"
order(c1)
## [1] 1 2 3 4
c2 <- c("A","D","C","B")
sort(c2,decreasing = TRUE)
## [1] "D" "C" "B" "A"
order(c2)
## [1] 1 4 3 2
# Vector numérico
x <- c(2,1:9)
x_sort <- sort(x)
9
x
## [1] 2 1 2 3 4 5 6 7 8 9
(indice <- order(x))
## [1] 2 1 3 4 5 6 7 8 9 10
x[indice]
## [1] 1 2 2 3 4 5 6 7 8 9
x_sort
## [1] 1 2 2 3 4 5 6 7 8 9
# Ordenar un data.frame
10
## 3 J 267 3
## 5 Z 123 3
# función xtfrm() es una función auxiliar que produce un vector numérico
que puede ser ordenado en el mismo orden que 'x'.
11
Combinar data frame
Dentro de los trabajos con data frame, una de las tareas más comunes es la fusión de
dos data frame. Las formas de fusionarlos son:
• Agregar filas: Dados los data frame X e Y agregar filas consiste en “pegar” las
filas de un conjunto de datos debajo del otro. Es lo que se conoce como unión
vertical y se realiza con la función rbind(X,Y).
• Agregar columnas: Dados los data frame X e Y agregar columnas consiste en
“pegar” las columnas de un conjunto de datos al lado del otro. Es lo que se conoce
como unión horizontal y se realiza con la función cbind(X,Y).
• Join o vlookup: Dados los data frame X e Y al primer data frame se le agrega el
contenido del segundo. Generalmente, los data frame presentan una o varias
variables que funcionan como campos claves o “keys”. Suponiendo que cada data
frame contiene al menos una key común a ambos, se pueden clasificar los join en:
i. Inner join. Devuelve únicamente los casos en los que la key se repite en
ambos data frame.
ii. Left join. Devuelve todos los casos del data frame de la izquierda y sólo los
casos del conjunto de la derecha que tiene una key que coincida con algún
elemento de la izquierda.
iii. Right join. Devuelve todos los casos del data frame de la derecha y sólo los
casos del conjunto de la izquierda que tiene una key que coincida con
algún elemento de la derecha.
iv. Full join. Devuelve todas las observaciones tanto del data frame de la
izquierda como de la derecha.
todos estos tipos de combinación de data frame se realizan con la función merge().
12
by.x = by, by.y = by, all = FALSE, all.x = all, all.y = all,
Argumentos
x, y data frames, u objetos que se van a combinar en un objeto
by, by.x, by.yespecificación de las columnas comunes.
all lógica; all = L es una abreviatura de all.x = L y all.y = L.
all.x lógica; si TRUE, se añade una fila extra a la salida, una fila por cada
fila en x que no tiene correspondencia con una fila en y. Estas filas
tendrán NAs en aquellas columnas que sean rellenado con campos de
y. El valor por defecto es FALSE, en este caso únicamente las filas con
datos en los dos data frame se incluirán en la salida.
all.y lógica; análoga a all.x -
sort lógica. El resultado se ordenará en función de las columnas
especificadas en by .
suffixes carácter(2) especifica los sufijos que se utilizaran para crear
nombres cuando los nombres especificados en by names() no sean
únicos.
incomparables Valores que no pueden ser emparejados. Ver match.
… Argumentos que son pasados a/de métodos.
Detalles
Por defecto los data frames se combinan en función de las columnas que en los dos
data frame tienen nombres comunes, pero se pueden especificar las columnas que se
quiere utilizar por medio de by.x y by.y, lo que permite realizar la unión sin que en
los dos data frame se utilicen los mismos nombres de columna.
Las columnas pueden especificarse por nombre, número o por medio de un vector
lógico, llamado row.names .El número 0 especifica la fila de nombres. Las filas en los
dos data frame que van a emparejarse son extraídas y juntadas. Si hay más de un
posible emparejamiento, se realizan tantos emparejamientos como sea posible y cada
uno de ellos genera una nueva fila. El significado preciso de ‘match’, se puede ver en
match.
Si by, by.x o by.y tiene longitud 0 (un vector de longitud cero o NULL), el resultado, r,
es el producto cartesiano de x e y, es decir, dim(r) = c(nrow(x)*nrow(y), ncol(x)
+ ncol(y)).
13
Las filas se ordenan por defecto según el orden lexicográfico entre las columnas
comunes, pero si la opción sort = FALSE se ordenarán en un orden no especificado.
Primero las columnas que son comunes, seguidas de las columnas de x e y. Si en el
emparejamiento se han especificado los nombres de las filas, se añade una columna
extra (carácter) a la izquierda que se llama row.names.
Dos data frame con variable clave común y con el mismo nombre
Ejemplo 10: Tabla de datos con una columna en común y con el mismo nombre.
# Data frame x
x <- data.frame(id=c(1,2,3,4,5),
nombre=c("José","Pilar","Nuria","Pepa","Antonio"),
edad=c(30,40,22,53,27),
peso=c(75,60,55,78,80))
x
## id nombre edad peso
## 1 1 José 30 75
## 2 2 Pilar 40 60
## 3 3 Nuria 22 55
## 4 4 Pepa 53 78
## 5 5 Antonio 27 80
#Data frame y
y <- data.frame(id=c(1,2,3,4,5),
carnet=c("si","si","si","no","no"),
estad.civil=c("soltero","casado","soltero","divorciado","soltero"),
hijos=c("no","si","no","si","no"),
n.hijos=c(NA,2,NA,1,NA))
y
14
## id carnet estad.civil hijos n.hijos
## 1 1 si soltero no NA
## 2 2 si casado si 2
## 3 3 si soltero no NA
## 4 4 no divorciado si 1
## 5 5 no soltero no NA
Los dos data frame tienen una columna en común, en el sentido que existe una
columna que tiene los mismos elementos en los dos objetos y además tiene el mismo
nombre. Para unirlas utilizamos el siguiente código:
merge(x,y,by="id")
## id nombre edad peso carnet estad.civil hijos n.hijos
## 1 1 José 30 75 si soltero no NA
## 2 2 Pilar 40 60 si casado si 2
## 3 3 Nuria 22 55 si soltero no NA
## 4 4 Pepa 53 78 no divorciado si 1
## 5 5 Antonio 27 80 no soltero no NA
Dos data frame con variable clave común y con nombre distinto
Ejemplos 11: Dos data frame con variable clave común y con nombre distinto
Vamos a trabajar con los data frame authors y books.
## use character columns of names to get sensible sort order
authors <- data.frame(
surname = I(c("Tukey", "Venables", "Tierney", "Ripley", "McNeil")),
nationality = c("US", "Australia", "US", "UK", "Australia"),
deceased = c("yes", rep("no", 4)))
15
"LISP-STAT",
"Spatial Statistics", "Stochastic Simulation",
"Interactive Data Analysis",
"An Introduction to R"),
other.author = c(NA, "Ripley", NA, NA, NA, NA,
"Venables & Smith"))
Lo data frame ‘authors’ y ‘books’ tiene en común la información del apellido del autor
de la obra. Sin embargo, en ‘authors’ esta variable se llama ‘surname’ y en ‘book’
‘name’.
Para unir estos dos data frame utilizaremos como campo clave estas variables.
Por medio de
• by.x = ??? se especifica el nombre de la variable en el primer data frame
(authors)
• by.y = ??? se especifica el nombre de la variable en el segundo data frame
(books)
Primero vamos a unir, authors con books:
(m1 <- merge(authors, books, by.x = "surname", by.y = "name"))
## surname nationality deceased title
other.author
## 1 McNeil Australia no Interactive Data Analysis
<NA>
## 2 Ripley UK no Spatial Statistics
<NA>
## 3 Ripley UK no Stochastic Simulation
<NA>
## 4 Tierney US no LISP-STAT
<NA>
## 5 Tukey US yes Exploratory Data Analysis
16
<NA>
## 6 Venables Australia no Modern Applied Statistics ...
Ripley
En este caso, primero aparecen las columnas (variables) del data frame ‘authors’
seguidos de las columnas del data frame ‘books’. El campo común, declarado en
by.x= y en by.y=es el que indexa el nuevo data frame y mantiene el nombre del
primer data frame. En este caso el nombre que aparece en el data frame ‘authors’ que
es name.
(m2 <- merge(books, authors, by.x = "name", by.y = "surname"))
## name title other.author nationality
deceased
## 1 McNeil Interactive Data Analysis <NA> Australia
no
## 2 Ripley Spatial Statistics <NA> UK
no
## 3 Ripley Stochastic Simulation <NA> UK
no
## 4 Tierney LISP-STAT <NA> US
no
## 5 Tukey Exploratory Data Analysis <NA> US
yes
## 6 Venables Modern Applied Statistics ... Ripley Australia
no
Si ahora unimos books con authors, primero aparecen las columnas (variables) del
data frame ‘books’ seguidos de los del data frame ‘authors’ indexados por la variable
surname que es el nombre de la columna común en el primer data frame de la unión.
17
#Data frame y
y <- data.frame(id=c(1,2,3,4,5),
carnet=c("si","si","si","no","no"),
estad.civil=c("soltero","casado","soltero","divorciado","soltero"),
hijos=c("no","si","no","si","no"),
n.hijos=c(NA,2,NA,1,NA),
peso=c(25,6,5,7,8))
y
## id carnet estad.civil hijos n.hijos peso
## 1 1 si soltero no NA 25
## 2 2 si casado si 2 6
## 3 3 si soltero no NA 5
## 4 4 no divorciado si 1 7
## 5 5 no soltero no NA 8
Al aparecer una misma variable en los dos data frame, al unirlos se crean dos
columnas una peso.x y la otra peso.y, indicando de esta forma de dónde procede cada
una de ellas.
merge(x,y, by="id")
## id nombre edad peso.x carnet estad.civil hijos n.hijos peso.y
## 1 1 José 30 75 si soltero no NA 25
## 2 2 Pilar 40 60 si casado si 2 6
## 3 3 Nuria 22 55 si soltero no NA 5
## 4 4 Pepa 53 78 no divorciado si 1 7
## 5 5 Antonio 27 80 no soltero no NA 8
Dos data frame sin una variable clave común como campo clave
Supongamos ahora que eliminamos del data frame la segunda fila. Es decir, los dos
data frame tienen una columna que se llama id pero que no coincide en el contenido.
y <- y[-2,]
y
## id carnet estad.civil hijos n.hijos peso
## 1 1 si soltero no NA 25
## 3 3 si soltero no NA 5
## 4 4 no divorciado si 1 7
## 5 5 no soltero no NA 8
18
## 3 4 Pepa 53 78 no divorciado si 1 7
## 4 5 Antonio 27 80 no soltero no NA 8
En la tabla de datos final no aparece el individuo 2 (de nombre “Pilar”). Por defecto, la
función merge() solo utiliza las filas que están en los dos data frame.
Este comportamiento se puede dirigir por medio de los argumentos: all,all.x y
all.y
Si se especifica:
• all=TRUE se utilizan todas las filas tanto del data frame x como del y.
• all.x=TRUE se utilizan todas las filas del data frame x.
• all.y=TRUE se utilizan todas las filas del data frame y.
Como se puede apreciar en el ejemplo, cuando se utilizan todas las filas los valores
faltantes se rellenan con NA.
19
Combinar más de dos data frame. La función Reduce()
La función merge permite unir dos tablas de datos, en el caso de querer unir más de
dos se puede repetir el procedimiento las veces que sea necesario. Sin embargo, la
función Reduce() automatiza este proceso.
Ejemplo 12
Se quieren unir los siguientes data frame,
A <- data.frame(id = c("A", "B", "C", "D"), edad = c(24, 25, 17, 19),
altura = c(180,190, 175, 165))
A
## id edad altura
## 1 A 24 180
## 2 B 25 190
## 3 C 17 175
## 4 D 19 165
B <- data.frame(gender = c("H", "H", "M", "M"), id = c("A", "B", "C",
"D"))
B
## gender id
## 1 H A
## 2 H B
## 3 M C
## 4 M D
C <- data.frame(id = c("A", "B", "C", "D"),
mates = c(6.5, 8.9, 7.4, 9.2),
ciencias = c(7.2,8.4, 6.5, 8.7))
C
## id mates ciencias
## 1 A 6.5 7.2
## 2 B 8.9 8.4
## 3 C 7.4 6.5
## 4 D 9.2 8.7
20
ABC <- merge (AB,C)
ABC
## id edad altura gender mates ciencias
## 1 A 24 180 H 6.5 7.2
## 2 B 25 190 H 8.9 8.4
## 3 C 17 175 M 7.4 6.5
## 4 D 19 165 M 9.2 8.7
La función Reduce() permite aplicar una función binaria, en este caso merge(),
sucesivamente a los elementos de una lista.
Dos posibilidades,
duplicated(df)
## [1] FALSE TRUE FALSE FALSE FALSE TRUE FALSE TRUE
df[duplicated(df), ]
## a b
## 2 A 1
21
## 6 B 1
## 8 C 2
df[!duplicated(df), ]
## a b
## 1 A 1
## 3 A 2
## 4 B 4
## 5 B 1
## 7 C 2
O utilizar la función
unique(df)
## a b
## 1 A 1
## 3 A 2
## 4 B 4
## 5 B 1
## 7 C 2
donde
Nombre Descripción
x vector o data frame que contiene los datos
f factor en el sentido de variable que define los grupos. Permite iteraciones.
drop variable lógica. Si toma el valor TRUE no utiliza los valores de f que no
estén presentes en x.
value lista de vectores o data frames compatibles con la división de x en función
de f.
… argumentos opcionales pasados por los methods.
22
Ejemplo 14
Se quiere dividir el data frame iris en función de la variable Specie.
#Data frame iris
head(iris)
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1 5.1 3.5 1.4 0.2 setosa
## 2 4.9 3.0 1.4 0.2 setosa
## 3 4.7 3.2 1.3 0.2 setosa
## 4 4.6 3.1 1.5 0.2 setosa
## 5 5.0 3.6 1.4 0.2 setosa
## 6 5.4 3.9 1.7 0.4 setosa
dividido <- split(x = iris, f = iris$Species)
str(dividido)
## List of 3
## $ setosa :'data.frame': 50 obs. of 5 variables:
## ..$ Sepal.Length: num [1:50] 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
## ..$ Sepal.Width : num [1:50] 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1
...
## ..$ Petal.Length: num [1:50] 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5
...
## ..$ Petal.Width : num [1:50] 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1
...
## ..$ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1
1 1 1 1 1 1 1 ...
## $ versicolor:'data.frame': 50 obs. of 5 variables:
## ..$ Sepal.Length: num [1:50] 7 6.4 6.9 5.5 6.5 5.7 6.3 4.9 6.6 5.2
...
## ..$ Sepal.Width : num [1:50] 3.2 3.2 3.1 2.3 2.8 2.8 3.3 2.4 2.9 2.7
...
## ..$ Petal.Length: num [1:50] 4.7 4.5 4.9 4 4.6 4.5 4.7 3.3 4.6 3.9
...
## ..$ Petal.Width : num [1:50] 1.4 1.5 1.5 1.3 1.5 1.3 1.6 1 1.3 1.4
...
## ..$ Species : Factor w/ 3 levels "setosa","versicolor",..: 2 2 2
2 2 2 2 2 2 2 ...
## $ virginica :'data.frame': 50 obs. of 5 variables:
## ..$ Sepal.Length: num [1:50] 6.3 5.8 7.1 6.3 6.5 7.6 4.9 7.3 6.7 7.2
...
## ..$ Sepal.Width : num [1:50] 3.3 2.7 3 2.9 3 3 2.5 2.9 2.5 3.6 ...
## ..$ Petal.Length: num [1:50] 6 5.1 5.9 5.6 5.8 6.6 4.5 6.3 5.8 6.1
...
## ..$ Petal.Width : num [1:50] 2.5 1.9 2.1 1.8 2.2 2.1 1.7 1.8 1.8 2.5
...
## ..$ Species : Factor w/ 3 levels "setosa","versicolor",..: 3 3 3
3 3 3 3 3 3 3 ...
length(dividido)
23
## [1] 3
lista.Setosa <- dividido[1]
str(lista.Setosa)
## List of 1
## $ setosa:'data.frame': 50 obs. of 5 variables:
## ..$ Sepal.Length: num [1:50] 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
## ..$ Sepal.Width : num [1:50] 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1
...
## ..$ Petal.Length: num [1:50] 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5
...
## ..$ Petal.Width : num [1:50] 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1
...
## ..$ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1
1 1 1 1 1 1 1 ...
cuadro.Setosa <- dividido[[1]]
str(cuadro.Setosa)
## 'data.frame': 50 obs. of 5 variables:
## $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
## $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
## $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
## $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
## $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1
1 1 1 1 1 1 ...
24