Categorització¶
Exercici categorisation-annex.pdf · PDF
Obres un cofre en un joc i en surt una espasa. Et llegeixes el percentatge de drop, "0.37%"? No. Mires el color del nom. Comuna, Rara, Èpica, Llegendària. Una sola paraula i ja saps si te la quedes.
Algú va decidir on acaba "Rara" i on comença "Èpica". Aquella persona va convertir milers de números possibles en quatre etiquetes, perquè tu pogueres decidir en mig segon. En aquesta pàgina fas la mateixa feina amb games: 199 preus diferents es converteixen en cinc franges, i cada joc rep un nivell segons la mida de la seva audiència.
Què aprendràs
- Explicar per què convertim un número en una categoria, i què es perd en fer-ho
- Escriure un
CASE WHENamb diverses branques i predir quina branca agafa una fila concreta - Explicar per què importa l'ordre de les branques, i on acaba un
NULL - Construir
price_bandiowners_tier, i ordenar-los en el seu ordre lògic en lloc de l'alfabètic - Detectar una categoria escrita de dues maneres i fusionar-les
- Evitar la trampa: les franges no són "a les dades", les has dibuixat tu
De números a nivells de raresa¶
Compta quants preus diferents té la taula:
SELECT COUNT(DISTINCT price) FROM games; -- 199
199 preus diferents. Dibuixa una barra per preu i obtens 199 barres: il·legible. Ningú llegeix "drop rate 0.37%". Tothom llegeix "Èpic".
Una categoria és una etiqueta que posa un valor dins d'un grup. Categoritzar és substituir molts valors diferents per unes poques etiquetes.
Un interval (o franja, en anglès bin o band) és un d'aquests grups quan el valor original és un número: un rang amb un límit inferior i un de superior.
L'analogia de tota la pàgina és el nivell de raresa: una categoria és un número que s'ha fet llegible.
| El número | La categoria | |
|---|---|---|
| Al joc | Drop rate 0.37% | Èpic |
A games |
Preu 9.99 | 5 to 15 |
| Serveix per | Calcular: sumar, mitjana, ordenar | Llegir, agrupar, comparar grups |
| Quants valors | 199 preus | 5 franges |
Compte: guarda també el número
Categoritzar no substitueix el preu. Afegeix una etiqueta al costat, en una columna nova. Sempre pots tallar un número en franges noves més endavant. Mai no pots recuperar el número a partir d'una etiqueta.
CASE WHEN: la regla de classificació¶
CASE WHENés una columna calculada amb condicions: per a cada fila dona l'etiqueta de la primera condició que és certa.
L'esquelet:
CASE WHEN condition_1 THEN 'label 1'
WHEN condition_2 THEN 'label 2'
ELSE 'label for the rest' END AS new_column
Cada línia WHEN ... THEN ... és una branca. Tres regles ho decideixen tot:
| Regla | Què vol dir |
|---|---|
| De dalt a baix | Cada fila prova les branques en ordre i s'atura a la primera que és certa. L'ordre forma part de la lògica |
ELSE agafa la resta |
Tot el que no ha encaixat enlloc, incloent-hi allò en què no havies pensat. Sense ELSE, la resta es converteix en NULL |
NULL mai no és cert |
NULL < 5 no és cert ni fals: és desconegut. Un NULL passa per totes les comparacions fins a arribar a ELSE |
flowchart TB
R["<b>Una fila</b><br>price = ?"] --> W1{"price IS NULL?"}
W1 -- "cert" --> L1["'Free'"]
W1 -- "no cert" --> W2{"price menor que 5?"}
W2 -- "cert" --> L2["'Under 5'"]
W2 -- "no cert" --> W3{"price menor que 15?"}
W3 -- "cert" --> L3["'5 to 15'"]
W3 -- "no cert" --> W4{"price menor que 30?"}
W4 -- "cert" --> L4["'15 to 30'"]
W4 -- "no cert" --> E["<b>ELSE</b><br>'30 or more'"]
El joc gratuït que semblava car¶
Prova la regla més simple possible amb tres jocs que coneixes:
SELECT game, price,
CASE WHEN price < 5 THEN 'Under 5' ELSE '5 or more' END AS band
FROM games WHERE game IN ('Half-Life 2', 'Dota 2', 'Portal') ORDER BY game;
| game | price | band |
|---|---|---|
| Dota 2 | 5 or more | |
| Half-Life 2 | 9.99 | 5 or more |
| Portal | 9.99 | 5 or more |
Dota 2 és gratuït. Ha rebut la franja 5 or more. El seu preu és NULL, NULL < 5 no és cert, així que la fila ha caigut a ELSE. El joc amb més propietaris de tota la taula, i gratuït, etiquetat com a car. Cap missatge d'error.
Compte: ELSE no vol dir els cars
ELSE vol dir tota la resta, i "tota la resta" inclou les cel·les buides. Si un NULL mereix la seva pròpia etiqueta, anomena'l primer, a propòsit, amb WHEN column IS NULL.
Construir price_band¶
Cinc franges, preus en dòlars dels Estats Units. El cas NULL va primer:
SELECT CASE WHEN price IS NULL THEN 'Free'
WHEN price < 5 THEN 'Under 5'
WHEN price < 15 THEN '5 to 15'
WHEN price < 30 THEN '15 to 30'
ELSE '30 or more' END AS price_band,
COUNT(*) AS n
FROM games WHERE game IS NOT NULL
GROUP BY price_band ORDER BY MIN(price) NULLS FIRST;
| price_band | n |
|---|---|
| Free | 3094 |
| Under 5 | 11613 |
| 5 to 15 | 9046 |
| 15 to 30 | 2367 |
| 30 or more | 565 |
%%{init: {"themeVariables": {"xyChart": {"plotColorPalette": "#4051b5"}}}}%%
xychart-beta
title "Jocs per franja de preu"
x-axis ["Free", "Under 5", "5 to 15", "15 to 30", "30 or more"]
y-axis "Jocs" 0 --> 12000
bar [3094, 11613, 9046, 2367, 565]
Cinc files, que sumen 26,685. Cinc barres en lloc de 199.
Fixa't en la branca WHEN price < 15 THEN '5 to 15'. No diu price >= 5 AND price < 15. No cal: una fila només arriba a aquesta branca si price < 5 no ha estat cert. L'ordre ja fa aquesta feina.
Trenca-la dues vegades, a propòsit¶
La millor manera d'entendre les regles és fer malbé la consulta i mirar què passa.
Trencament 1 — mou una branca a dalt de tot. Posa WHEN price < 30 THEN '15 to 30' per sobre de totes les altres:
| price_band | n |
|---|---|
| 15 to 30 | 23026 |
| Free | 3094 |
| 30 or more | 565 |
Tots els jocs de menys de 30 dòlars s'aturen a la primera branca. Under 5 i 5 to 15 han desaparegut: 23,026 jocs porten ara l'etiqueta equivocada.
Trencament 2 — esborra la branca Free. Torna a posar l'ordre i treu la línia WHEN price IS NULL:
| price_band | n |
|---|---|
| Under 5 | 11613 |
| 5 to 15 | 9046 |
| 30 or more | 3659 |
| 15 to 30 | 2367 |
Els 3,094 jocs gratuïts han caigut a ELSE i s'han unit als 565 cars: 3,659 jocs "de 30 o més". Les dues consultes trencades s'executen sense cap error. Això és, una altra vegada, l'error silenciós de la lliçó de tipus.
| Error | Què passa | Com te n'adones |
|---|---|---|
| Una condició ampla posada primer | S'empassa les files pensades per a les branques de sota | Falten algunes franges al resultat |
Cap branca per a NULL |
Les cel·les buides cauen a ELSE |
La franja de ELSE és sospitosament gran |
Una errada en una etiqueta ('5 to 15 ') |
Es converteix en una categoria pròpia | Una franja de més |
Ordenar les categories en el seu ordre lògic¶
Per què ORDER BY MIN(price) i no ORDER BY price_band? Perquè una etiqueta és text, i el text s'ordena com un diccionari:
ORDER BY price_band |
ORDER BY MIN(price) NULLS FIRST |
|---|---|
| 15 to 30 | Free |
| 30 or more | Under 5 |
| 5 to 15 | 5 to 15 |
| Free | 15 to 30 |
| Under 5 | 30 or more |
Alfabèticament, 15 to 30 va primer, perquè el caràcter 1 va abans que 3 i 5. Per obtenir l'ordre lògic ordenes per alguna cosa que encara és un número: el preu més baix dins de cada franja. NULLS FIRST posa a dalt els jocs gratuïts, que no tenen preu.
Construir owners_tier¶
La segona categoria descriu l'audiència, amb el owners_min construït a la lliçó anterior. Tres nivells:
| Nivell | Regla | Significat |
|---|---|---|
Niche |
owners_min per sota de 20,000 |
El rang més baix: entre 0 i 20,000 propietaris |
Mid |
owners_min per sota d'1,000,000 |
De 20,000 fins a un milió |
Hit |
tota la resta | Un milió de propietaris o més |
Una columna creada en un SELECT no es pot reutilitzar en aquell mateix SELECT, així que l'expressió de owners_min s'escriu de nou dins del CASE:
CASE WHEN REGEXP_REPLACE(SPLIT_PART(owners, '..', 1), '[^0-9]', '', 'g')::bigint < 20000
THEN 'Niche'
WHEN REGEXP_REPLACE(SPLIT_PART(owners, '..', 1), '[^0-9]', '', 'g')::bigint < 1000000
THEN 'Mid'
ELSE 'Hit' END AS owners_tier,
Afegit a la consulta neta (el bloc ara es diu step3) i comptat amb SELECT owners_tier, COUNT(*) AS n FROM step3 GROUP BY owners_tier ORDER BY MIN(owners_min);:
| owners_tier | n |
|---|---|
| Niche | 17921 |
| Mid | 8141 |
| Hit | 623 |
Dos de cada tres jocs de la taula són Niche. Només 623 de 26,685 són un Hit.
Compte: recorda la unitat
Niche no vol dir "gairebé ningú no l'ha comprat". Vol dir que l'estimació diu "entre 0 i 20,000 propietaris". Un nivell construït sobre un límit inferior hereta la seva unitat.
Creuar dues categories¶
Les categories existeixen per ser creuades. Amb les dues columnes a step3, una sola consulta respon "quina franja de preu produeix més hits?":
SELECT price_band, COUNT(*) AS games,
SUM(CASE WHEN owners_tier = 'Hit' THEN 1 ELSE 0 END) AS hits,
ROUND(100.0 * SUM(CASE WHEN owners_tier = 'Hit' THEN 1 ELSE 0 END) / COUNT(*), 1) AS hit_pct
FROM step3 GROUP BY price_band ORDER BY MIN(price) NULLS FIRST;
| price_band | games | hits | hit_pct |
|---|---|---|---|
| Free | 3094 | 182 | 5.9 |
| Under 5 | 11613 | 47 | 0.4 |
| 5 to 15 | 9046 | 168 | 1.9 |
| 15 to 30 | 2367 | 167 | 7.1 |
| 30 or more | 565 | 59 | 10.4 |
El SUM(CASE ... THEN 1 ELSE 0 END) és un truc per comptar: cada hit suma 1, tota la resta suma 0. La proporció de hits va del 0.4% entre els jocs de pagament més barats al 10.4% entre els més cars.
Compte: un preu més alt no fa un èxit
La taula mostra que els jocs cars són hits més sovint. No mostra per què. Els estudis grans cobren més i venen més: la mida de l'estudi pot explicar les dues xifres. Dues coses que es mouen juntes no vol dir que una causi l'altra.
On van els límits?¶
Un límit és el valor on acaba un interval i comença el següent.
Per què < 5 i no <= 5? Mira els preus més habituals:
SELECT price, COUNT(*) FROM games GROUP BY price ORDER BY 2 DESC LIMIT 3;
| price | count |
|---|---|
| 9.99 | 3686 |
| 4.99 | 3204 |
| (buit) | 3095 |
Els preus s'amunteguen just per sota del número rodó: 4.99, 9.99. Per això el límit va sobre el número rodó, i tothom està d'acord en quin costat cau 4.99.
| Bona pràctica | Per què |
|---|---|
| Posa els límits en números rodons | Fàcils de dir, fàcils de recordar, i els preus s'agrupen just per sota |
Usa una sola direcció a tot arreu (< a cada branca) |
Cap valor pot caure en dos intervals ni en cap |
Anomena els intervals pels seus límits (5 to 15) |
El lector veu la regla a l'etiqueta |
Dona al NULL el seu propi interval |
Si no, s'amaga dins de ELSE |
Compte: les franges no són a les dades
Tu has dibuixat les línies al 5, al 15 i al 30. Mou una línia i la història canvia. Un interval és una decisió: té un autor i s'ha d'escriure a l'informe.
I un interval llença informació. Dins de 30 or more, un joc a 39.99 i un programari a 595.99 ara són el mateix.
Categories brutes¶
Les categories de text també s'embruten. Quants editors hi ha?
SELECT COUNT(DISTINCT publisher) AS as_written,
COUNT(DISTINCT LOWER(publisher)) AS ignoring_case
FROM games;
| as_written | ignoring_case |
|---|---|
| 13951 | 13863 |
LOWER converteix un text en minúscules. Ignorant les majúscules, desapareixen 88 "editors": eren segones grafies d'un que ja existia. Mira'n dos:
SELECT publisher, COUNT(*) FROM games
WHERE LOWER(publisher) IN ('big fish games', 'capcom')
GROUP BY publisher ORDER BY 1;
| publisher | count |
|---|---|
| Big FIsh Games | 1 |
| Big Fish Games | 284 |
| CAPCOM | 1 |
| Capcom | 33 |
Per a tu, dos editors. Per a una base de dades, quatre. La mateixa eina els fusiona:
CASE WHEN LOWER(publisher) = 'big fish games' THEN 'Big Fish Games'
ELSE publisher END AS publisher
Això dona un sol Big Fish Games amb 285 jocs. A la taula de classe no arreglem les 88 grafies: les coneixem, i això va a l'informe. Conèixer un límit i deixar-lo escrit també és una decisió.
Prova-ho: franges i nivells¶
Obre SQL → SQL Lab, base de dades Dades classe, esquema public. Executa una sentència cada vegada.
Pas 1 — price_band. Executa la consulta de cinc franges sobre games. Hauries de veure cinc files en l'ordre Free, Under 5, 5 to 15, 15 to 30, 30 or more, que sumen 26,685.
Pas 2 — Trenca-la dues vegades. Fes els dos canvis descrits més amunt, un cada vegada. Abans d'arreglar-ne cap, apunta els recomptes i una frase que digui on han anat a parar els jocs.
Pas 3 — Afegeix les dues columnes a la consulta neta. Obre games_step2 a SQL → Saved Queries, canvia el nom del bloc a step3, i afegeix el teu price_band i l'expressió de owners_tier. Compte amb la coma abans de cada CASE nou. Comprova-ho amb el recompte d'owners_tier: Niche 17,921, Mid 8,141, Hit 623.
Pas 4 — Desa-la. Prem Save, canvia el nom a games_step3, tria Save as new.
Pas 5 — Creua-les. Conserva el bloc WITH step3 i executa la consulta dels hits. Hauries de poder dir quina franja té la proporció de hits més alta i quina la més baixa.
La base de dades no troba la columna price_band
Una columna creada amb AS no es pot fer servir al WHERE ni en una altra columna del mateix SELECT. Només existeix un nivell més amunt, al SELECT que llegeix de step3. Per això la consulta neta viu dins d'un bloc WITH.
Idees clau¶
- Una categoria fa llegible un número: 199 preus es converteixen en 5 intervals. El número es queda a la seva pròpia columna, perquè una etiqueta no es pot tornar a convertir en número.
CASE WHENprova les seves branques de dalt a baix i s'atura a la primera certa. L'ordre forma part de la lògica.ELSEagafa tota la resta, inclòsNULL. Anomena primer el casNULL, ambIS NULL.- Un ordre equivocat o una branca que falta no dona cap error: comprova els recomptes de cada franja.
- Ordena les categories per un número (
ORDER BY MIN(price)), no per l'etiqueta, que s'ordena alfabèticament. - Els límits són decisió teva. Posa'ls en números rodons, usa una sola direcció i deixa'ls escrits.
- Les categories de text també s'embruten:
CapcomiCAPCOMsón dos valors fins que els fusiones.
Comprovació ràpida¶
1. En un CASE WHEN amb diverses branques, quina branca agafa una fila?
- L'última branca amb la condició certa
- La primera branca amb la condició certa, llegint de dalt a baix
- La branca amb la condició més estreta
- Totes les branques amb la condició certa
Una fila prova les branques en ordre i s'atura a la primera certa. Per això l'ordre forma part de la lògica: una condició ampla posada primer s'empassa les files pensades per a les branques de sota.
2. Amb CASE WHEN price < 5 THEN 'Under 5' ELSE '5 or more' END, quina etiqueta rep Dota 2 (preu NULL)?
-
Under 5, perquè un joc gratuït costa menys de 5 -
5 or more, perquèNULL < 5no és cert i la fila cau aELSE -
NULL, perquè el preu és buit - La consulta dona un error
Una comparació amb NULL no és mai certa: és desconeguda. La fila no encaixa en cap branca i arriba a ELSE, que agafa tota la resta. Un joc gratuït acaba etiquetat com a car, sense cap error. La solució és una primera branca WHEN price IS NULL THEN 'Free'.
3. Mous WHEN price < 30 THEN '15 to 30' a dalt de tot de la consulta price_band. Què passa?
- Res: l'ordre de les branques no importa
- La consulta s'atura amb un error
- 23,026 jocs reben l'etiqueta
15 to 30, iUnder 5i5 to 15desapareixen - Només canvien de franja els jocs de més de 30 dòlars
Tot preu per sota de 30 també compleix price < 30, així que totes aquestes files s'aturen a la primera branca. La consulta s'executa i retorna tres franges en lloc de cinc. Una franja que falta al resultat és la pista.
4. Per què el resultat s'ordena amb ORDER BY MIN(price) NULLS FIRST i no amb ORDER BY price_band?
- Perquè
ORDER BYno es pot usar amb una columna deCASE - Perquè ordenar per preu és més ràpid
- Perquè les etiquetes són text i s'ordenen alfabèticament:
15 to 30aniria abans que5 to 15 - Perquè
price_bandconté valorsNULL
Una etiqueta és text, i el text s'ordena com un diccionari: 1 abans de 5. Per obtenir l'ordre lògic ordenes per alguna cosa que encara és un número, com el preu més baix de cada franja.
5. Per què el límit s'escriu price < 5 i no price <= 5?
- Perquè
<=no existeix a PostgreSQL - Perquè cap joc no costa exactament 5 dòlars
- Perquè els preus s'amunteguen just per sota dels números rodons (4.99, 9.99), així que un límit sobre el número rodó els separa netament
- Perquè
<és més ràpid que<=
Els dos preus més habituals són 9.99 i 4.99. Posar cada límit sobre el número rodó, sempre amb <, fa que cada valor caigui en exactament un interval i que tothom estigui d'acord en quin costat és 4.99.
6. COUNT(DISTINCT publisher) dona 13,951 i COUNT(DISTINCT LOWER(publisher)) dona 13,863. Què et diu la diferència?
- 88 editors no tenen cap joc
- 88 files tenen l'editor buit
- 88 valors només són una grafia diferent, en majúscules, d'un editor que ja hi és
-
LOWERha esborrat 88 files de la taula
LOWER converteix el text en minúscules, així que CAPCOM i Capcom es converteixen en el mateix valor. Els 88 "editors" que falten mai no van ser empreses diferents: són categories brutes, una mateixa cosa escrita de dues maneres.
7. Algú escriu CASE WHEN metascore >= 50 THEN 'Mixed' WHEN metascore >= 75 THEN 'Good' ELSE 'Bad' END. Tria les dues coses que hi ha malament.
- Un joc amb una puntuació de 90 rep
Mixed, perquè>= 50és cert primer: la branca>= 75ha d'anar per sobre -
CASEno es pot usar en una columna numèrica - Un joc sense puntuació rep
Bad, perquèNULLcau aELSE: necessita la seva pròpia brancaIS NULL - Les etiquetes s'han d'ordenar alfabèticament dins del
CASE
Les dues regles d'aquesta pàgina alhora. Executa-ho sobre games i cap joc no és Good, mentre que 23,952 són Bad, gairebé tots jocs que simplement mai no han estat valorats. Arreglat (IS NULL primer, després >= 75, després >= 50), la taula té 23,838 sense puntuació, 1,457 Mixed, 1,279 Good i només 114 Bad.
Una de les franges d'avui no era un preu: Free era una suposició sobre què vol dir una cel·la buida. Teníem dret a fer-la? I què passa amb 23,838 puntuacions buides? A continuació: Imputació.