El bloque <mix>
Úselo cuando las proporciones de una columna no son iguales y además cada
variante es más que una sola palabra. Los datos reales son desparejos: casi todos
los pedidos están paid y muy pocos cancelled; casi todas las cuentas son free
y muy pocas premium. Usted quiere una columna donde las variantes aparezcan en
proporciones fijas — ni repartidas por igual, ni como ruido aleatorio.
<mix> es una distribución: una fuente con nombre que reparte sus variantes —
las ramas <case> — entre las filas en porcentajes
exactos. Piénselo como una <sequence> cuyos
valores se distribuyen por percent, salvo que cada rama puede ser todo un
compuesto de literales y generadores en vez de un único valor simple. El reparto es
determinista para una seed dada.
Las salidas de ejemplo que siguen son ilustrativas — los valores exactos que produce
una seed dada pueden cambiar entre versiones del core, pero los conteos que
garantiza una máscara percent nunca cambian.
- los porcentajes escritos en la configuración
- la proporción que realmente se produjo
Una distribución con nombre
<mix> va directamente en <env>, justo
al lado de <sequence> — no hace falta ningún envoltorio, basta con darle un
name. El valor se lee con ${{Nombre}}, exactamente igual que cualquier otra
fuente con nombre:
<env count="100" seed="demo" inject="${{%}}">
<mix name="Code" percent="25,70">
<case><gen type="text" value="A"/></case>
<case><gen type="text" value="B"/></case>
<case><gen type="text" value="C"/></case>
</mix>
</env>
<block>
<line><data>${{Code}}</data></line>
</block>
Las primeras filas no dicen nada — las proporciones solo se ven a lo largo de toda la muestra:
A B A B B A
Cuente las 100 filas y el reparto es exacto:
A 25 B 70 C 5
Exactamente 25 / 70 / 5. La máscara fija las dos primeras proporciones; la tercera
rama se lleva el resto, 100 − 25 − 70 = 5. Esto no es «como 25 %»: es un
reparto exacto por el método de Hamilton (mayores restos), el mismo que gobierna
percent en el generador text.
Cambie las proporciones y cambia el reparto
Las mismas ramas A/B/C, pero con percent="60,30":
<mix name="Code" percent="60,30">
<case><gen type="text" value="A"/></case>
<case><gen type="text" value="B"/></case>
<case><gen type="text" value="C"/></case>
</mix>
A 60 B 30 C 10
60 / 30, y el sobrante 10 se va a la tercera rama. Un solo número de la máscara
vuelve a cortar la columna entera.
Cuándo se necesita <mix> — y cuándo basta con text
Para una simple distribución de cadenas ya hechas, <mix> es excesivo: el generador
text ya reparte proporciones exactas con percent.
<sequence name="Gender">
<gen type="text" value="Hombre,Mujer" percent="50,50"/>
</sequence>
Hombre 10 Mujer 10
<mix> se gana su lugar solo cuando las ramas son compuestas — cuando cada
variante se arma con su propia mezcla de texto literal y generadores. Ese es el caso
al que llevan las secciones siguientes.
Atributos
| Atributo | Obligatorio | Qué hace |
|---|---|---|
name | sí | El nombre para interpolar con ${{Nombre}} |
percent | no | La proporción de cada <case>; omítalo para un reparto uniforme |
parent | no | Una secuencia padre — el reparto se calcula dentro de su subconjunto |
flag | no | Agrega una columna de respuestas que marca la rama atípica (ver más abajo) |
comment | no | Una nota libre para el autor de la configuración; nunca se renderiza |
Un <mix> debe contener al menos un <case> — una rama.
Todo lo demás es opcional.
percent — opcional, y las máscaras cortas
Deje percent fuera por completo y las ramas se reparten de forma uniforme.
Tres casos sobre 99 filas dan 33 cada uno:
<mix name="Bucket">
<case><gen type="text" value="low"/></case>
<case><gen type="text" value="mid"/></case>
<case><gen type="text" value="high"/></case>
</mix>
low 33 mid 33 high 33
Cuando sí se da una máscara, esta sigue la misma gramática que
percent en text: un número fija la proporción de esa
rama, y cada posición vacía — una coma suelta dentro de la máscara ("25,,70") o
una coma final ("25,70,") — reparte por igual lo que falta para llegar a 100. Los
dos ejemplos del inicio de esta página ya se apoyan en esa regla: percent="25,70"
deja que la tercera rama absorba el resto.
parent — una distribución dentro de un subconjunto
Déle un parent a un <mix> y los porcentajes se cuentan contra el subconjunto
filtrado de filas, no contra el count completo — la misma regla que gobierna una
<sequence> dependiente. Aquí las cuentas de paga
reciben un desglose por nivel; las cuentas gratuitas dejan la columna vacía:
<sequence name="Segment">
<gen type="text" value="Free,Paid" percent="70,30"/>
</sequence>
<mix name="Tier" parent="Segment.Paid" percent="60,30">
<case><gen type="text" value="Silver"/></case>
<case><gen type="text" value="Gold"/></case>
<case><gen type="text" value="Platinum"/></case>
</mix>
Sobre count="100", 30 filas son Paid. La máscara 60 / 30 se aplica a esas 30
filas, así que Tier se reparte 18 / 9 / 3:
Silver 18 Gold 9 Platinum 3
18 + 9 + 3 = 30 — todo el subconjunto de paga, y no un porcentaje del total de 100. Este es el corazón del modelo jerárquico; el tratamiento completo, con niveles
anidados, está en
Dependencias jerárquicas.
<mix> se anida
Un <case> puede contener a su vez un <mix> anidado, y el reparto anidado se
cuenta contra las filas que eligieron la rama externa — la misma regla de
subconjunto, un nivel más adentro. Aquí un tercio de todas las filas son error, y
dentro de ellas un <mix> interno gradúa la severidad:
<mix name="Status" percent="34,33">
<case>
<gen type="text" value="ok"/>
</case>
<case>
<gen type="text" value="warn"/>
</case>
<case>
<mix percent="70,20">
<case><data>error/minor</data></case>
<case><data>error/major</data></case>
<case><data>error/fatal</data></case>
</mix>
</case>
</mix>
Sobre count="100" el reparto externo es 34 ok / 33 warn / 33 error. La máscara
interna 70 / 20 divide entonces esas 33 filas de error en 23 / 7 / 3:
ok 34 warn 33 error/minor 23 error/major 7 error/fatal 3
23 + 7 + 3 = 33 — exactamente el subconjunto de errores.
Lo mismo vale un nivel más arriba: un <mix> escrito dentro de una rama de
<switch> toma su cuota sobre las
filas que esa rama capturó, no sobre la ejecución completa.
Ramas compuestas
Esto es lo que <mix> le da y una lista pelada de cadenas no puede dar: un <case>
puede armar su valor con varias piezas — un fragmento literal
<data>, uno o más
generadores y <mix> anidados. En este contexto
<data> es solo un trozo literal del valor (texto de pegamento), no formato de
salida — para eso vea
Máscaras y mayúsculas.
<mix name="Charge" percent="10,12,34,">
<case><data>reembolso: </data><gen type="number" value="1..10"/></case>
<case><data>contracargo: </data><gen type="number" value="11..20"/></case>
<case><gen type="number" value="21..40"/></case>
<case><gen type="number" value="41..100"/><data> (marcado)</data></case>
</mix>
36 reembolso: 4 contracargo: 18 66 (marcado) reembolso: 8 reembolso: 1 73 (marcado) 82 (marcado)
Cada rama armó su propia forma: reembolso: 4 es el literal reembolso: más un
number en 1..10; 66 (marcado) es un número en
41..100 seguido del literal (marcado); la tercera rama es un número pelado sin
ningún envoltorio. Agrupe las 100 filas por rama y las proporciones siguen siendo
exactas:
reembolso 10 contracargo 12 simple 34 marcado 44
10 / 12 / 34 / 44. La última rama no tiene porcentaje propio — la coma final de
percent="10,12,34," la deja abierta, así que se lleva el resto, 44.
Una distribución genera — no da formato
<mix> produce datos, así que vive únicamente en <env>. No se puede poner
dentro del bloque de salida: un <mix> directamente en un <line> se rechaza antes
de la corrida con el error TDC132, porque el
bloque de salida es solo para la
disposición. Declare <mix name="…"> en <env> e interpole ${{Nombre}} donde
quiera el valor.
Si necesita una elección que no sea por porcentaje, dos vecinos la cubren:
<switch>elige por una clave — una tabla de consulta, comopaís → moneda.- Una
<sequence>con ramas condicionales<gen if="…">elige por una condición arbitraria — gana la primera rama verdadera.
Marcar valores atípicos con flag
Una rama se puede etiquetar como anómala — <case anomaly="true"> — y usted puede
pedirle al mix una columna de respuestas mediante flag. El resultado es un
conjunto de datos contra el cual probar un detector de anomalías: los valores
atípicos están ahí, y una columna acompañante registra exactamente en qué filas
cayeron.
<mix name="Temp" percent="75,25" flag="Bad">
<case><gen type="number" value="20..24"/></case>
<case anomaly="true"><gen type="number" value="90..99"/></case>
</mix>
${{Bad}} vale true justo en las filas que salieron de la rama etiquetada — el
25 % de ellas — y false en todas las demás. La etiqueta se deriva de la misma
decisión que eligió la rama, así que nunca puede contradecir al valor.
anomaly="true" es solo una etiqueta: el valor atípico en sí es lo que produzca el
generador de esa rama, y por eso usted conserva el control total sobre cómo se ve.
Este es apenas un rincón de un tema más amplio — la inyección de valores atípicos y
la columna flag reciben su tratamiento completo en la guía de anomalías.
Siguiente paso
- Generador text — proporciones
percentexactas para una lista simple de opciones, cuando las ramas son palabras sueltas. - Secuencias — la fuente con nombre junto a la
cual vive
<mix>, y el modeloparentque comparten. - Dependencias jerárquicas — la
historia completa de
parent, con porcentajes anidados en varios niveles.