Sunteți pe pagina 1din 8

12/11/2019 Bucles anidados en R - Stack Overflow en español

Bucles anidados en R
Formulada hace 1 año y 6 meses Activa hace 1 año y 6 meses Vista 773 veces

Tengo 3 dataframe que contienen la siguiente información:

df1
2
COD LON LAT ALT
C037 -289.976 432.165 162
E000 -274.107 430.783 218
C068 -228.623 428.395 596

df2 #Tantos datos por COD como fechas (que están contenidas en el df3)

C037 C038 G0E7 G0E9 G0EA G0F0 G0F4 G0E5 G0B6 G0C1
-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
1.456 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999

df3 #Fechas desde el 01/01/2000 hasta el 31/12/2015 (5844 registro)

Date
01/01/2000
02/01/2000
03/01/2000
04/01/2000
05/01/2000
06/01/2000
07/01/2000
08/01/2000
09/01/2000
10/01/2000
11/01/2000
12/01/2000
13/01/2000
14/01/2000

Tengo que hacer un bucle para crear una matriz final que contenga

FECHA COD ALT LAT LON datosdf2


01/01/2000 C037 -289.976 432.165 162 -9999
02/01/2000 C037 -289.976 432.165 162 1.456

Así sucesivamente
Al usar este rellenar
sitio, reconoces haber leidolos registros nuestra
y entendido del df2Política
para cada día hasta
de Cookies el 31/12/2015.
, Política de Privacidad, y nuestros
Términos de Servicio.

https://es.stackoverflow.com/questions/164497/bucles-anidados-en-r 1/8
12/11/2019 Bucles anidados en R - Stack Overflow en español

01/01/2000 E000 -274.107 430.783 218 -9999

Hacer lo mismo para 200 códigos más

Estoy intentando algo así, pero sinceramente no sé si está bien o no, nunca he hecho este tipo de
cosas en R

Creo que tengo que hacer algo del tipo:

for (i in 1:nrow(df1))
for (j in 1:ncol(df2)){
if (df1(i,1)==(df2(1,j)){ #Esto es, si el COD del df1 coincide con el COD del
df 2 (que estaría en la fila 1, columna 1), entonces que tome los valores
registrados en el df2
print ("i is 1", "1 is j")

En este punto no sé cómo indicarle que tome los registros de las fechas y los añada a la matriz...
Tampoco sé cómo hacer para indicarle al programa que cuando tenga que tomar el siguiente COD,
me añanda nuevamente las fechas desde 01/01/2000 sin machacarme las que ya tiene registradas
antes.

Espero que entiendan lo que quiero decir y lo que debo conseguir al final. Gracias por la ayuda que
me puedan dar.

r bucle-for bucles

editada el 15 may. 18 a las 14:03 formulada el 15 may. 18 a las 8:50


Patricio Moracho Caro
30.4k 6 23 51 368 1 10

Hola Carolina, bienvenida. ¿Necesitas forzosamente hacerlo con un bucle por algún otro motivo? Si en cada
data.frame tienes una columna con un código que está presente en los demás, una alternativa mucho mejor
sería hacer una operación que se llama join. La función base merge , debería ser muy fácil de escribir y no
tendrías que reinventar la rueda... De nuevo, bienvenida. – mpaladino el 15 may. 18 a las 14:14

Si, tengo que usar un bucle con sentencias condicionales pero estoy super perdida. if (df1(i,1)==(df2(1,j)) Este
paso no me sale, me da error... – Caro el 16 may. 18 a las 10:43

3 respuestas

Hola el siguiente código te puede ayudar, se utiliza el tidyverse en lugar de bucles

1 library(tidyverse)

dt1<-tribble(
~COD , ~LON, ~LAT, ~ALT,
"C037", -289.976, 432.165, 162,
"E000", -274.107, 430.783, 218,
Al usar este sitio,
"C038",reconoces haber leido
-228.623, y428.395,
entendido nuestra Política de
596#Agregue Cookies, Política de Privacidad, y nuestros
C038
)
Términos de Servicio.

https://es.stackoverflow.com/questions/164497/bucles-anidados-en-r 2/8
12/11/2019 Bucles anidados en R - Stack Overflow en español
dt2<-tribble(#una parte de tu ejemplo
~C037, ~C038,
-9999, -9999,
1.456, -9999,
-9999, -9999,
-9999, -9999
)

dt3<-tribble(
~Date,
"01/01/2000",
"02/01/2000",
"03/01/2000",
"04/01/2000"
)

#Primero si hay tantas fechas como datos en dt2, los combinamos

dt4<-cbind(dt3,dt2)
dt4
Date C037 C038
1 01/01/2000 -9999.000 -9999
2 02/01/2000 1.456 -9999
3 03/01/2000 -9999.000 -9999
4 04/01/2000 -9999.000 -9999

n<-ncol(dt4)#Numero de columnas en dt4


#Pasamos los nombres de las columnas a una nueva variable "COD"
#Las observaciones de cada COD por fecha se pasan a la variable "VALUE"
dt4<-gather(dt4, "COD", "VALUE", 2:n)
dt4
Date COD VALUE
1 01/01/2000 C037 -9999.000
2 02/01/2000 C037 1.456
3 03/01/2000 C037 -9999.000
4 04/01/2000 C037 -9999.000
5 01/01/2000 C038 -9999.000
6 02/01/2000 C038 -9999.000
7 03/01/2000 C038 -9999.000
8 04/01/2000 C038 -9999.000

#Agregamos dagtos de lat, lon, alt por cordenada


#La siguiente funcion agrega los datos sólo a las cordenadas presentes en dt4
dt5<-left_join(dt4,dt1,"COD")
dt5
Date COD VALUE LON LAT ALT
1 01/01/2000 C037 -9999.000 -289.976 432.165 162
2 02/01/2000 C037 1.456 -289.976 432.165 162
3 03/01/2000 C037 -9999.000 -289.976 432.165 162
4 04/01/2000 C037 -9999.000 -289.976 432.165 162
5 01/01/2000 C038 -9999.000 -228.623 428.395 596
6 02/01/2000 C038 -9999.000 -228.623 428.395 596
7 03/01/2000 C038 -9999.000 -228.623 428.395 596
8 04/01/2000 C038 -9999.000 -228.623 428.395 596

#Se puede usar full join para unir todos los datos pero quedarian sin fecha
full_join(dt4,dt1,"COD")
Date COD VALUE LON LAT ALT
1 01/01/2000 C037 -9999.000 -289.976 432.165 162
2 02/01/2000 C037 1.456 -289.976 432.165 162
3 03/01/2000 C037 -9999.000 -289.976 432.165 162
4 04/01/2000 C037 -9999.000 -289.976 432.165 162
5 01/01/2000
Al usar este C038
sitio, reconoces -9999.000
haber -228.623nuestra
leido y entendido 428.395 596 de Cookies, Política de Privacidad, y nuestros
Política
6 02/01/2000 C038 -9999.000 -228.623 428.395 596
Términos7de03/01/2000
Servicio. C038 -9999.000 -228.623 428.395 596

https://es.stackoverflow.com/questions/164497/bucles-anidados-en-r 3/8
12/11/2019 Bucles anidados en R - Stack Overflow en español
8 04/01/2000 C038 -9999.000 -228.623 428.395 596
9 <NA E000 NA -274.107 430.783 218

respondida el 15 may. 18 a las 14:43


Rolando Tamayo
934 3 18

Si te obligan que lo hagas con bucles y condicionales es posible. Coincido que un join es la mejor
opción, pero se puede hacer con estructuras de control explícitas.
1
Los datos

Sería muy importante que confirmes que tus datos tienen la estructura que los que se están
usando de ejemplo y test en este hilo. Por "la misma estructura" me refiero a que tienen las
mismas filas y columnas con el mismo tipo de datos en cada una. Caso contrario el código no va
a funcionar.

Retomo los datos que creó Rolando, aunque le cambio los nombres.

library(tidyverse)

df1 <- tribble(


~COD , ~LON, ~LAT, ~ALT,
"C037", -289.976, 432.165, 162,
"E000", -274.107, 430.783, 218,
"C038", -228.623, 428.395, 596#Agregue C038
)

df2 <- tribble(#una parte de tu ejemplo


~C037, ~C038,
-9999, -9999,
1.456, -9999,
-9999, -9999,
-9999, -9999
)

df3 <- tribble(


~Date,
"01/01/2000",
"02/01/2000",
"03/01/2000",
"04/01/2000"
)

El bucle con el que lo estabas intentando

La insistencia en que un join es mejor que un bucle va a estar clara acá: uno de los problemas de
los bucles es que tenés "decir" explícitamete qué hacer en cada paso y luego dónde y cómo ir
guardando el resultado. Por eso corresponden a un paradigma de programación imperativo. El join
sería una operación del paradigma declarativo, le indicas a tu función cuál es el resultado que
buscas
Al usar este sitio,yreconoces
la funcionhaber
se enarga
leido y del trabajonuestra
entendido engorroso.
Política de Cookies, Política de Privacidad, y nuestros
Términos de Servicio.
Ahora bien, ¿por qué no funciona tu bucle?
https://es.stackoverflow.com/questions/164497/bucles-anidados-en-r 4/8
12/11/2019 Bucles anidados en R - Stack Overflow en español

1. Tiene problemas de sintaxis. Le faltan algunos símbolos para ordenar el código y el intérprete
semántico (parser) de R se pierde y no sabe que hacer. La sintaxis básica de un bucle for es:

for (indice in iterador) {hacer_algo_con_índice}

Dada esta sintaxis a tu código le faltan una llave { abriendo dentro del primer bucle y dos llaves }
cerrando al final. Eso sin contar las llaves del if .

2. El subset o creación de subconjuntos de datos en R se hace -entre otras maneras, pero esta es
la más usual- con los símbolos [ ] , corchetes. En la línea tres de tu código estás usando
paréntesis ( ) . Al usar paréntesis le estás diciento a R que lo que está detrás es una función,
no una estructura de datos. Entonces R intenta ejecutar la función df1 con los argumentos
(i, 1) . Obviamente falla, porque no existe tal función.

3. El output. Usando un bucle for es necesario explicitar a dónde se va a guardando lo que


quieres que te devuelva al final. En términos más técnicos: ir asignando el valor de salida en
una nueva estructura de datos. En tu código no hay nada de esto, por lo tanto aún si funcionara
a la perfección no te regresaría nada al final. Haría el procesamiento, pero el resultado se
perdería. Veo que incluyes un print "al final" de tu bucle. Puede ser que eso sea lo que
quieres, que el bucle sólo regrese en pantalla el resultado. Es estaría bien para un usuario
humano que está leyendo la pantalla, pero no te crearía unos datos de output que pudieras
seguir usando después de procesar el bucle. En términos técnicos produce un efecto colateral
(side effect), pero no un output propiamente dicho.

En la solución de más abajo eso es lo que hacen los cbind() y rbind() de x , y , z y out , ir
armando paso a paso el output final.

4. El print de la línea 4 no va a regresar nada. Aún si funcionara agregando la función paste


para que concatene las cadenas de caracteres entrecomilladas te regresaría siempre una
constante: "i is 11 is j" . No tiene mucho caso hacer un bucle para que regrese siempre lo
mismo :). Además, como vimos en punto anterior, lo que te interesa es obtener una estructura
de datos al final, no la impresión en pantalla. Así que print no se usa, excepto quizás para hacer
debuggin del código o como ayuda mientras lo estás construyendo.

for (i in 1:nrow(df1)) #Falta una llave abriendo, si no R no sabe


cuando comienza el bucle
for (j in 1:ncol(df2)){ #Es está "bien"
if (df1(i,1)==(df2(1,j)){ #En df1(i, 1) debería ser df1[i,1]
print ("i is 1", "1 is j") #Acá no hay output, de hecho no hay nada.

¿Cómo funcionaría un bucle?

Voy a crear el bucle dentro de una función, para no modificar ni crear estructuras temporales en el
entorno global. La funcion se va a llamar unir y sirve solamente para est problema u otro
exactamente igual. La idea de esto de ver cuan penoso es solucionar este problema con bucles y
cuanto más vale la pena invertir tiempo en aprender a usar joins que escribir un bucle que haga lo
mismo.

No soluciona el problema de las fechas, para eso abría que abrir otro for y otro if . Ya es
suficientemente complicado como está.
Al usar este sitio, reconoces haber leido y entendido nuestra Política de Cookies, Política de Privacidad, y nuestros
No dudo que haya una mejor manera de hacerlo con bucles, pero de todos modos no tiene caso
Términos de Servicio.
mejorarlo, los bucles son una solución suboptima desde cualquier punto de vista.
https://es.stackoverflow.com/questions/164497/bucles-anidados-en-r 5/8
12/11/2019 Bucles anidados en R - Stack Overflow en español

unir <- function (df1, df2){


out <- data.frame()
for (i in 1:nrow(df1)) {
for (j in 1:ncol(df2)) {
if (df1[i,1] == colnames(df2)[j]) {
x <- as.vector(df1[i,])
y <- as.vector(df2[ ,j]) #Porque si no sale un data.frame
for (k in 1:length(y)){ #Itero dentro del vector
z <- rbind(cbind(x, y[k])) #Armo la estructura de datos
names(z)[ncol(z)] <- "dato_que_interesa_unir" #Porque en cada
ciclo hereda un nombre diferente
}
}
}
out <- rbind(out, z) #Uno recursivamente el resultado de
cada ciclo del segundo for
}
return(out)
}

unir (df1, df2)

# Resultado

> unir(df1, df2)


COD LON LAT ALT dato_que_interesa_unir
1 C037 -289.976 432.165 162 -9999.000
2 C037 -289.976 432.165 162 1.456
3 C037 -289.976 432.165 162 -9999.000
4 C037 -289.976 432.165 162 -9999.000
5 C037 -289.976 432.165 162 -9999.000
6 C037 -289.976 432.165 162 1.456
7 C037 -289.976 432.165 162 -9999.000
8 C037 -289.976 432.165 162 -9999.000
9 C038 -228.623 428.395 596 -9999.000
10 C038 -228.623 428.395 596 -9999.000
11 C038 -228.623 428.395 596 -9999.000
12 C038 -228.623 428.395 596 -9999.000

Conclusión
merge y join sí, bucles no .

respondida el 16 may. 18 a las 17:55


mpaladino
2,503 4 12

Me genera algo así como fichero de salida..... X.COD. X.LON. X.LAT. X.ALT. X.y.k.. 1 COD LON LAT ALT y[k] 2
COD LON LAT ALT y[k] 3 COD LON LAT ALT y[k] – Caro el 18 may. 18 a las 11:02

En general, en R se suele tratar de evitar el uso de los ciclos explícitos, es decir el for o el while ,
para ciertas operaciones. Esto, por que en muchos casos, resulta mucho más performante, sencillo
0 y claro, trabajar directamente con la funcionalidad base del lenguaje que ya está preparada para las
manipulaciones
Al usar este que
sitio, reconoces deberemos
haber que hacer.
leido y entendido nuestra Política de Cookies, Política de Privacidad, y nuestros
Términos de Servicio.

https://es.stackoverflow.com/questions/164497/bucles-anidados-en-r 6/8
12/11/2019 Bucles anidados en R - Stack Overflow en español

En primer lugar vamos a importar los datos de tu ejemplo. Achiqué un poco la muestra para que
todos los data.frame sean consistentes entre sí y para que el ejemplo quede más claro:

df1 <- read.table(text="COD LON LAT ALT


C037 -289.976 432.165 162
E000 -274.107 430.783 218
C068 -228.623 428.395 596", header= T, stringsAsFactors=F)

# Achicamos la muestra para que sea consistente con los códigos en df1
df2 <- read.table(text="C037 E000 C068
-1999 -9999 -9991
1.456 -9998 -9992
-2999 -9997 -9993
-3999 -9996 -9994", header= T, stringsAsFactors=F)

# Dejamos solo 4 valores de fecha para que sea consistente con las 4 filas de
df2
df3 <- read.table(text="Date
01/01/2000
02/01/2000
03/01/2000
04/01/2000", header= T, stringsAsFactors=F)

La solución

# Agregamos la columna de fecha. Aquí se asume que el orden de df2 es el


# mismo que tiene df3.
df2$Fecha <- df3$Date

# Modificamos el formato de df2 "ancho" a "largo"


df4 <- reshape(df2,
varying = list(names(df2[1:ncol(df2)-1])),
direction = "long",
v.names="VALOR")

#Renombramos valores de columnas y nos quedamos con las que nos interesan
df4$COD=colnames(df2)[df4$time]
df4 <- df4[, c(1, 5, 3)]

# Hacemos un merge final de los dos dataframe


df_final <- merge(df1, df4, by="COD", all=T)

df_final

Explicación:

Básicamente lo que hacemos es hacer consistente la estructura de df2 a la estructura de df1 , es


decir, dónde cada fila será un COD y una Fecha , si vemos como nos queda df4 luego del
reshape() y el resto de las normalizaciones antes del merge() resultará mas claro:

Fecha COD VALOR


1.1 01/01/2000 C037 -1999.000
2.1 02/01/2000 C037 1.456
3.1 03/01/2000 C037 -2999.000
4.1 04/01/2000 C037 -3999.000
1.2 01/01/2000 E000 -9999.000
2.2 02/01/2000 E000 -9998.000
Al usar este
3.2sitio, reconocesE000
03/01/2000 haber-9997.000
leido y entendido nuestra Política de Cookies, Política de Privacidad, y nuestros
4.2 04/01/2000
Términos de Servicio. E000 -9996.000
1.3 01/01/2000 C068 -9991.000
https://es.stackoverflow.com/questions/164497/bucles-anidados-en-r 7/8
12/11/2019 Bucles anidados en R - Stack Overflow en español
2.3 02/01/2000 C068 -9992.000
3.3 03/01/2000 C068 -9993.000
4.3 04/01/2000 C068 -9994.000

Como se vé, convertimos todo lo que era columna en fila, y ahora es bien sencillo, aplicar un
merge() para "combinar" df1 y df4 , la salida final:

COD LON LAT ALT Fecha VALOR


1 C037 -289.976 432.165 162 01/01/2000 -1999.000
2 C037 -289.976 432.165 162 02/01/2000 1.456
3 C037 -289.976 432.165 162 03/01/2000 -2999.000
4 C037 -289.976 432.165 162 04/01/2000 -3999.000
5 C068 -228.623 428.395 596 01/01/2000 -9991.000
6 C068 -228.623 428.395 596 02/01/2000 -9992.000
7 C068 -228.623 428.395 596 03/01/2000 -9993.000
8 C068 -228.623 428.395 596 04/01/2000 -9994.000
9 E000 -274.107 430.783 218 01/01/2000 -9999.000
10 E000 -274.107 430.783 218 02/01/2000 -9998.000
11 E000 -274.107 430.783 218 03/01/2000 -9997.000
12 E000 -274.107 430.783 218 04/01/2000 -9996.000

editada el 15 may. 18 a las 16:10 respondida el 15 may. 18 a las 16:04


Patricio Moracho
30.4k 6 23 51

Al usar este sitio, reconoces haber leido y entendido nuestra Política de Cookies, Política de Privacidad, y nuestros
Términos de Servicio.

https://es.stackoverflow.com/questions/164497/bucles-anidados-en-r 8/8

S-ar putea să vă placă și