1. Faro

Nivel 6 · Por qué se devuelve cada categoría

La solicitud

De Angela Rivera, Directora de Atención al Cliente

“Mi equipo quiere saber por qué vuelve cada categoría. No recuentos brutos, porque las categorías venden cantidades muy distintas: para cada categoría, ¿qué proporción de sus devoluciones es damaged, late, wrong item o changed mind?”

Tu objetivo

Une cada devolución con su línea de pedido y su producto. Asigna a result un DataFrame con las columnas category, changed_mind, damaged, late, wrong_item: para cada categoría, la proporción de las devoluciones de esa categoría con cada motivo (cada fila suma 1), redondeada a 3. Una fila por categoría, ordenada de la A a la Z.

  • Usa el DataFrame productspendiente
  • Usa el DataFrame order_itemspendiente
  • Muestra exactamente category changed_mind damaged late wrong_itempendiente

Tu código

Python

Cargando el editor…

    ResultadoVista previa de products · presiona Ejecutar para ver el tuyo
    Vista previa de products
    product_idnamecategorysubcategoryunit_price
    101Vale Velvet LoveseatFurnitureSofas1659.00
    102Alder Oak Coffee TableFurnitureTables919.00
    103Orchard Rattan Dining ChairFurnitureChairs789.00
    104Upland Oak BookcaseFurnitureStorage429.00

    Mote revisa tu resultado

    Presiona Ejecutar. Cada fila que cumple el objetivo se vuelve una luciérnaga en tu linterna.

    DataFrames

    Cargados como DataFrames de pandas, junto con pd y np.

    products120 filas · 8 columnas
    • product_idinteger
    • namevarchar
    • categoryvarchar
    • subcategoryvarchar
    • unit_pricedecimal
    • unit_costdecimal
    • launched_ondate
    • is_activeboolean
    Primeras 5 filas de products
    product_idnamecategorysubcategoryunit_priceunit_costlaunched_onis_active
    101Vale Velvet LoveseatFurnitureSofas1659.00NaN2023-09-11true
    102Alder Oak Coffee TableFurnitureTables919.00503.502024-05-16true
    103Orchard Rattan Dining ChairFurnitureChairs789.00429.872023-05-27true
    104Upland Oak BookcaseFurnitureStorage429.00214.702022-12-20true
    105Avery Leather Bed FrameFurnitureBeds449.00232.702021-08-31true
    order_items30,338 filas · 6 columnas
    • order_item_idinteger
    • order_idinteger
    • product_idinteger
    • quantityinteger
    • unit_pricedecimal
    • discount_pctdecimal
    Primeras 5 filas de order_items
    order_item_idorder_idproduct_idquantityunit_pricediscount_pct
    11001121931.990.00
    21001154311.990.00
    31002154411.990.00
    410021941149.000.00
    51002193219.990.00
    returns1,673 filas · 5 columnas
    • return_idinteger
    • order_item_idinteger
    • returned_ondate
    • reasonvarchar
    • refund_amountdecimal
    Primeras 5 filas de returns
    return_idorder_item_idreturned_onreasonrefund_amount
    1142023-01-10damaged83.69
    2422023-01-10wrong_item19.99
    31052023-01-14wrong_item10.99
    4242023-01-16changed_mind26.99
    51262023-01-16late20.99
    customers2,018 filas · 9 columnas
    • customer_idinteger
    • first_namevarchar
    • last_namevarchar
    • emailvarchar
    • cityvarchar
    • statevarchar
    • signup_datedate
    • segmentvarchar
    • referral_sourcevarchar
    Primeras 5 filas de customers
    customer_idfirst_namelast_nameemailcitystatesignup_datesegmentreferral_source
    1OwenHudsonowen.hudson@icloud.comSan FranciscoCA2022-06-02consumersearch
    2DouglasMendozadmendoza69@gmail.comAtlantaGA2022-06-02consumerNaN
    3HenryBrookshbrooks@lakesidecafe.comLos AngelesCA2022-06-04businessNaN
    4BrianGrahambgraham@bluecedarhomes.comSeattleWA2022-06-06businesspinterest
    5KyleJimenezkjimenez27@yahoo.comIndianapolisIN2022-06-07consumerNaN
    orders12,000 filas · 7 columnas
    • order_idinteger
    • customer_idinteger
    • order_datetimestamp
    • statusvarchar
    • channelvarchar
    • shipping_feedecimal
    • coupon_codevarchar
    Primeras 5 filas de orders
    order_idcustomer_idorder_datestatuschannelshipping_feecoupon_code
    10011252023-01-01 20:51:19completedweb0.00NaN
    10021562023-01-02 07:58:46completedweb0.00NaN
    1003222023-01-02 10:25:27completedmarketplace4.99WELCOME10
    1004482023-01-02 11:21:51completedmarketplace4.99WELCOME10
    1005822023-01-02 11:43:36completedweb0.00WELCOME10
    employees60 filas · 8 columnas
    • employee_idinteger
    • first_namevarchar
    • last_namevarchar
    • departmentvarchar
    • titlevarchar
    • manager_idinteger
    • hire_datedate
    • salaryinteger
    Primeras 5 filas de employees
    employee_idfirst_namelast_namedepartmenttitlemanager_idhire_datesalary
    1CatherineHaleExecutiveChief Executive OfficerNaN2016-03-01285000
    2RobertKimExecutiveChief Operating Officer12017-01-09235000
    3MeganCollinsSalesHead of Sales12018-04-16172000
    4ChloeGutierrezSalesAccount Executive32020-01-2172000
    5FrankBellSalesAccount Executive32023-05-2173000
    web_sessions40,000 filas · 7 columnas
    • session_idinteger
    • customer_idinteger
    • started_attimestamp
    • devicevarchar
    • sourcevarchar
    • pages_viewedinteger
    • convertedboolean
    Primeras 5 filas de web_sessions
    session_idcustomer_idstarted_atdevicesourcepages_viewedconverted
    1NaN2023-01-01 23:02:24mobilepaid1false
    2182023-01-01 15:07:49desktoppaid1false
    3NaN2023-01-01 16:55:46desktopdirect7false
    4NaN2023-01-01 12:43:28mobileorganic3false
    5NaN2023-01-01 13:06:21mobilesocial2false
    marketing_spend3,276 filas · 3 columnas
    • spend_datedate
    • channelvarchar
    • amountdecimal
    Primeras 5 filas de marketing_spend
    spend_datechannelamount
    2023-01-01paid492.99
    2023-01-01email37.38
    2023-01-01social200.53
    2023-01-02paid709.13
    2023-01-02email64.13

    La lección

    crosstab: una cuadrícula de recuentos a partir de dos columnas

    pd.crosstab es un atajo para el pivot más común: contar con qué frecuencia ocurre cada par de valores. Le pasas las dos columnas directamente:

    pd.crosstab(web_sessions["device"], web_sessions["converted"])
    # converted  False  True
    # device
    # desktop    13978   563
    # mobile     21029   520
    # tablet      3800   110

    El primer argumento pasa a ser las filas, el segundo las columnas. Los pares vacíos son 0, no NaN, porque un recuento de nada es cero. Es una función del módulo pandas (pd.crosstab), no un método de DataFrame, así que las columnas pueden incluso venir de tablas distintas siempre que sus filas se alineen.

    normalize: cuotas en lugar de recuentos

    Los recuentos brutos engañan cuando los grupos difieren en tamaño. Mobile tuvo 520 conversiones, cerca de las 563 de desktop, pero a partir de muchas más sesiones. El argumento normalize divide por un total:

    • normalize="index": cada celda ÷ el total de su fila. Cada fila suma 1. “De las sesiones en mobile, ¿qué proporción convirtió?”
    • normalize="columns": cada celda ÷ el total de su columna. Cada columna suma 1. “De las sesiones que convirtieron, ¿qué proporción fueron en mobile?”
    • normalize=True (o "all"): cada celda ÷ el total general.
    pd.crosstab(web_sessions["device"], web_sessions["converted"], normalize="index").round(3)
    # converted  False   True
    # desktop    0.961  0.039
    # mobile     0.976  0.024
    # tablet     0.972  0.028

    Desktop convierte al 3,9 % frente al 2,4 % de mobile: la cuota cuenta la historia que los recuentos ocultaban.

    Elegir la dirección

    Di la pregunta en voz alta y escucha el “de”. “De las devoluciones de cada categoría, ¿qué proporción es damaged?” divide por el total de la categoría (fila). “De todas las devoluciones damaged, ¿qué proporción es Furniture?” divide por el total del motivo (columna). Las dos dan números distintos a partir de los mismos recuentos, y ambas son respuestas correctas a preguntas distintas.

    margins=True añade una fila y una columna All con los totales, que es una forma rápida de comprobar los recuentos antes de normalizar: en los datos de devoluciones el total general es 1.673, todas las devoluciones de la tabla.

    Obtener la categoría

    Las devoluciones no llevan una categoría. Cada devolución apunta a una línea de pedido (order_item_id), la línea apunta a un producto, y el producto tiene la categoría. Dos merges la traen, y como cada devolución coincide con exactamente una línea y cada línea con un producto, el número de filas se mantiene en 1.673.

    Errores comunes

    • Normalizar en la dirección equivocada. Las filas suman 1 con "index", las columnas con "columns".
    • Comparar recuentos brutos entre grupos de tamaños muy distintos.
    • Pasar nombres de columna como cadenas, pd.crosstab("category", "reason"). crosstab recibe las columnas mismas, no sus nombres.
    • Informar cuotas sin los recuentos en que se apoyan. El 45,6 % de damaged de Furniture se apoya en solo 103 devoluciones; dilo.

    Elige qué puede ejecutarse en este sitio. Puedes cambiarlo cuando quieras desde "Configurar cookies", al pie de cada página.