Uso del lenguaje R para análisis de varianza (ANOVA, ANCOVA) (1)

1. Ajuste del modelo ANOVA

1.1 función aov()

 Sintaxis: aov (fórmula, datos = marco de datos)

Símbolos especiales en expresiones R:
inserte la descripción de la imagen aquí

Expresiones para diseños de investigación comunes en lenguaje R:
inserte la descripción de la imagen aquí

1.2 El orden de los términos en una expresión

  El orden de los términos en una expresión importa en dos casos, por ejemplo, y ~ A B no da el mismo resultado que y ~ B A:

  1. Hay múltiples factores y un diseño desequilibrado (es decir, el número de muestras en cada grupo es diferente)
  2. Hay covariables(Habrá diferencias entre cada muestra, y las variables que causan estas diferencias se denominan covariables)

El lenguaje R tiene como valor predeterminado el tipo I (tipo secuencial)
Otro ejemplo: y~A+B+A:B:

  1. El efecto de A sobre y
  2. El efecto de B sobre y mientras se controla A
  3. Al controlar los efectos principales de A y B, el efecto de interacción de A y B

Efecto del orden de los factores sobre el resultado:
inserte la descripción de la imagen aquí

  Cuanto más desigual sea el tamaño de la muestra, más afectará el orden de los términos de efecto a los resultados. Por lo tanto, los factores más básicos deben colocarse delante de la expresión, es decir, las covariables deben colocarse antes de las variables principales, seguidas del término de interacción de dos factores y luego el término de interacción de tres factores.
  Para el efecto principal, las variables más básicas deben colocarse delante de la expresión, por ejemplo, el género debe colocarse delante del tratamiento.
  La función Anova() en el paquete de automóviles proporciona métodos que usan Tipo 2 y Tipo 3, y la función aov() usa métodos de Tipo 1.

2. ANOVA unidireccional

  ANOVA de una vía compara las medias de la variable dependiente en dos o más grupos definidos por factores categóricos. Tomando como ejemplo el conjunto de datos de colesterol en el paquete multcomp (tomado de Westfall, Tobia, Rom, Hochberg, 1999), 50 pacientes fueron tratados con uno de los cinco tratamientos de terapia con medicamentos para reducir el colesterol (trt). Tres de las condiciones de tratamiento usan el mismo medicamento, que son 20 mg una vez al día (1 vez), 10 mg dos veces al día (2 veces) y 5 mg cuatro días al día (4 veces). Las dos modalidades restantes (drugD y drugE) representan candidatos a fármacos. ¿Qué tratamiento farmacológico redujo más el colesterol (variable de respuesta)?

install.packages('multcomp')
library(multcomp)

attach(cholesterol) #打开连接:直接使用其中的变量名而不需要使用符号
colnames(cholesterol)
table(trt)

## 计算各组平均值mean
## aggregate()函数是用于对数据进行分组统计的函数:
# aggregate()函数是用于对数据进行分组统计的函数。
# response是一个向量,trt是一个因子变量,表示不同的处理组。
# aggregate(response, by=list(trt), FUN=mean)的作用是计算response向量中每个处理组的平均值
aggregate(response, by=list(trt), FUN=mean)
response

## 计算各组标准差sd
aggregate(response, by=list(trt), FUN=sd)

## 检验组间差异
fit <- aov(response ~ trt)
summary(fit)
#自由度 平方和 均方和 F值 P值

resultado:

> aggregate(response, by=list(trt), FUN=mean)
  Group.1        x
1   1time  5.78197
2  2times  9.22497
3  4times 12.37478
4   drugD 15.36117
5   drugE 20.94752
> aggregate(response, by=list(trt), FUN=sd)
  Group.1        x
1   1time 2.878113
2  2times 3.483054
3  4times 2.923119
4   drugD 3.454636
5   drugE 3.345003
> summary(fit)
            Df Sum Sq Mean Sq F value   Pr(>F)    
trt          4 1351.4   337.8   32.43 9.82e-13 ***
Residuals   45  468.8    10.4                     
---
Signif. codes:  0***0.001**0.01*0.05 ‘.’ 0.1 ‘ ’ 1

  La prueba F de ANOVA para el tratamiento (trt) fue muy significativa (p<0,0001), lo que indica que los cinco tratamientos tuvieron efectos diferentes.

2.1 Dibujar la gráfica de la media de cada grupo y su intervalo de confianza

## 绘制各组均值及其置信区间的图形
library(gplots) 
plotmeans(response ~ trt, xlab="Treatment", ylab="Response", 
            main="Mean Plot\nwith 95% CI")
detach(cholesterol) # 关闭连接

inserte la descripción de la imagen aquí

  Grado de libertad: considerando una muestra con un tamaño de muestra de n (n números), si conocemos la media de la muestra, entonces solo necesitamos conocer los primeros n-1 números para obtener toda la información, porque el último número se puede calcular con la ayuda del medio fuera. entonces,Dada la media muestral (restricciones), hemos reducido un grado de libertad con base en los n números originales, y la información proporcionada por la muestra es solo n-1 partes independientes.

2.2 Comparaciones múltiples - TukeyHSD

   Si bien la prueba F de ANOVA para cada tratamiento muestra que los cinco tratamientos farmacológicos funcionan de manera diferente, no indica qué tratamiento es diferente de los demás. Las comparaciones múltiples pueden resolver este problema, donde la función TukeyHSD() proporciona una prueba por pares para la diferencia en las medias de los grupos.

TukeyHSD(fit)

resultado:

  Tukey multiple comparisons of means
    95% family-wise confidence level

Fit: aov(formula = response ~ trt)

$trt
                  diff        lwr       upr     p adj
2times-1time   3.44300 -0.6582817  7.544282 0.1380949
4times-1time   6.59281  2.4915283 10.694092 0.0003542
drugD-1time    9.57920  5.4779183 13.680482 0.0000003
drugE-1time   15.16555 11.0642683 19.266832 0.0000000
4times-2times  3.14981 -0.9514717  7.251092 0.2050382
drugD-2times   6.13620  2.0349183 10.237482 0.0009611
drugE-2times  11.72255  7.6212683 15.823832 0.0000000
drugD-4times   2.98639 -1.1148917  7.087672 0.2512446
drugE-4times   8.57274  4.4714583 12.674022 0.0000037
drugE-drugD    5.58635  1.4850683  9.687632 0.0030633

  Se puede observar que la diferencia de medias entre 1 vez y 2 veces no es significativa (p=0,138), mientras que la diferencia entre 1 vez y 4 veces es muy significativa (p<0,001).

2.2.1 Gráfico de comparación por pares

  La primera declaración par se usa para rotar la etiqueta del eje, y la segunda se usa para aumentar el área del borde izquierdo, lo que puede hacer que la ubicación de la etiqueta sea más hermosa.Los tratamientos cuyo intervalo de confianza contiene 0 en el gráfico indican que la diferencia no es significativa (p>0.5)
En el lenguaje R, par(las=2) se usa para establecer la dirección de la etiqueta del área de dibujo. donde las es un número entero que especifica la orientación de la etiqueta.las=0 indica que la etiqueta es paralela al eje,las=1 indica que la etiqueta es perpendicular al eje,las=2 indica que la etiqueta es perpendicular al eje y el texto se escribe de derecha a izquierda

par(las=2)
par(mar=c(5,8,4,2)) 
plot(TukeyHSD(fit))

La pantalla de resultados:
inserte la descripción de la imagen aquí

2.2.2 Comparación de medias múltiples - TukeyHSD (más fácil de entender)

  La función glht() del paquete multcomp proporciona un método más completo para comparaciones de medias múltiples, tanto para modelos lineales como para modelos lineales generalizados. El siguiente código reproduce la prueba Tukey HSD y muestra los resultados con un gráfico diferente.

library(multcomp) 
par(las=0)
par(mar=c(5,4,6,2))
tuk <- glht(fit, linfct=mcp(trt="Tukey")) 
plot(cld(tuk, level=.05),col="lightgrey") #cld()函数中的level选项设置了使用的显著水平0.05

Presentación de resultados:
inserte la descripción de la imagen aquí
Interpretación de imágenes:
  Los grupos con la misma letra (representados por diagramas de caja) indican que la diferencia de medias no es significativa. Se puede ver que la diferencia entre 1time y 2times no es significativa (tienen la misma letra a), la diferencia entre 2times y 4times no es significativa (tienen la misma letra b), y la diferencia entre 1time y 4times es significativa (no tienen letra común). Personalmente, creo que este gráfico es más fácil de entender que el gráfico de comparación por pares en 2.2.1.

2.3 Supuestos para la prueba de evaluación

2.3.1 Prueba de normalidad

  Nuestra confianza en los resultados depende de hacer pruebas estadísticasLa medida en que los datos satisfacen los supuestos.. En ANOVA unidireccional, asumimos que la variable dependienteobedecer la distribución normal,Todos los grupos tienen la misma varianza.. Se puede usar un gráfico QQ para probar la suposición de normalidad:

library(car) 
# qqPlot()要求用lm()拟合
qqPlot(lm(response ~ trt, data=cholesterol), 
         simulate=TRUE, main="Q-Q Plot", labels=FALSE)

Gráfica QQ:
inserte la descripción de la imagen aquí
Los datos se encuentran dentro del intervalo de confianza del 95 %, lo que indica que se cumple el supuesto de normalidad.

2.3.2 Homogeneidad de la prueba de varianza

library(car) 
qqPlot(lm(response ~ trt, data=cholesterol), 
         simulate=TRUE, main="Q-Q Plot", labels=FALSE)

La pantalla de resultados:


	Bartlett test of homogeneity of variances

data:  response by trt
Bartlett's K-squared = 0.57975, df = 4, p-value = 0.9653

  Existen otras pruebas como la prueba de Fligner-Killeen (función fligner.test()) y la prueba de Brown-Forsythe (función hov() en el paquete HH), que obtienen los mismos resultados que la prueba de Bartlett.

2.3.3 Prueba de valores atípicos

  Valores atípicos: puntos que predicen mal, con residuos agrandados.

La presencia o ausencia de valores atípicos se juzga en función de la importancia del mayor valor residual:

  1. Si no es significativo Bonferonni P>0.05, indica que no hay outlier;
  2. Si es significativo Bonferonni P<0.05, indica que el punto con el valor residual más grande es un valor atípico y debe eliminarse, y luego se realiza nuevamente la prueba de valores atípicos en el modelo de ajuste después de eliminar este punto.

  ANOVA es muy sensible a los valores atípicos. La función outlierTest() en el paquete del automóvil se puede usar para detectar valores atípicos:

library(car)
outlierTest(fit)

La pantalla de resultados:

No Studentized residuals with Bonferroni p < 0.05
Largest |rstudent|:
   rstudent unadjusted p-value Bonferroni p
19 2.251149           0.029422           NA

Análisis de resultados:
  este resultado es el resultado de una prueba estadística en un análisis de regresión particular. Para el punto de datos 19, la prueba calculó un residuo estudentizado de 2,251, que corresponde a un valor p no corregido de 0,029422. Sin embargo, no se encontraron valores residuales estudentizados con un valor de p corregido por Bonferroni inferior a 0,05, por lo que el resultado dice "No hay residuos estudentizados con Bonferroni p < 0,05". A partir de esto, se puede concluir que el valor residual estudentizado para este punto de datos no es significativo, es decir, no es estadísticamente significativo(No estadísticamente significativo significa que el resultado no es lo suficientemente fuerte para respaldar la hipótesis. En este caso, no podemos rechazar la hipótesis nula. En el ejemplo, el valor p de Bonferroni para el residuo no estudentizado es menor que 0.05, lo que significa que no hay no hay valores atípicos).

  A partir de los resultados de salida, no hay evidencia de que haya valores atípicos en los datos de colesterol (se generará NA cuando p>1). Entonces, según el gráfico QQ, la prueba de Bartlett y la prueba de valores atípicos, los datos parecen encajar bien con el modelo ANOVA. Estos métodos, a su vez, aumentan nuestra confianza en los resultados obtenidos.

3. Análisis de covarianza unidireccional

  El análisis de covarianza unidireccional (ANCOVA) amplía el análisis de varianza unidireccional (ANOVA) para incluir una o más covariables cuantitativas . Los ejemplos a continuación son del conjunto de datos de basura en el paquete multcomp. Los ratones preñados se dividieron en cuatro grupos, y cada grupo recibió diferentes dosis (0, 5, 50 o 500) del tratamiento farmacológico. El peso medio de las crías nacidas fue la variable dependiente y el tiempo de gestación fue la covariable .

#单因素协方差分析
data(litter, package="multcomp")
attach(litter) 
table(dose)
aggregate(weight, by=list(dose), FUN=mean)

fit <- aov(weight ~ gesttime + dose) # 注意aov()使用的是类型1
summary(fit)

La pantalla de resultados:

> table(dose)
dose
  0   5  50 500 
 20  19  18  17
> aggregate(weight, by=list(dose), FUN=mean)
  Group.1        x
1       0 32.30850
2       5 29.30842
3      50 29.86611
4     500 29.64647
> summary(fit)
            Df Sum Sq Mean Sq F value  Pr(>F)   
gesttime     1  134.3  134.30   8.049 0.00597 **
dose         3  137.1   45.71   2.739 0.04988 * 
Residuals   69 1151.3   16.69                   
---
Signif. codes:  0***0.001**0.01*0.05 ‘.’ 0.1 ‘ ’ 1

Análisis de resultados:
  Usando la función table(), se puede ver que el número de cachorros nacidos bajo cada dosis es diferente: 20 cachorros nacieron cuando la dosis era 0 (sin medicamento), y 17 cachorros nacieron cuando la dosis era 500 . Luego use la función de agregado () para obtener el valor promedio de cada grupo, y se puede encontrar que el peso promedio de los cachorros en el grupo no tratado es el más alto (32.3). La prueba F de ANCOVA mostró que:
(a) el tiempo de gestación se relacionó con el peso al nacer de las crías;
(b) la dosis del fármaco se relacionó con el peso al nacer cuando se controló el tiempo de gestación.
Al controlar el tiempo de preñez, se encontró que el peso medio al nacer de las crías era diferente para cada dosis de fármaco.

3.1 Eliminar la influencia de las covariables

  Debido al uso de covariables, es posible que desee obtener medias de grupo ajustadas, es decir, medias de grupo después de eliminar los efectos de las covariables. Las medias ajustadas se pueden calcular usando la función de efectos () del paquete de efectos :

library(effects)
effect("dose", fit)

resultado:

 dose effect
dose
       0        5       50      500 
32.35367 28.87672 30.56614 29.33460 

  La media ajustada es similar a la media no ajustada obtenida por la función de agregado(), pero no en todos los casos. En resumen, el paquete de efectos proporciona una forma poderosa de calcular medias ajustadas para diseños de investigación complejos y visualizar los resultados.

3.2 Comparaciones múltiples de controles definidos por el usuario (Contrastes definidos por el usuario)

  La prueba F para las dosis, aunque mostró que las crías tenían diferentes pesos medios para los diferentes tratamientos, no nos dijo qué tratamiento era diferente de los demás. Nuevamente, usamos el paquete multcomp para realizar comparaciones por pares de todas las medias. Además, el paquete multcomp también se puede usar para probar suposiciones medias definidas por el usuario. Suponiendo que está interesado en saber si el efecto de la condición no medicada es diferente al de las otras tres condiciones drogadas, puede usar el siguiente código para lograrlo:

library(multcomp)
contrast <- rbind("no drug vs. drug" = c(3, -1, -1, -1)) #rbind表示“row bind”,即“按行绑定”,其中每个对象应该具有相同的列数和相同的类型
summary(glht(fit, linfct=mcp(dose=contrast)))

  c(3, -1, -1, -1) en rbind("ningún fármaco frente a fármaco" = c(3, -1, -1, -1)) es un vector numérico de longitud 4, donde el valor Uno (es decir, 3) significa "gravedad específica de la droga no inyectada", y los siguientes tres valores (es decir, -1, -1, -1) indican "gravedad específica de tres dosis". Este vector se usa para definir un vector de comparación que combina las tres dosis en un grupo y lo compara con el grupo sin inyección de drogas.

resultado:

	 Simultaneous Tests for General Linear Hypotheses

Multiple Comparisons of Means: User-defined Contrasts


Fit: aov(formula = weight ~ gesttime + dose)

Linear Hypotheses:
                      Estimate Std. Error t value Pr(>|t|)
no drug vs. drug == 0    8.284      3.209   2.581    0.012
                       
no drug vs. drug == 0 *
---
Signif. codes:  
0***0.001**0.01*0.05 ‘.’ 0.1 ‘ ’ 1
(Adjusted p values reported -- single-step method)

  El control c(3, -1, -1, -1) establece las medias del primer grupo y los otros tres grupos para la comparación. El estadístico t (2.581) de la prueba de hipótesis es significativo al nivel de p<0.05, por lo tanto, se puede concluir que el peso al nacer del grupo sin drogas es mayor que el de otras condiciones tratadas con drogas.

3.3 Supuestos para la prueba de evaluación

  ANCOVA es lo mismo que ANOVA, ambos requieren supuestos de normalidad y homocedasticidad, y ANCOVA también asume la misma pendiente de regresión . En este ejemplo, se supone que las pendientes de regresión para el peso al nacer por tiempo de gestación son las mismas para los cuatro grupos de tratamiento. La homogeneidad de las pendientes de regresión se puede probar cuando el modelo ANCOVA incluye el término de interacción tiempo de embarazo × dosis. Un efecto de interacción significativo implica que la relación entre el tiempo y el peso al nacer de las crías depende del nivel de la dosis del fármaco.

library(multcomp)
fit2 <- aov(weight ~ gesttime*dose, data=litter) 
summary(fit2)

resultado:

              Df Sum Sq Mean Sq F value  Pr(>F)   
gesttime       1  134.3  134.30   8.289 0.00537 **
dose           3  137.1   45.71   2.821 0.04556 * 
gesttime:dose  3   81.9   27.29   1.684 0.17889   
Residuals     66 1069.4   16.20                   
---
Signif. codes:  0***0.001**0.01*0.05 ‘.’ 0.1 ‘ ’ 1

  Se puede observar que el efecto de interacción no es significativo, apoyando la suposición de pendientes iguales. Si el supuesto no es cierto, se puede intentar transformar la covariable o la variable dependiente, o utilizar un modelo que pueda explicar cada pendiente de forma independiente, o utilizar un método ANCOVA no paramétrico que no requiera el supuesto de homogeneidad de las pendientes de regresión. La función sm.ancova() en el paquete sm proporciona un ejemplo de esto último.
  En resumen, si el efecto de interacción no es significativo , significa que la influencia de la variable independiente sobre la variable dependiente es lineal y se puede utilizar una ecuación de regresión unificada para describir la relación entre ellas.

3.4 Visualización de resultados

  La función ancova() en el paquete HH puede trazar la relación entre variables dependientes, covariables y factores:

library(HH)
ancova(weight ~ gesttime + dose, data=litter)

resultado:

Analysis of Variance Table

Response: weight
          Df  Sum Sq Mean Sq F value   Pr(>F)   
gesttime   1  134.30 134.304  8.0493 0.005971 **
dose       3  137.12  45.708  2.7394 0.049883 * 
Residuals 69 1151.27  16.685                    
---
Signif. codes:  0***0.001**0.01*0.05 ‘.’ 0.1 ‘ ’ 1

inserte la descripción de la imagen aquí
  En la figura se puede ver que las líneas de regresión que usan el tiempo de embarazo para predecir el peso al nacer son paralelas entre sí, pero el término de intersección es diferente. A medida que aumenta el tiempo de gestación, también aumenta el peso de las crías al nacer. Además, también se puede ver que el grupo de 0 dosis tiene el elemento de intercepción más grande, y el grupo de 5 dosis tiene el elemento de intercepción más pequeño. Debido a su configuración anterior, las líneas permanecerán paralelas,Con ancova(weight ~ gesttime*dose), el gráfico resultante permitirá que los términos de pendiente e intercepción varíen por grupo, lo que es útil para visualizar casos en los que se viola la homogeneidad de la pendiente de regresión.

4. Análisis de varianza de dos vías (ANOVA)

  En un ANOVA de dos vías, los sujetos fueron asignados a grupos de categorías cruzadas de dos factores. Tomando como ejemplo el conjunto de datos de ToothGrowth en la instalación básica, 60 conejillos de indias fueron asignados aleatoriamente a dos métodos de alimentación (jugo de naranja o vitamina C), y había tres niveles de ácido ascórbico en cada método de alimentación (0,5 mg, 1 mg o 2 mg A cada combinación de tratamientos se le asignaron 10 cuyes. La longitud del diente fue la variable dependiente.

#双因素方差分析
attach(ToothGrowth)
table(supp, dose)
head(ToothGrowth)
aggregate(len, by=list(supp, dose), FUN=mean)
aggregate(len, by=list(supp, dose), FUN=sd)

dose <- factor(dose)
fit <- aov(len ~ supp*dose) # 双因素影响
summary(fit)
detach(ToothGrowth)

resultado:

> head(ToothGrowth)
   len supp dose
1  4.2   VC  0.5
2 11.5   VC  0.5
3  7.3   VC  0.5
4  5.8   VC  0.5
5  6.4   VC  0.5
6 10.0   VC  0.5
> aggregate(len, by=list(supp, dose), FUN=mean)
  Group.1 Group.2     x
1      OJ     0.5 13.23
2      VC     0.5  7.98
3      OJ     1.0 22.70
4      VC     1.0 16.77
5      OJ     2.0 26.06
6      VC     2.0 26.14
> aggregate(len, by=list(supp, dose), FUN=sd)
  Group.1 Group.2        x
1      OJ     0.5 4.459709
2      VC     0.5 2.746634
3      OJ     1.0 3.910953
4      VC     1.0 2.515309
5      OJ     2.0 2.655058
6      VC     2.0 4.797731
> summary(fit)
            Df Sum Sq Mean Sq F value   Pr(>F)    
supp         1  205.4   205.4  15.572 0.000231 ***
dose         2 2426.4  1213.2  92.000  < 2e-16 ***
supp:dose    2  108.3    54.2   4.107 0.021860 *  
Residuals   54  712.1    13.2                     
---
Signif. codes:  0***0.001**0.01*0.05 ‘.’ 0.1 ‘ ’ 1

Análisis de resultados:
  El procesamiento previo de la declaración de la tabla muestra que el diseño es un diseño equilibrado (el tamaño de la muestra en cada unidad de diseño es el mismo), y el procesamiento de la declaración agregada puede obtener la media y la desviación estándar de cada unidad. La variable de dosis se transforma en una variable de factor para que la función aov() la trate como una variable de agrupación en lugar de una covariable numérica. Usando la función de resumen () para obtener la tabla de análisis de varianza, podemos ver que los efectos principales (suplemento y dosis) y los efectos de interacción son muy significativos.

4.1 Visualización de resultados

  disponible aquífunción interacción.plot()Demostrar el efecto de interacción de ANOVA de dos vías.

interaction.plot(dose, supp, len, type="b", 
                 col=c("red","blue"), pch=c(16, 18), 
                 main = "Interaction between Dose and Supplement Type")

El gráfico muestra la longitud media de los dientes de cobayos alimentados con varias dosis:
inserte la descripción de la imagen aquí

Use la función plotmeans() en el paquete gplots para visualizar los efectos de interacción:

library(gplots)
plotmeans(len ~ interaction(supp, dose, sep=" "), 
          connect=list(c(1,3,5),c(2,4,6)), 
          col=c("red", "darkgreen"), 
          main = "Interaction Plot with 95% CIs", 
          xlab="Treatment and Dose Combination")

El gráfico muestra la media, las barras de error (intervalo de confianza del 95 %) y el tamaño de la muestra:
inserte la descripción de la imagen aquí

  Use la función de interacción2wt() en el paquete HH para visualizar los resultados. El gráfico muestra tanto el efecto principal como el efecto de interacción del diseño factorial en cualquier orden:

library(HH)
interaction2wt(len~supp*dose)

Efectos principales y de interacción para el conjunto de datos ToothGrowth:
inserte la descripción de la imagen aquí

  Los tres gráficos anteriores muestran que la longitud del diente aumenta con dosis crecientes de ácido ascórbico en el jugo de naranja (QJ) y vitamina C (VC). Para las dosis de 0,5 mg y 1 mg, el jugo de naranja promovió el crecimiento de los dientes más que la vitamina C; para la dosis de 2 mg de ácido ascórbico, el crecimiento de la longitud de los dientes fue el mismo para ambos métodos de alimentación. Entre los tres métodos de dibujo, recomiendo la función de interacción2wt() en el paquete HH , porque puede mostrar el efecto principal (diagrama de caja) y el efecto de interacción de cualquier diseño de complejidad (ANOVA de dos factores, ANOVA de tres factores, etc.) .
  La prueba de hipótesis del modelo y la comparación de medias no se tratan aquí, ya que son solo una extensión natural del enfoque anterior. Además, el diseño está equilibrado, por lo que no hay necesidad de preocuparse por el orden de los efectos.

Supongo que te gusta

Origin blog.csdn.net/amyniez/article/details/130171970
Recomendado
Clasificación