input_1
# A veces necesitamos instalar nuevas librerías en nuestros proyectos
!pip install openpyxl==3.0.10
Requirement already satisfied: openpyxl==3.0.10 in /root/venv/lib/python3.9/site-packages (3.0.10)
Requirement already satisfied: et-xmlfile in /root/venv/lib/python3.9/site-packages (from openpyxl==3.0.10) (1.1.0)
WARNING: You are using pip version 22.0.4; however, version 22.1.2 is available.
You should consider upgrading via the '/root/venv/bin/python -m pip install --upgrade pip' command.
!pip install openpyxl==3.0.10
Requirement already satisfied: openpyxl==3.0.10 in /root/venv/lib/python3.9/site-packages (3.0.10)
Requirement already satisfied: et-xmlfile in /root/venv/lib/python3.9/site-packages (from openpyxl==3.0.10) (1.1.0)
WARNING: You are using pip version 22.0.4; however, version 22.1.2 is available.
You should consider upgrading via the '/root/venv/bin/python -m pip install --upgrade pip' command.
# imports
import numpy as np
import pandas as pd
import sqlite3 as sql3
import openpyxl # para que levante bien el excel
import matplotlib.pyplot as plt
import seaborn as sns
# Levanto los datos en 3 diferentes dataframes
# Artículos
conn = sql3.connect('/work/data/articles.db')
sql_query = pd.read_sql_query('SELECT * FROM articles', conn)
df_articles = pd.DataFrame(sql_query, columns = ['article_id', 'article_name', 'unit_price'])
# Vendedores
df_sellers = pd.read_excel('/work/data/sellers.xlsx', index_col=0)
df_sellers
# Órdenes
df_orders = pd.read_csv('/work/data/orders.csv')
# Exploración del df de artículos
print('Muestra de datos')
print(df_articles.head())
print('\nFormato del dataframe')
print(df_articles.shape)
print('\nBúsqueda de valores nulos por columna')
print(df_articles.isnull().sum())
print('\nFormato de los datos por columna')
print(df_articles.dtypes)
Muestra de datos
article_id article_name unit_price
0 20015 Smartphone 525.00
1 20016 Full Pc 2127.81
2 20017 Monitor 230.00
3 20018 Tablet 130.00
4 20019 Desk 130.10
Formato del dataframe
(31, 3)
Búsqueda de valores nulos por columna
article_id 0
article_name 0
unit_price 0
dtype: int64
Formato de los datos por columna
article_id int64
article_name object
unit_price object
dtype: object
# Exploración del df de vendedores
print('Muestra de datos')
print(df_sellers.head())
print('\nFormato del dataframe')
print(df_sellers.shape)
print('\nBúsqueda de valores nulos por columna')
print(df_sellers.isnull().sum())
print('\nFormato de los datos por columna')
print(df_sellers.dtypes)
Muestra de datos
seller_name
seller_id
1 Aveline Swanwick
2 Jase Doy
3 Oliviero Charkham
4 Cornie Wynrehame
5 Ewell Peres
Formato del dataframe
(15, 1)
Búsqueda de valores nulos por columna
seller_name 0
dtype: int64
Formato de los datos por columna
seller_name object
dtype: object
# Exploración del df de órdenes
print('Muestra de datos')
print(df_orders.head())
print('\nFormato del dataframe')
print(df_orders.shape)
print('\nBúsqueda de valores nulos por columna')
print(df_orders.isnull().sum())
print('\nFormato de los datos por columna')
print(df_orders.dtypes)
Muestra de datos
order_id week article_id quantity seller_id country_name
0 15024 1 20039 10 10 Peru
1 15025 1 20029 15 5 Peru
2 15026 1 20024 5 14 Bolivia
3 15027 1 20018 9 14 Brazil
4 15028 1 20035 6 15 Mexico
Formato del dataframe
(1000, 6)
Búsqueda de valores nulos por columna
order_id 0
week 0
article_id 0
quantity 0
seller_id 0
country_name 0
dtype: int64
Formato de los datos por columna
order_id int64
week int64
article_id int64
quantity int64
seller_id int64
country_name object
dtype: object
# Luego de la exploración de datos, se observó en articles.db:
#- el formato de los datos de la columna "Unit_price" es object y debería ser float.
# Se procede a realizar dicho cambio:
df_articles['unit_price'] = df_articles['unit_price'].astype(float)
print(df_articles.dtypes)
#- el ID de los artículos se encuentra como dato en una columna.
# Se crea una copia de articles.db y se procede al cambio de índice.
df_artic = df_articles.set_index('article_id',inplace = False)
print(df_artic)
# - los datos no tienen la misma cantidad de cifras significativas.Para ello, se configura el separadores de miles y formato de 2 decimales.
pd.options.display.float_format = '{:,.2f}'.format
pd.set_option('display.width', 1000)
article_id int64
article_name object
unit_price float64
dtype: object
article_name unit_price
article_id
20015 Smartphone 525.00
20016 Full Pc 2127.81
20017 Monitor 230.00
20018 Tablet 130.00
20019 Desk 130.10
20020 Chair 335.64
20021 Modem 67.50
20022 Range Extender 20.45
20023 Notebook 1000.00
20024 Netbook 145.00
20025 HDD 54.62
20026 SDD 22.00
20027 Ram Memory 35.95
20028 Motherboard 138.38
20029 Mouse 30.30
20030 Fan Cooler 4.25
20031 Webcam 20.07
20032 Keyboard 22.60
20033 Headphones 23.30
20034 Scanner 185.00
20035 Case 37.90
20036 Video Card 131.50
20037 CPU 139.62
20038 Power Supply 43.95
20039 Water Cooling 67.50
20040 Heatsink 10.00
20041 Usb Cable 2.95
20042 Sata Cable 2.14
20043 Pci Express Port 10.12
20044 Wi-Fi Card 59.61
20045 Mesh Wi-Fi X 2 32.50
# Creo una copia del df_orders
pd.set_option('precision',2)
my_df = df_orders.copy()
# Agrego algunas columnas y pongo el campo que me va a servir de "ancla"
my_df = my_df.assign(article_name = my_df['article_id'])
my_df = my_df.assign(total_amount = my_df['article_id'])
my_df = my_df.assign(seller_name = my_df['seller_id'])
# reemplazo los valores en el nuevo df
# 1. busco el nombre del artículo y lo asigno a una variable
# como df_artic está indexado por article_id, lo uso para ubicarme en
# el registro que busco
# SINTAXIS: df_artic.loc[indice][columna]
# [indice] va a ser el dato que obtengo de my_df.loc[i]['article_id']
# -> o sea, tomo registro a registro el article_id y lo uso para extraer
# el nombre del artículo
for i in range(len(my_df.index)): # len(my_df.index) devuelve la cantidad de registros
# Obtenemos article_name
id_articulo = my_df.loc[i]['article_id']
nombreArticulo = df_artic.loc[id_articulo]['article_name']
#se lo asigno a la columna correspondiente
my_df.loc[i,'article_name'] = nombreArticulo
# Obtenemos total_amount
precioArticulo = df_artic.loc[id_articulo]['unit_price']
my_df.loc[i, 'total_amount'] = my_df.loc[i,'quantity'] * precioArticulo
# Obtenemos seller_name
id_vendedor = my_df.loc[i]['seller_id']
nombreVendedor = df_sellers.loc[id_vendedor]['seller_name']
my_df.loc[i, 'seller_name'] = nombreVendedor
# elimino las columnas que no necesito
my_df.drop(['order_id', 'article_id', 'seller_id'], axis = 'columns', inplace=True)
#visualizo la tabla
print(my_df)
week quantity country_name article_name total_amount seller_name
0 1 10 Peru Water Cooling 675.00 Cirilo Grandham
1 1 15 Peru Mouse 454.50 Ewell Peres
2 1 5 Bolivia Netbook 725.00 Janel O'Curran
3 1 9 Brazil Tablet 1,170.00 Janel O'Curran
4 1 6 Mexico Case 227.40 Daisie Slograve
.. ... ... ... ... ... ...
995 4 1 Brazil Modem 67.50 Kati Innot
996 4 15 Brazil Heatsink 150.00 Daisie Slograve
997 4 2 Colombia Heatsink 20.00 Vasily Danilyuk
998 4 14 Brazil Tablet 1,820.00 Vasily Danilyuk
999 4 12 Brazil SDD 264.00 Onida Cosely
[1000 rows x 6 columns]
# RESOLUCIÓN ANALÍTICA
df_cant_articulos = my_df.groupby('article_name').sum()
df_cant_articulos_ord = df_cant_articulos.sort_values('quantity', ascending=False)
#print(df_cant_articulos_ord) # visualizo la tabla
#Respuesta---
print("El artículo más vendido es (unidades):\n", df_cant_articulos_ord['quantity'].head(1)) # Respuesta Artículo más vendido: HDD 413 unidades
#---------------- Generación y acondicionamiento de tablas para graficar----------------
df_cant_articulos_ord_head= df_cant_articulos_ord['quantity'].head() #Los 5 primeros artículos
El artículo más vendido es (unidades):
article_name
HDD 413
Name: quantity, dtype: int64
# RESOLUCIÓN GRÁFICA
# Grafico 1
ax1=sns.barplot(y = df_cant_articulos_ord["quantity"], x=df_cant_articulos_ord.index,palette= "light:#5A9")
plt.xticks(rotation=90, ha="right")
ax1.set_title("Artículos vendidos",fontsize = 16)
ax1.set_xlabel("Artículos",fontsize = 12)
ax1.set_ylabel("Cantidad (unidades)",fontsize = 12)
plt.show(ax1)
#Gráfico 2
ax2=sns.barplot(y = df_cant_articulos_ord_head, x=df_cant_articulos_ord_head.index,palette= "flare")
ax2.set_title("5 Artículos más vendidos",fontsize = 16)
ax2.set_xlabel("Artículos",fontsize = 12)
ax2.set_ylabel("Cantidad (unidades)",fontsize = 12)
plt.xticks(rotation = 45, ha="right")
plt.show(ax2)
print("En el primer gráfico se observan las unidades vendidas de cada artículo, siendo el artículo más vendido HDD. \n Con el objetivo de mostrar las diferencias entre los primeros artículos más vendidos, se presenta el gráfico 2")
En el primer gráfico se observan las unidades vendidas de cada artículo, siendo el artículo más vendido HDD.
Con el objetivo de mostrar las diferencias entre los primeros artículos más vendidos, se presenta el gráfico 2
# RESOLUCIÓN ANALÍTICA
df_monto_articulo_ord = my_df.groupby('article_name').sum().sort_values('total_amount', ascending=False).head(5)
#print(df_monto_articulo_ord) #Para visualizar tabla
#Respuesta---
print("El artículo que más ingresos proporcionó ($ Pesos argentinos):\n", df_monto_articulo_ord['total_amount'].head(1)) # Respuesta: Full Pc $538.335,93
El artículo que más ingresos proporcionó ($ Pesos argentinos):
article_name
Full Pc 538,335.93
Name: total_amount, dtype: float64
# RESOLUCIÓN GRÁFICA
plt.barh(df_monto_articulo_ord.index, df_monto_articulo_ord['total_amount'] , height=0.8, color= "salmon")
plt.xlabel('Monto ($ Pesos argentinos)', fontsize=12)
plt.title('5 Artículos que proporcionan mayor ganancia',fontsize=16)
plt.xticks([0,100000,200000,300000,400000,500000], ["0", "100.000", "200.000", "300.000","400.000","500.000"])
plt.show()
print("Se observa que, los 5 artículos que generan mayores ganancias son artículos importantes ( referido a prestaciones y costo) \n"
"Además, la diferencia entre las ganancias generadas por la venta de Full Pc y Notebook son del 50% aprox. \n"
"Finalmente, si comparamos con las gráficas anteriores observamos que, Full Pc se encuentra en orden 16 de ventas (unidades) \n"
"y por ejemplo Tablet es el segundo en ventas (unidades) pero el quinto en ganancias ($). Por otro lado, Chair se encuentra entre los 5 artículos \n"
"menos vendidos (unidades) y es el cuarto en generar más ganancias por sus ventas.")
Se observa que, los 5 artículos que generan mayores ganancias son artículos importantes ( referido a prestaciones y costo)
Además, la diferencia entre las ganancias generadas por la venta de Full Pc y Notebook son del 50% aprox.
Finalmente, si comparamos con las gráficas anteriores observamos que, Full Pc se encuentra en orden 16 de ventas (unidades)
y por ejemplo Tablet es el segundo en ventas (unidades) pero el quinto en ganancias ($). Por otro lado, Chair se encuentra entre los 5 artículos
menos vendidos (unidades) y es el cuarto en generar más ganancias por sus ventas.
# RESOLUCIÓN ANALÍTICA
df_monto_vendedor_ord = my_df.groupby('seller_name').sum().sort_values('total_amount', ascending=False)
#print(df_monto_vendedor_ord[['quantity']+['total_amount']]) #Visualizar la Tabla
#Respuesta---
print("El bono por \"Mejor vendedor del mes\" debe entregarse a: \n", df_monto_vendedor_ord[['quantity']+['total_amount']].head(1)) # Respuesta: Janel O' Curran $192,832.47
El bono por "Mejor vendedor del mes" debe entregarse a:
quantity total_amount
seller_name
Janel O'Curran 703 192,832.47
# RESOLUCIÓN GRÁFICA
plt.bar(df_monto_vendedor_ord.index, df_monto_vendedor_ord['total_amount'], color= "turquoise")
plt.xticks(rotation=45, ha="right")
plt.ylabel('Monto ($ Pesos argentinos)', fontsize=12)
plt.title('Ventas del mes por vendedor',fontsize=16)
plt.yticks([0,25000,50000,75000,100000,125000,150000,175000,200000], ["0","25.000","50.000","75.000","100.000","125.000","150.000","175.000","200.000"])
plt.show()
print("De la gráfica se observa que, el mejor vendedor posee una diferencia con respecto al segundo y tercer vendedor de 25% aprox \n"
"y del 75% respecto al último vendedor. Se debería analizar qué artículos vende para explicar las diferencias, por ejemplo.")
De la gráfica se observa que, el mejor vendedor posee una diferencia con respecto al segundo y tercer vendedor de 25% aprox
y del 75% respecto al último vendedor. Se debería analizar qué artículos vende para explicar las diferencias, por ejemplo.
# RESOLUCIÓN ANALÍTICA
df_venta_semanal = my_df.groupby(by='week').sum().sort_values('total_amount',ascending=False)
#Respuesta---
print("Las variaciones en ventas ($ Pesos argentinos) a lo largo del mes, pueden observarse a continuación a: \n", df_venta_semanal['total_amount'])
Las variaciones en ventas ($ Pesos argentinos) a lo largo del mes, pueden observarse a continuación a:
week
1 507,458.81
2 415,364.44
3 329,140.03
4 223,844.56
Name: total_amount, dtype: float64
# RESOLUCIÓN GRÁFICA
plt.subplot(2,2,1) # Grafico 1
plt.plot(df_venta_semanal.index,df_venta_semanal['total_amount'],'tab:purple', marker='p', linestyle=':')
plt.ylabel('Ventas ($ Pesos argentinos)', fontsize=10)
plt.xlabel('Semanas', fontsize=10)
plt.title("Variaciones en el mes \n expresadas en ventas", fontsize=14)
plt.subplot(2,2,2) # Gráfico 2
plt.plot(df_venta_semanal.index,df_venta_semanal['quantity'],'darkturquoise', marker='>', linestyle='-.')
plt.ylabel('Ventas (unidades)', fontsize=10)
plt.xlabel('Semanas', fontsize=10)
plt.title("Variaciones en el mes \n expresadas en cantidades", fontsize=14)
plt.subplots_adjust(left=0.1, bottom=1, right=0.9, top=2.5, wspace=0.8, hspace=0.4)
plt.show()
print("Si bien el ejercicio sugiere analizar a través de las variaciones en ventas ( expresadas en monto) \n"
"es conveniente analizar en detalle qué sucede en los distintas semanas para lanzar una promoción. \n"
"Por ejemplo del gráfico 2 se observa que, prácticamente no hubo variaciones en las cantidades vendidas durante la semana 1 y 2.\n"
"Pero el ingreso percibido por las ventas si disminuyó. Sin entrar en más detalles, se sugiere incorporar promociones en la semana 3.\n"
"De forma tal de mantener al menos las cantidades vendidas, y realizar un estudio más profundo sobre los artículos que se venden \n"
"para generar mayores ingresos ($).")
Si bien el ejercicio sugiere analizar a través de las variaciones en ventas ( expresadas en monto)
es conveniente analizar en detalle qué sucede en los distintas semanas para lanzar una promoción.
Por ejemplo del gráfico 2 se observa que, prácticamente no hubo variaciones en las cantidades vendidas durante la semana 1 y 2.
Pero el ingreso percibido por las ventas si disminuyó. Sin entrar en más detalles, se sugiere incorporar promociones en la semana 3.
De forma tal de mantener al menos las cantidades vendidas, y realizar un estudio más profundo sobre los artículos que se venden
para generar mayores ingresos ($).
# RESOLUCIÓN
df_articulo1_ventas = my_df.loc[my_df['article_name'] == 'Full Pc']
df_articulo1_ventas_semanal = df_articulo1_ventas.groupby(by='week').sum().sort_values('total_amount',ascending=False)
df_articulo1_ventas_semanal=df_articulo1_ventas_semanal.sort_index()
df_articulo2_ventas = my_df.loc[my_df['article_name'] == 'Notebook']
df_articulo2_ventas_semanal = df_articulo2_ventas.groupby(by='week').sum().sort_values('total_amount',ascending=False)
df_articulo2_ventas_semanal=df_articulo2_ventas_semanal.sort_index()
df_articulo3_ventas = my_df.loc[my_df['article_name'] == 'Smartphone']
df_articulo3_ventas_semanal = df_articulo3_ventas.groupby(by='week').sum().sort_values('total_amount',ascending=False)
df_articulo3_ventas_semanal=df_articulo3_ventas_semanal.sort_index()
df_articulo4_ventas = my_df.loc[my_df['article_name'] == 'Chair']
df_articulo4_ventas_semanal = df_articulo4_ventas.groupby(by='week').sum().sort_values('total_amount',ascending=False)
df_articulo4_ventas_semanal=df_articulo4_ventas_semanal.sort_index()
df_articulo5_ventas = my_df.loc[my_df['article_name'] == 'Tablet']
df_articulo5_ventas_semanal = df_articulo5_ventas.groupby(by='week').sum().sort_values('total_amount',ascending=False)
df_articulo5_ventas_semanal=df_articulo5_ventas_semanal.sort_index()
#---GRÁFICO----
plt.plot(df_articulo5_ventas_semanal.index,df_articulo5_ventas_semanal['total_amount'],'tab:purple', marker='p', linestyle=':')
plt.plot(df_articulo4_ventas_semanal.index,df_articulo4_ventas_semanal['total_amount'],'darkturquoise', marker='>')
plt.plot(df_articulo3_ventas_semanal.index,df_articulo3_ventas_semanal['total_amount'],'red', marker='8')
plt.plot(df_articulo2_ventas_semanal.index,df_articulo2_ventas_semanal['total_amount'],'#00FF00', marker='s')
plt.plot(df_articulo1_ventas_semanal.index,df_articulo1_ventas_semanal['total_amount'],'blue', marker='1')
plt.ylabel('Ventas ($ Pesos argentinos)', fontsize=12)
plt.xlabel('Semanas', fontsize=12)
plt.title("Variaciones en el mes \n expresadas en ventas", fontsize=14)
plt.legend(('Tablet','Chair','Smartphone','Notebook','Full Pc' ),loc="upper right")
plt.show()
print("Del gráfico se observa que, prácticamente, las ventas de los 5 artículos que generan más \n"
"ganancias disminuyen en la segunda semana. Ese es el momento para lanzar promociones de ventas. \n"
"En la pregunta 4, grafico 2, observamos que las unidades vendidas entre semana 1 y 2 no variaban, pero si las ventas \n"
"esto nos da un indicio que, en la segunda semana se vendieron artículos menores que no impactan en las ganancias.")
Del gráfico se observa que, prácticamente, las ventas de los 5 artículos que generan más
ganancias disminuyen en la segunda semana. Ese es el momento para lanzar promociones de ventas.
En la pregunta 4, grafico 2, observamos que las unidades vendidas entre semana 1 y 2 no variaban, pero si las ventas
esto nos da un indicio que, en la segunda semana se vendieron artículos menores que no impactan en las ganancias.
# RESOLUCIÓN
df_articulo1_ventas_pais = df_articulo1_ventas.groupby(by='country_name').sum().sort_values('total_amount',ascending=False)
colores=("rosybrown","lightcoral","indianred","brown","firebrick","maroon","red","salmon","coral","sienna", "chocolate","tan")
desfase=(0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1)
df_articulo1_ventas.groupby(by='country_name').sum().plot(kind='pie',y='total_amount',colors=colores, autopct='%1.0f%%',legend=False, explode=desfase)
plt.title("Ventas por país del artículo Full Pc", fontsize=14)
plt.axis("off")
plt.show()
print("Los países que más compran el artículo Full Pc son Brazil, Argentina y Colombia. \n"
"Tal como se observa en el gráfico de torta. Se debería realizar un estudio que muestre cuál es el artículo más vendido por país\n"
"y analizar la variación mensual de las ventas.")
Los países que más compran el artículo Full Pc son Brazil, Argentina y Colombia.
Tal como se observa en el gráfico de torta. Se debería realizar un estudio que muestre cuál es el artículo más vendido por país
y analizar la variación mensual de las ventas.
# RESOLUCIÓN
#----------Respuesta A----------
df_vendedor1= my_df.loc[(my_df['seller_name'] == "Janel O'Curran")]
df_vendedor1_articulos_ventas = df_vendedor1.groupby(by='article_name').sum().sort_values('total_amount',ascending=False)
#Se observa una amplia diferencia en ventas entre artículos.Se muestran los primeros 5 y se grafican.
df_vendedor1_articulos_ventas_head=df_vendedor1_articulos_ventas['total_amount'].head()
print(df_vendedor1_articulos_ventas_head)
print("Se observa que el artículo que ventas genera es el artículo Full Pc,\n"
"luego siguen otros pero no son relevantes.")
#----------Respuesta B----------
df_vendedor1_pais= my_df.loc[(my_df['seller_name'] == "Janel O'Curran") & (my_df['article_name'] == 'Full Pc')]
plt.bar(df_vendedor1_pais['country_name'], df_vendedor1_pais['total_amount'], color= "rosybrown")
plt.xticks(rotation=45, ha="right")
plt.ylabel('Monto ($ Pesos argentinos)', fontsize=12)
plt.title("Ventas de Ful Pc por país por proveedor Janel O'Curran",fontsize=16)
plt.show()
print("Del gráfico de barras observamos qué el proveedor Janel O'Curran vende el \n"
"artículo Full Pc en los países mayoritarios en ventas de dicho artículo. ")
article_name
Full Pc 119,157.36
Notebook 17,000.00
Smartphone 16,800.00
Netbook 5,945.00
Tablet 4,940.00
Name: total_amount, dtype: float64
Se observa que el artículo que ventas genera es el artículo Full Pc,
luego siguen otros pero no son relevantes.
Del gráfico de barras observamos qué el proveedor Janel O'Curran vende el
artículo Full Pc en los países mayoritarios en ventas de dicho artículo.
print("CONCLUSIONES: En lo personal, el trabajo práctico me pareció muy interesante. Dejar abierto a continuar analizando la información \n"
"me pareció muy adecuado, seguramente a cada alumno le pareció más apropiado ahondar en el análisis de relaciones de distintas categorías")
print("PROPUESTAS: Del debate que surgió en clases sobre la pregunta 4. Se sugiere ahondar con más detalle \n"
"en las preguntas complementarias, si el alumno lo cree pertinente. Ya que sacar conclusiones de promociones por ventas en general \n"
"sin especificar que productos se están vendiendo ( ya que los ingresos están directamente asociados al tipo de artículo) puede inducir a errores. \n"
"Por otro lado, se sugiere analizar un podio de vendedores del mes y qué artículos venden o el mejor vendedor por artículo. \n")
CONCLUSIONES: En lo personal, el trabajo práctico me pareció muy interesante. Dejar abierto a continuar analizando la información
me pareció muy adecuado, seguramente a cada alumno le pareció más apropiado ahondar en el análisis de relaciones de distintas categorías
PROPUESTAS: Del debate que surgió en clases sobre la pregunta 4. Se sugiere ahondar con más detalle
en las preguntas complementarias, si el alumno lo cree pertinente. Ya que sacar conclusiones de promociones por ventas en general
sin especificar que productos se están vendiendo ( ya que los ingresos están directamente asociados al tipo de artículo) puede inducir a errores.
Por otro lado, se sugiere analizar un podio de vendedores del mes y qué artículos venden o el mejor vendedor por artículo.