Además de los tipos de datos simples donde una variable está referenciada a un solo valor (numérico o de texto), como los que se muestran a continuación...
x <- 10
y <- "Algoritmos"
Para realizar operaciones sobre las variables, es indispensable conocer la clase (o tipo) de datos que utlizaremos. Para ello ocuparemos la función class().
print(class(x))
## [1] "numeric"
print(class(y))
## [1] "character"
Para el análisis de datos haremos uso de variables estructuradas que bajo el nombre de una variable, nos permite almacenar y manipular todo un conjunto de datos. Como ejemplo de estas variables tenemos:
Un vector es un conjunto de valores almacenados bajo una misma variable, lo crearemos con la función c( ) que hacer alusión a una combinación de elementos
vector_precios <- c(2.33, 2.44, 2.25, 2.27, 2.57)
print(vector_precios)
## [1] 2.33 2.44 2.25 2.27 2.57
print(class(vector_precios))
## [1] "numeric"
Las listas son datos estructurados que pueden almacenar diferentes tipos de datos.
lista_precios <- list(2.33, 2.44, 2.25, 2.27, 2.57, "Hola", c(10,20,30))
print(lista_precios)
## [[1]]
## [1] 2.33
##
## [[2]]
## [1] 2.44
##
## [[3]]
## [1] 2.25
##
## [[4]]
## [1] 2.27
##
## [[5]]
## [1] 2.57
##
## [[6]]
## [1] "Hola"
##
## [[7]]
## [1] 10 20 30
print(class(lista_precios))
## [1] "list"
Observen como accedemos al segundo valor de la lista almacenada en la posición 7 de la lista previa.
lista_precios[[7]][1]
## [1] 10
Nota: Comparado con el vector, si modificamos el tipo de dato de alguno de los elementos de la lista, no alteramos el resto de los elementos.
Las matrices son tipos de datos estructurados de dos dimensiones, se definen mediante la función matrix(), los podemos crear con los valores de un vector
matriz_precios = matrix(c(2.33, 2.44, 2.25, 2.27, 2.57), nrow = 2, ncol = 3, byrow = FALSE)
## Warning in matrix(c(2.33, 2.44, 2.25, 2.27, 2.57), nrow = 2, ncol = 3, byrow =
## FALSE): data length [5] is not a sub-multiple or multiple of the number of rows
## [2]
# nrow: Número de renglones de la matriz
# ncol: Número de columnas de la matriz
# byrow: (TRUE / FALSE) valor booleano que determina si los valores de la lista serán acomodados por renglón o por columna
print(matriz_precios)
## [,1] [,2] [,3]
## [1,] 2.33 2.25 2.57
## [2,] 2.44 2.27 2.33
El warning que nos informa R, hace referencia a que el tamaño de los datos de entrada no corresponde al tamaño definido para la matriz. R rellena los datos faltantes son los mismos datos de entrada en el orden en que están definidos.
Nota: ¿Cuántos valores tiene la lista de precios, y cuántos tiene la matriz?
Los arreglos son variables estructuradas que pueden tener mas de una dimensión, se definen con la función array() y toma como parámetro un vector que dimensiona el tamaño del arreglo.
arreglo_precios <- array(vector_precios, dim=c(2,3,4))
#dim: Parámetro de la función array que define el tamaño del arreglo
# dim = c(renglones, columnas, profundidad)
print(arreglo_precios)
## , , 1
##
## [,1] [,2] [,3]
## [1,] 2.33 2.25 2.57
## [2,] 2.44 2.27 2.33
##
## , , 2
##
## [,1] [,2] [,3]
## [1,] 2.44 2.27 2.33
## [2,] 2.25 2.57 2.44
##
## , , 3
##
## [,1] [,2] [,3]
## [1,] 2.25 2.57 2.44
## [2,] 2.27 2.33 2.25
##
## , , 4
##
## [,1] [,2] [,3]
## [1,] 2.27 2.33 2.25
## [2,] 2.57 2.44 2.27
Para poder acceder a alguno de los elementos del arreglo, tenemos que especificar las coordenadas del elemento.
arreglo_precios[1,2,3]
## [1] 2.57
#arreglo_precios[1,2,]
Los Data Frames son tipos de datos estructurados que permiten almacenar múltiples columnas con nombre y tipo de dato propio, y múltiples renglones con un índide.
dataframe_precios_acciones <- data.frame(
femsa = c(23.1, 22.4, 21.4, 22.3),
alfa = c(12.3, 12.4, 12.8, 12.3),
cemex = c(17.6, 18.9, 18.0, 18.3),
fecha = c("2021-03-01","2021-03-02","2021-03-03","2021-03-04")
)
print(dataframe_precios_acciones)
## femsa alfa cemex fecha
## 1 23.1 12.3 17.6 2021-03-01
## 2 22.4 12.4 18.9 2021-03-02
## 3 21.4 12.8 18.0 2021-03-03
## 4 22.3 12.3 18.3 2021-03-04
Nota: El número de elementos en cada uno de los vectores tiene que ser el mismo, si alguno de los vectores tiene menos datos, R nos marcará un error.
Para conocer la estructura del Data Frame, utilizamos el comando str()
str(dataframe_precios_acciones)
## 'data.frame': 4 obs. of 4 variables:
## $ femsa: num 23.1 22.4 21.4 22.3
## $ alfa : num 12.3 12.4 12.8 12.3
## $ cemex: num 17.6 18.9 18 18.3
## $ fecha: Factor w/ 4 levels "2021-03-01","2021-03-02",..: 1 2 3 4
Observamos que uno de los datos almacena valores en forma de fechas, pero el Data Frame que elaboramos no lo interpreta así desde su estructura, podemos convertir este tipo de dato a Fecha desde la definición del Data Frame con el comando as.Date().
dataframe_precios_acciones <- data.frame(
femsa = c(23.1, 22.4, 21.4, 22.3),
alfa = c(12.3, 12.4, 12.8, 12.3),
cemex = c(17.6, 18.9, 18.0, 18.3),
fecha = as.Date(c("2021-03-01","2021-03-02","2021-03-03","2021-03-04"))
)
str(dataframe_precios_acciones)
## 'data.frame': 4 obs. of 4 variables:
## $ femsa: num 23.1 22.4 21.4 22.3
## $ alfa : num 12.3 12.4 12.8 12.3
## $ cemex: num 17.6 18.9 18 18.3
## $ fecha: Date, format: "2021-03-01" "2021-03-02" ...
Con el comando summary() podemos obtener un resumen estadístico de los valores del Data Frame
summary(dataframe_precios_acciones)
## femsa alfa cemex fecha
## Min. :21.40 Min. :12.30 Min. :17.60 Min. :2021-03-01
## 1st Qu.:22.07 1st Qu.:12.30 1st Qu.:17.90 1st Qu.:2021-03-01
## Median :22.35 Median :12.35 Median :18.15 Median :2021-03-02
## Mean :22.30 Mean :12.45 Mean :18.20 Mean :2021-03-02
## 3rd Qu.:22.57 3rd Qu.:12.50 3rd Qu.:18.45 3rd Qu.:2021-03-03
## Max. :23.10 Max. :12.80 Max. :18.90 Max. :2021-03-04
Podemos extraer los valores de una columna con el nombre del Data Frame, y el nombre de la columna anteponiéndola con el símbolo $.
dataframe_precios_acciones$femsa
## [1] 23.1 22.4 21.4 22.3
Para obtener el valor del número de renglones del Data Frame podemos utilizar la función nrow()
nrow(dataframe_precios_acciones)
## [1] 4
Para obtener el número de columnas del Data Frame podemos utilizar el comando ncol()
ncol(dataframe_precios_acciones)
## [1] 4
Otra forma de extraer valores del Data Frame, es a través de los índices
#dataframe_precios_acciones[renglones,columnas]
dataframe_precios_acciones[1:2,2:3]
## alfa cemex
## 1 12.3 17.6
## 2 12.4 18.9
Nota: Con el uso de : podemos determinar intervalos de renglones o columnas
Con las estructuras repetitivas For podemos ejecutar una sentencia de código n número de veces, o tantos elementos tenga nuestro conjunto de referencia.
vector_numeros = c(10:20)
suma <- 0
for (i in vector_numeros){
suma <- suma + i
}
print(suma)
## [1] 165
Con las estructura selectiva If-Else podemos determinar que segmento de nuestro código deseamos que se ejecute en función de alguna condición lógica.
Si la condición es verdadera, se ejecutará la sentencia acotadas por las llaves después del If.
De otra, forma, si la condición es falsa, se ejecutará las sentencias definidas en la sección de Else
precio = 101
if (precio > 100){
print("precio es mayor que 100")
} else {
print("precio es menor o igual que 100")
}
## [1] "precio es mayor que 100"
Cuando realizamos un análisis de datos, las fuentes de información pueden ser archivos almacenados localmente en nuestro equipo, y que dependiendo el formato del archivo, para que pueda ser incluido en nuestro programa, tiene que ser llaamado de diferente forma.
csv (comma separated value) es un formato de archivo, donde los valores se encuentran separados por comas. Cuando hacemos la importación de un archivo con extensión .csv a nuestro entorno de programación, utilizaremos la función read.csv() donde incluiremos el nombre de nuestro archivo. Los valores estraídos del archivo serán almacenados en una variable.
datos_csv <- read.csv(file = 'ventas_region.csv', header=TRUE)
# Obtenemos el tipo de datos que importamos
class(datos_csv)
## [1] "data.frame"
Extraemos una sección de los datos. Para ello utilizaremos la función head() que nos regresará los primeros datos del conjunto de información (también existe el equivalente para los últimos datos usando tail())
head(datos_csv)
## PAIS REGION MARCA VENTAS COSTOS
## 1 MEXICO NORTE PEPSI 102000 85000
## 2 MEXICO NORTE COCA COLA 130115 97000
## 3 MEXICO NORTE SIDRAL 25000 17000
## 4 MEXICO NORTE FANTA 15123 8901
## 5 MEXICO SUR PEPSI 75987 65345
## 6 MEXICO SUR COCA COLA 87345 81234
Si queremos guardar nuestros datos en el formato csv utilizamos el comando write.csv() junto con los datos y el nombre del archivo.
write.csv(dataframe_precios_acciones, file='datos_precios.csv')
Con R-Studio podemos observar el conjunto de datos dando doble click a la variable en la pestaña Environment
Nota: También se puede hacer lectura de otros formatos de archivos como .xls .txt .html .json .xml, donde necesitaremos de unas librerías específicas para su manipulación.
Para esta sección utilizaremos el Data Frame que elaboramos cuando importamos los datos desde el archivo con formato .csv.
Uno de los primero pasos para comenzar nuestro análisis de datos es conocer la estructura de nuestro conjunto de información a través de la función str().
str(datos_csv)
## 'data.frame': 45 obs. of 5 variables:
## $ PAIS : Factor w/ 2 levels "EEUU","MEXICO": 2 2 2 2 2 2 2 2 2 2 ...
## $ REGION: Factor w/ 5 levels "CENTRO","ESTE",..: 3 3 3 3 5 5 5 5 1 1 ...
## $ MARCA : Factor w/ 5 levels "COCA COLA","DR. PEPPER",..: 4 1 5 3 4 1 5 3 4 1 ...
## $ VENTAS: int 102000 130115 25000 15123 75987 87345 12353 8765 210678 250981 ...
## $ COSTOS: int 85000 97000 17000 8901 65345 81234 7654 6543 170876 199654 ...
Observamos que nuestro conjunto tiene 45 observaciones y 5 columnas (o variables). Las columnas PAIS, REGION, MARCA son valores de texto, mientras que VENTAS y COSTOS son variables de tipo numérico.
También podemos utilizar la función summary() para conocer datos estaísticos de nuestro conjunto de datos.
summary(datos_csv)
## PAIS REGION MARCA VENTAS COSTOS
## EEUU :25 CENTRO:9 COCA COLA :10 Min. : 3455 Min. : 2134
## MEXICO:20 ESTE :9 DR. PEPPER: 5 1st Qu.: 23467 1st Qu.: 14549
## NORTE :9 FANTA :10 Median : 55987 Median : 42314
## OESTE :9 PEPSI :10 Mean : 86663 Mean : 65582
## SUR :9 SIDRAL :10 3rd Qu.:130115 3rd Qu.: 91000
## Max. :319075 Max. :257000
## NA's :2
¿Qué podemos observar del resultado anterior?
En el proceso de análisis y limpieza de datos es relevante llevar un control de los datos faltantes (NA).
Con la función is.na() podemos elaborar un conjunto de datos donde señale con un valor booleano TRUE, aquellos elementos que sean NA. Como ejemplo mostramos solo una fracción de lo que regresaría la función .
head(is.na(datos_csv))
## PAIS REGION MARCA VENTAS COSTOS
## [1,] FALSE FALSE FALSE FALSE FALSE
## [2,] FALSE FALSE FALSE FALSE FALSE
## [3,] FALSE FALSE FALSE FALSE FALSE
## [4,] FALSE FALSE FALSE FALSE FALSE
## [5,] FALSE FALSE FALSE FALSE FALSE
## [6,] FALSE FALSE FALSE FALSE FALSE
Con el comando sum() junto con is.na(), podemos conocer el número de valores NA que tenemos en todo el conjunto de datos.
Nota: Recordemos que un valor FALSE equivale a 0, y un valor TRUE equivale a 1
sum(is.na(datos_csv))
## [1] 2
Tenemos dos valores faltantes, que ya lo sabíamos utilizando summary()
Con procesos mas avanzados podemos identificar en qué renglones encontramos los valores NA. Como nota, cuando hablamos de big-data este tipo de funciones nos puede devolver una gran cantidad de datos.
valores <- unique (unlist (lapply (datos_csv, function (x) which (is.na (x)))))
datos_csv[valores,]
## PAIS REGION MARCA VENTAS COSTOS
## 36 EEUU ESTE PEPSI 98765 NA
## 37 EEUU ESTE COCA COLA 176654 NA
Habiendo identificado con summary() la columna donde encontramos valores faltantes, tenemos que decidir que hacer con esos registros, dentro de las acciones a llevar a cabo podemos:
Con la función na.omit() creamos un nuevo Data Frame que no incluye los registros con valores faltantes
datos_csv_sin_na <- na.omit(datos_csv)
summary(datos_csv_sin_na)
## PAIS REGION MARCA VENTAS COSTOS
## EEUU :23 CENTRO:9 COCA COLA : 9 Min. : 3455 Min. : 2134
## MEXICO:20 ESTE :7 DR. PEPPER: 5 1st Qu.: 20560 1st Qu.: 14549
## NORTE :9 FANTA :10 Median : 55863 Median : 42314
## OESTE :9 PEPSI : 9 Mean : 84289 Mean : 65582
## SUR :9 SIDRAL :10 3rd Qu.:124440 3rd Qu.: 91000
## Max. :319075 Max. :257000
Dependiendo la naturaleza de nuestros datos, podemos rellenar los datos faltantes con un valor predeterminado.
IMPORTANTE: HAY QUE CONOCER LA NATURALEZA DE NUESTROS DATOS PARA DECIDIR SI BORRAMOS O SUSTITUIMOS VALORES FALTANTES POR OTRO VALOR
En nuestro ejemplo es la columna de COSTOS la que tiene los valores faltantes.
Una recomendación sería rellenar estos datos con un promedio de los costos de la región completa, o bien una proporción general de las ventas. En nuestro caso utilizaremos los valores del pais (EEUU) para estimar la proporción de los costos con relación a las ventas para después estimar los costos de los registros faltantes.
Con la función which() podemos identificar el índice de los registros que cumplen con alguna condición, en nuestro caso nos regresaría todos los números de renglones en donde el PAIS es EEUU
# Atención con el uso de los corchetes
datos_eeuu <- datos_csv[which(datos_csv$PAIS == 'EEUU'),]
Creamos una nueva variable para EEUU donde no hay datos faltantes
datos_eeuu_sin_na <- na.omit(datos_eeuu)
Calculamos la proporción de los costos en función de las ventas del total de la región
proporcion <- sum(datos_eeuu_sin_na$COSTOS) / sum(datos_eeuu_sin_na$VENTAS)
print(proporcion)
## [1] 0.7629807
A nivel nacional, los costos representan aproximadamente el 76% de las Ventas
Con esta línea obtenemos los datos de las Ventas, de los registros donde los costos son NA
# Atención con el uso de corchetes
datos_csv$VENTAS[is.na(datos_csv$COSTOS)]
## [1] 98765 176654
Usando la línea anterior, multiplicamos las ventas (donde los costos son na) por la proporcion calculada anteriormente
costos_estimados <- datos_csv$VENTAS[is.na(datos_csv$COSTOS)] * proporcion
costos_estimados
## [1] 75355.79 134783.60
Reemplazamos los valores NA con los costos estimados
datos_csv$COSTOS[is.na(datos_csv$COSTOS)] <- costos_estimados
Utilizamos nuevamente summary() para identificar las estadísticas de nuestros datos
summary(datos_csv)
## PAIS REGION MARCA VENTAS COSTOS
## EEUU :25 CENTRO:9 COCA COLA :10 Min. : 3455 Min. : 2134
## MEXICO:20 ESTE :9 DR. PEPPER: 5 1st Qu.: 23467 1st Qu.: 17000
## NORTE :9 FANTA :10 Median : 55987 Median : 49876
## OESTE :9 PEPSI :10 Mean : 86663 Mean : 67337
## SUR :9 SIDRAL :10 3rd Qu.:130115 3rd Qu.: 97000
## Max. :319075 Max. :257000
Ya contamos con un conjunto de datos listo para hacer nuestros análisis.
Una manera de manipular los datos en un Data Frame, es a través de uso de la función select() del paquete dplyr
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
datos_ventas_costos = datos_csv %>% select(MARCA, VENTAS, COSTOS)
summary(datos_ventas_costos)
## MARCA VENTAS COSTOS
## COCA COLA :10 Min. : 3455 Min. : 2134
## DR. PEPPER: 5 1st Qu.: 23467 1st Qu.: 17000
## FANTA :10 Median : 55987 Median : 49876
## PEPSI :10 Mean : 86663 Mean : 67337
## SIDRAL :10 3rd Qu.:130115 3rd Qu.: 97000
## Max. :319075 Max. :257000
COn la función filter() podemos extraer un subconjunto de datos en función de alguna condición.
datos_coca_cola <- datos_csv %>% filter(MARCA=='COCA COLA')
datos_coca_cola
## PAIS REGION MARCA VENTAS COSTOS
## 1 MEXICO NORTE COCA COLA 130115 97000.0
## 2 MEXICO SUR COCA COLA 87345 81234.0
## 3 MEXICO CENTRO COCA COLA 250981 199654.0
## 4 MEXICO ESTE COCA COLA 55675 49876.0
## 5 MEXICO OESTE COCA COLA 75098 69000.0
## 6 EEUU NORTE COCA COLA 198356 155654.0
## 7 EEUU SUR COCA COLA 319075 257000.0
## 8 EEUU CENTRO COCA COLA 178936 123410.0
## 9 EEUU ESTE COCA COLA 176654 134783.6
## 10 EEUU OESTE COCA COLA 190876 156245.0
Otro ejemplo sería traer todos los registros cuyas ventas sean superiores a x valor
datos_ventas_sup <- datos_csv %>% filter(VENTAS>200000)
datos_ventas_sup
## PAIS REGION MARCA VENTAS COSTOS
## 1 MEXICO CENTRO PEPSI 210678 170876
## 2 MEXICO CENTRO COCA COLA 250981 199654
## 3 EEUU SUR PEPSI 203000 178654
## 4 EEUU SUR COCA COLA 319075 257000
Con la función group_by() podemos agrupar resultados de acuerdo a los valores de una columna, junto con la función summarise() que realiza alguna función de cálculo sobre otra variable.
En nuestro ejemplo calculamos las ventas totales por marca:
sum_by_brand <- datos_csv %>% group_by(PAIS) %>% summarise(ventas_totales = sum(VENTAS))
sum_by_brand
## # A tibble: 2 x 2
## PAIS ventas_totales
## <fct> <int>
## 1 EEUU 2525426
## 2 MEXICO 1374428
Podemos agregar mas condiciones a nuestros criterios de group_by y de summarise
Por ejemplo, además del total de ventas, queremos también el promedio de ventas por pais y marca
sum_by_brand_sales_costs <- datos_csv %>% group_by(PAIS, MARCA) %>% summarise(ventas_totales = sum(VENTAS), promedio_ventas = mean(VENTAS))
## `summarise()` has grouped output by 'PAIS'. You can override using the `.groups` argument.
sum_by_brand_sales_costs
## # A tibble: 9 x 4
## # Groups: PAIS [2]
## PAIS MARCA ventas_totales promedio_ventas
## <fct> <fct> <int> <dbl>
## 1 EEUU COCA COLA 1063897 212779.
## 2 EEUU DR. PEPPER 415783 83157.
## 3 EEUU FANTA 74995 14999
## 4 EEUU PEPSI 775284 155057.
## 5 EEUU SIDRAL 195467 39093.
## 6 MEXICO COCA COLA 599214 119843.
## 7 MEXICO FANTA 95640 19128
## 8 MEXICO PEPSI 499610 99922
## 9 MEXICO SIDRAL 179964 35993.
Calculadas Condicionales
Con la misma librería dplyr podemos agregar columnas nuevas a nuestro conjunto de información.
Agregamos una columna nueva en función de otras columnas del mismo Data Frame
datos_csv_actualizado <- datos_csv %>% mutate(INGRESO_BRUTO = (VENTAS - COSTOS))
head(datos_csv_actualizado)
## PAIS REGION MARCA VENTAS COSTOS INGRESO_BRUTO
## 1 MEXICO NORTE PEPSI 102000 85000 17000
## 2 MEXICO NORTE COCA COLA 130115 97000 33115
## 3 MEXICO NORTE SIDRAL 25000 17000 8000
## 4 MEXICO NORTE FANTA 15123 8901 6222
## 5 MEXICO SUR PEPSI 75987 65345 10642
## 6 MEXICO SUR COCA COLA 87345 81234 6111
O bien una columna nueva cuyos con condiciones específicas, como ejemplo, agregamos una columna nueva que se llame VOLUMEN, que nos informe si las ventas son superiores a 150000, entonces nos señale como 'SIGNIFICATIVO', o bien, entre 150000 y 85000 'MEDIO', y'NO SIGNIFICATIVO'en otro contrario
datos_csv_actualizado_volumen <- datos_csv_actualizado %>% mutate(VOLUMEN = case_when(
VENTAS > 150000 ~ 'SIGNIFICATIVO',
VENTAS > 85000 ~ 'MEDIO',
VENTAS > 0 ~ 'NO SIGNIFICATIVO'))
head(datos_csv_actualizado_volumen)
## PAIS REGION MARCA VENTAS COSTOS INGRESO_BRUTO VOLUMEN
## 1 MEXICO NORTE PEPSI 102000 85000 17000 MEDIO
## 2 MEXICO NORTE COCA COLA 130115 97000 33115 MEDIO
## 3 MEXICO NORTE SIDRAL 25000 17000 8000 NO SIGNIFICATIVO
## 4 MEXICO NORTE FANTA 15123 8901 6222 NO SIGNIFICATIVO
## 5 MEXICO SUR PEPSI 75987 65345 10642 NO SIGNIFICATIVO
## 6 MEXICO SUR COCA COLA 87345 81234 6111 MEDIO
Elegimos las de volumen significativo
datos_csv_actualizado_volumen %>% filter (VOLUMEN == 'SIGNIFICATIVO')
## PAIS REGION MARCA VENTAS COSTOS INGRESO_BRUTO VOLUMEN
## 1 MEXICO CENTRO PEPSI 210678 170876.0 39802.0 SIGNIFICATIVO
## 2 MEXICO CENTRO COCA COLA 250981 199654.0 51327.0 SIGNIFICATIVO
## 3 EEUU NORTE PEPSI 165987 123543.0 42444.0 SIGNIFICATIVO
## 4 EEUU NORTE COCA COLA 198356 155654.0 42702.0 SIGNIFICATIVO
## 5 EEUU SUR PEPSI 203000 178654.0 24346.0 SIGNIFICATIVO
## 6 EEUU SUR COCA COLA 319075 257000.0 62075.0 SIGNIFICATIVO
## 7 EEUU CENTRO COCA COLA 178936 123410.0 55526.0 SIGNIFICATIVO
## 8 EEUU ESTE COCA COLA 176654 134783.6 41870.4 SIGNIFICATIVO
## 9 EEUU OESTE PEPSI 172654 141765.0 30889.0 SIGNIFICATIVO
## 10 EEUU OESTE COCA COLA 190876 156245.0 34631.0 SIGNIFICATIVO
Utilizamos el paquete ggplot2 para graficar algunos de nuestros hallazgos.
ggplot(datos_csv_actualizado_volumen, aes(x=MARCA, y=VENTAS)) + geom_bar(stat="identity")
Entrega por Canvas el 28 de Septiembre antes del inicio de la sesión