pccpy
Control Estadístico de Procesos (SPC) en Python, al estilo Minitab.
pccpy es una librería de SPC en español diseñada para ingenieros y técnicos que conocen
Minitab y quieren hacer el mismo análisis desde Python. Todas las convenciones de
nomenclatura (LCS/LCI, LEI/LES, Cp/Cpk/Pp/Ppk, Z.Bench, PPM, Anderson-Darling),
los métodos de estimación de sigma y las 8 pruebas de causas especiales siguen lo que
documenta Minitab.
Índice
- Instalación
- Inicio rápido
- Cartas de variables
- Cartas de atributos
- Cartas de tiempo ponderado
- Cartas avanzadas
- Cartas multivariadas
- Pruebas de causas especiales
- Visualización de las cartas
- Capacidad del proceso
- Normalidad, Pareto y constantes SPC
- Acceso a los datos del resultado
- Validación
- Desarrollo
- Licencia
Instalación
pip install pccpy
Desde GitHub (versión de desarrollo):
pip install git+https://github.com/LeoSanta15/pccpy.git
Requiere Python ≥ 3.9 con NumPy, SciPy, pandas y matplotlib.
Inicio rápido
import numpy as np
import pccpy as pp
rng = np.random.default_rng(1)
x = rng.normal(100, 2, 60)
x[40:] += 3 # el proceso se desplaza en la observación 41
# Calcular carta I-MR con las 8 pruebas de causas especiales
carta = pp.imr_chart(x, tests=(1, 2, 3, 4, 5, 6, 7, 8))
print(carta.summary()) # resumen tipo sesión de Minitab
carta.violations() # DataFrame: panel, punto, prueba, descripción
carta.to_frame() # todos los valores, límites y pruebas fallidas
carta.plot() # figura de matplotlib (se muestra con plt.show())
Cartas de variables
Carta I-MR
La carta Individuales y Rango Móvil es la opción estándar cuando cada observación es una medición única (no hay subgrupos). Produce dos paneles:
- Panel I: valores individuales con límites ±3σ en torno a la media.
- Panel MR: rangos móviles sucesivos con su límite superior.
import numpy as np
import pccpy as pp
x = np.array([10.2, 10.5, 9.8, 10.1, 10.4, 9.9, 10.3, 10.6,
9.7, 10.0, 10.2, 10.8, 9.6, 10.1, 10.3])
carta = pp.imr_chart(
x,
span=2, # longitud del rango móvil (defecto: 2, igual que Minitab)
sigma_method="mr", # estimador de sigma: 'mr' (defecto), 'median_mr', 'mssd'
tests=(1, 2, 3), # qué pruebas de causas especiales activar
)
print(carta.summary())
Opciones de sigma_method:
| Método | Cálculo | Cuándo usarlo |
|---|---|---|
'mr' |
MR_prom / d2 |
por defecto; el mismo que Minitab |
'median_mr' |
mediana(MR) / 0.9540 |
más robusto ante valores atípicos (solo span=2) |
'mssd' |
√(MSSD / 2) |
cuando no hay observaciones consecutivas correladas |
Cartas Xbar-R y Xbar-S
Cuando los datos se recogen en subgrupos (varias mediciones por muestra), las cartas Xbar-R (subgrupos pequeños, n ≤ 8) y Xbar-S (subgrupos grandes, n > 8) estiman sigma usando la variación dentro de cada subgrupo, lo que las hace más sensibles a desplazamientos de la media que la carta I-MR.
datos = np.array([
[20.1, 20.3, 20.0, 20.2, 19.9],
[20.4, 20.1, 20.5, 20.2, 20.3],
# ... una fila por subgrupo
])
carta_r = pp.xbar_r_chart(
datos,
sigma_method="rbar", # 'rbar' (defecto) o 'pooled'
tests=(1, 2, 3, 4, 5, 6, 7, 8),
)
carta_s = pp.xbar_s_chart(
datos,
sigma_method="sbar", # 'sbar' (defecto) o 'pooled'
)
Opciones de sigma_method para Xbar:
| Método | Cálculo | Cuándo usarlo |
|---|---|---|
'rbar' |
R_prom / d2(n) |
Xbar-R, subgrupos de tamaño fijo (igual que Minitab) |
'pooled' |
S_pooled / c4(n_total) |
Xbar-R o Xbar-S, mejor estimación con muchos subgrupos |
'sbar' |
S_prom / c4(n) |
Xbar-S, subgrupos de tamaño fijo (igual que Minitab) |
Formatos de entrada de datos
Todas las cartas de variables aceptan tres formatos equivalentes:
# 1. Matriz 2-D: cada fila es un subgrupo
datos_2d = np.array([[20.1, 20.3, 20.0],
[20.4, 20.1, 20.5],
[19.9, 20.2, 20.1]])
pp.xbar_r_chart(datos_2d)
# 2. Vector 1-D + tamaño de subgrupo fijo
vector = datos_2d.ravel() # [20.1, 20.3, 20.0, 20.4, 20.1, 20.5, ...]
pp.xbar_r_chart(vector, subgroup_size=3)
# 3. Vector 1-D + identificador de subgrupo (permite tamaños desiguales)
ids = np.repeat(["S1", "S2", "S3"], 3)
pp.xbar_r_chart(vector, subgroup=ids)
# También acepta pandas Series y DataFrame directamente
import pandas as pd
df = pd.DataFrame({"medida": vector, "subgrupo": ids})
pp.xbar_r_chart(df["medida"], subgroup=df["subgrupo"])
Parámetros históricos y etapas
Equivalente a Opciones de estimación y Etapas en Minitab:
# Parámetros conocidos (no se estiman de los datos)
pp.imr_chart(x, mu=100.0, sigma=2.0)
# Etapas: los límites se calculan de forma independiente por etapa
etapas = ["Antes"] * 30 + ["Después"] * 30
carta = pp.imr_chart(x, stages=etapas)
carta.params # lista de dicts, uno por etapa
carta.params[0] # {'stage': 'Antes', 'media': ..., 'sigma': ..., ...}
carta.params[1] # {'stage': 'Después', 'media': ..., 'sigma': ..., ...}
# Combinación: parámetros históricos + etapas (los mismos parámetros para todas)
pp.imr_chart(x, mu=100, sigma=2, stages=etapas)
Cartas de atributos
Cuando la característica de calidad es discreta (piezas defectuosas, número de defectos) se usan cartas de atributos. Las cartas de Laney corrigen la sobredispersión (variabilidad mayor a la esperada por el modelo teórico), un problema frecuente con tamaños de muestra grandes.
# P: fracción defectuosa (n puede variar entre muestras)
defectuosos = np.array([3, 5, 2, 4, 6, 1, 3, 5, 2, 4])
n_muestral = np.full(10, 200) # tamaño de cada muestra
pp.p_chart(defectuosos, n=n_muestral)
# NP: número de defectuosos (requiere n constante)
pp.np_chart(defectuosos, n=200)
# C: número de defectos por unidad (n fijo = 1 unidad por muestra)
defectos = np.array([2, 1, 3, 0, 4, 2, 1, 3, 2, 1])
pp.c_chart(defectos)
# U: tasa de defectos por unidad (n puede variar)
n_unidades = np.array([1, 1, 2, 1, 2, 1, 1, 2, 1, 2])
pp.u_chart(defectos, n=n_unidades)
# Laney P': igual que P pero corrige sobredispersión (phi != 1)
pp.laney_p_chart(defectuosos, n=n_muestral)
# Laney U': igual que U pero corrige sobredispersión
pp.laney_u_chart(defectos, n=n_unidades)
Cuando n es un escalar se aplica el mismo tamaño a todas las muestras. Con n
variable los límites se calculan individualmente para cada punto.
Cartas de tiempo ponderado
EWMA
La carta Media Móvil Exponencialmente Ponderada es más sensible que I-MR a pequeños desplazamientos de la media (típicamente ≤ 1.5σ). Los límites exactos se ensanchan en los primeros puntos hasta estabilizarse, igual que Minitab.
carta = pp.ewma_chart(
x,
weight=0.2, # λ: factor de suavizado (0 < λ ≤ 1); menor = más memoria
k=3.0, # multiplicador de sigma para los límites (defecto: 3)
tests=(1,), # solo la prueba 1 tiene sentido en EWMA
)
# El 'sigma_method' de la carta subyacente se configura con sigma_method='mr'
Guía de selección de λ:
| λ | Detecta mejor | Memoria |
|---|---|---|
| 0.05 – 0.10 | desplazamientos muy pequeños (¼σ) | mucha |
| 0.20 | desplazamientos moderados (½σ – 1σ) | moderada (recomendado Minitab) |
| 0.40+ | parecido a carta Shewhart | poca |
CUSUM
La carta Suma Acumulada también detecta pequeños desplazamientos. Usa el esquema
tabular de Hawkins: dos acumuladores (superior C⁺ e inferior C⁻) que parten de 0
y se comparan con el límite de decisión H.
carta = pp.cusum_chart(
x,
h=4.0, # límite de decisión H (en unidades de sigma); defecto: 4 (= 4σ)
k=0.5, # zona de referencia K (en unidades de sigma); defecto: 0.5
# Con H=4, K=0.5 el ARL en control es ≋370 (estándar de la industria)
tests=(1,),
)
Regla práctica:
H = 4σyK = 0.5σequilibran la detección de un desplazamiento de 1σ con un ARL fuera de control ≈ 10 y un ARL en control ≈ 370.
Media móvil
La carta MA promedia los últimos length puntos para suavizar el ruido.
Los primeros length - 1 puntos usan el promedio de los datos disponibles,
por lo que sus límites son más amplios.
pp.ma_chart(
x,
length=5, # ventana de la media móvil; defecto: 3
tests=(1,),
)
Cartas avanzadas
Z-MR (corridas cortas)
Cuando se fabrican piezas con especificaciones distintas (distintas medias o variabilidades nominales) no se pueden trazar en la misma carta I-MR estándar. La carta Z-MR estandariza cada observación con los parámetros de su parte, permitiendo visualizar todas en una sola carta con límites ±3.
partes = ["A"] * 10 + ["B"] * 10 + ["A"] * 10
medidas = np.r_[
rng.normal(50, 1, 10), # parte A: media 50, sigma 1
rng.normal(80, 2, 10), # parte B: media 80, sigma 2
rng.normal(50, 1, 10), # parte A de nuevo
]
carta = pp.zmr_chart(
medidas,
partes,
sigma_method="by_part", # 'constant', 'relative', 'by_part', 'by_run'
# mu y sigma: dict {parte: valor} para parámetros históricos o nominales
# mu={"A": 50, "B": 80}, sigma={"A": 1, "B": 2}
)
Opciones de sigma_method para Z-MR:
| Método | Descripción |
|---|---|
'constant' |
misma sigma para todas las partes |
'relative' |
sigma proporcional a la media de la parte |
'by_part' |
sigma estimada por rango móvil dentro de cada parte (defecto) |
'by_run' |
sigma estimada por rango móvil dentro de cada corrida (bloque consecutivo) |
I-MR-R/S (variación entre/dentro)
Cuando los subgrupos tienen una variación entre subgrupos grande (diferencias de operario, turno, lote), la carta Xbar-R genera falsas alarmas porque su límite de control solo refleja la variación dentro. La carta I-MR-R/S descompone es dos fuentes y las trata por separado.
# sub: matriz (n_subgrupos x tamaño_subgrupo)
sub = rng.normal(20, 1, (25, 5)) + rng.normal(0, 1.5, (25, 1)) # variación entre grupos
carta = pp.imr_rs_chart(
sub,
within="r", # 'r' (rango, defecto) o 's' (desviación estándar)
)
carta.params[0]
# {'sigma_dentro': 0.97, 'sigma_entre': 1.48, 'sigma_entre_dentro': 1.79, ...}
Eventos raros (G y T)
Cuando los eventos son tan infrecuentes que las cartas P o C darían muchos puntos en cero, se usan las cartas G (número de casos/piezas entre eventos) y T (tiempo entre eventos).
# G: número de casos entre eventos (distribución geométrica)
entre_eventos = rng.geometric(0.02, 40) - 1 # p = probabilidad del evento
pp.g_chart(entre_eventos)
# T: tiempo entre eventos (distribución Weibull o exponencial)
tiempos = rng.weibull(1.5, 40) * 30
pp.t_chart(tiempos) # Weibull (defecto)
pp.t_chart(tiempos, dist="exp") # exponencial
Los límites de la carta G se basan en percentiles exactos de la distribución geométrica; los de la carta T en los de la Weibull o exponencial ajustada por máxima verosimilitud.
Cartas multivariadas
T² de Hotelling
Equivalente multivariado de la carta I-MR o Xbar. Detecta desplazamientos
simultáneos en varias variables correlacionadas. El método contributions()
identifica qué variable(s) causaron la señal.
Sigma = [[1, .6, .3], [.6, 1, .2], [.3, .2, 1]]
hist = rng.multivariate_normal([0, 0, 0], Sigma, 100) # datos de Fase I
nuev = rng.multivariate_normal([0, 0, 0], Sigma, 50)
nuev[35:, 2] += 4 # variable 3 se desplaza en el punto 36
# --- Fase I: parámetros estimados de los mismos datos ---
carta1 = pp.t2_chart(hist)
print(carta1.summary())
# --- Fase II: parámetros tomados del periodo histórico ---
carta2 = pp.t2_chart(
nuev,
mu=hist.mean(axis=0),
cov=np.cov(hist, rowvar=False),
n_hist=100, # n de la estimación histórica (afecta el límite)
)
# Diagnosticar: ¿qué variable causó la señal en el punto 36?
carta2.contributions(36) # pandas Series con la contribución de cada variable
# Con subgrupos (una fila = una observación; subgroup_size agrupa de a n filas)
pp.t2_chart(nuev, subgroup_size=5)
# Con DataFrame: los nombres de columna aparecen en contributions()
import pandas as pd
df = pd.DataFrame(nuev, columns=["Temperatura", "Presión", "Flujo"])
pp.t2_chart(df)
Tipo de límite según lo que se provea:
mu / cov |
n_hist |
Distribución | Fase |
|---|---|---|---|
| No dados | — | Beta (individuales) / F (subgrupos) | I |
| Dados | Dado | F ajustada a n_hist | II |
| Dados | No dado | χ² | parámetros conocidos |
Varianza generalizada
Panel complementario al T² para datos en subgrupos: monitorea la dispersión
multivariada mediante el determinante de la matriz de covarianza muestral |S|.
pp.generalized_variance_chart(
nuev,
subgroup_size=5,
mu=hist.mean(axis=0),
cov=np.cov(hist, rowvar=False),
)
MEWMA
Versión multivariada de la carta EWMA. Muy sensible a desplazamientos pequeños y sostenidos en el vector de medias.
carta = pp.mewma_chart(
nuev,
mu=hist.mean(axis=0),
cov=np.cov(hist, rowvar=False),
weight=0.1, # λ (defecto: 0.1)
arl=200, # ARL objetivo en control (el límite H se calcula automáticamente)
)
# Calcular el límite H por separado
H = pp.mewma_limit(p=3, weight=0.1, arl=200)
print(f"H = {H:.3f}") # p: número de variables
MCUSUM
Versión multivariada de la carta CUSUM (esquema de Crosier). También detecta pequeños desplazamientos sostenidos.
carta = pp.mcusum_chart(
nuev,
mu=hist.mean(axis=0),
cov=np.cov(hist, rowvar=False),
k=0.5, # zona de referencia (defecto: 0.5)
arl=200, # el límite H se calcula automáticamente
)
H = pp.mcusum_limit(p=3, k=0.5, arl=200)
Etapas y Box-Cox en cartas multivariadas
Las 4 cartas multivariadas (T², varianza generalizada, MEWMA y MCUSUM) aceptan
stages y boxcox, igual que las cartas univariadas:
etapas = [1] * 40 + [2] * 40
# Sin mu/cov: cada etapa re-estima sus parámetros
c = pp.t2_chart(datos, stages=etapas)
c.stage_mean[1] # vector de medias de la etapa 1
c.stage_mean[2] # vector de medias de la etapa 2
c.contributions(45) # usa la media/covarianza de la etapa del punto 45
# Con mu/cov: los mismos parámetros en todas las etapas
pp.t2_chart(datos, mu=mu, cov=cov, n_hist=100, stages=etapas)
# MEWMA y MCUSUM reinician el acumulador al empezar cada etapa
pp.mewma_chart(datos, stages=etapas)
pp.mcusum_chart(datos, stages=etapas)
# Box-Cox: estima una lambda por variable (no compatible con mu/cov históricos)
c = pp.t2_chart(datos_positivos, boxcox=True)
c.params[0]["lambda_boxcox"] # {'Var1': 0.42, 'Var2': 1.13, ...}
pp.mewma_chart(datos_positivos, boxcox=True)
pp.mcusum_chart(datos_positivos, boxcox=True)
Pruebas de causas especiales
pccpy implementa las 8 pruebas de Western Electric / Nelson tal como
las documenta Minitab, con sus parámetros K por defecto:
| Nú | Descripción | K defecto | Equivalente Minitab |
|---|---|---|---|
| 1 | 1 punto más allá de Kσ | 3 | Prueba 1 |
| 2 | K puntos consecutivos en el mismo lado de la LC | 9 | Prueba 2 |
| 3 | K puntos consecutivos en tendencia (subiendo o bajando) | 6 | Prueba 3 |
| 4 | K puntos alternando arriba/abajo | 14 | Prueba 4 |
| 5 | 2 de 3 puntos más allá de 2σ en el mismo lado | 2 | Prueba 5 |
| 6 | 4 de 5 puntos más allá de 1σ en el mismo lado | 4 | Prueba 6 |
| 7 | K puntos consecutivos entre ±1σ | 15 | Prueba 7 |
| 8 | K puntos consecutivos en lados alternos de la LC más allá de 1σ | 8 | Prueba 8 |
# Seleccionar pruebas y ajustar parámetros
carta = pp.imr_chart(
x,
tests=(1, 2, 5), # solo activar las pruebas 1, 2 y 5
test_params={2: 7, 5: 3}, # cambiar el K de la prueba 2 a 7 y el de la 5 a 3
)
# Activar todas las pruebas
carta = pp.imr_chart(x, tests="all")
# Sin pruebas (solo calcular los límites)
carta = pp.imr_chart(x, tests=None)
# Ver los puntos fuera de control
carta.violations() # DataFrame: panel, punto, prueba, valor, descripcion
carta.in_control # True si ninguna prueba falló
carta.panels[0].flagged # índices (base 0) de puntos marcados en el panel I
Cada tipo de carta aplica el subconjunto que corresponde:
- Completo (1-8): carta I, Xbar, Z
- Básicas (1-4): carta MR, R, S, G, T, atributos (P, NP, C, U, Laney)
- Solo prueba 1: EWMA, CUSUM, MA, T², MEWMA, MCUSUM
Visualización de las cartas
Todas las cartas se grafican con plot_control_chart(). Los gráficos incluyen
por defecto las líneas de zonas ±1σ y ±2σ (en gris punteado), igual que
Minitab, y marcan en rojo los puntos que fallan alguna prueba con el número
de la prueba.
import matplotlib.pyplot as plt
carta = pp.imr_chart(x, tests=(1, 2, 3))
# Con zonas σ visibles (por defecto)
fig = pp.plot_control_chart(carta)
plt.show()
# Sin zonas (solo LCS, LC, LCI)
fig = pp.plot_control_chart(carta, zones=False)
# Con título personalizado y tamaño de figura
fig = pp.plot_control_chart(carta, title="Diámetro del eje (mm)", figsize=(14, 7))
# Acceso directo desde el objeto carta
carta.plot(title="Mi carta")
Las zonas sigma en la carta permiten aplicar visualmente las pruebas 5, 6, 7 y 8:
- Zona A (±2σ a ±3σ): p. ej. prueba 5 — 2 de 3 puntos en zona A
- Zona B (±1σ a ±2σ): p. ej. prueba 6 — 4 de 5 puntos en zona B o más allá
- Zona C (0 a ±1σ): p. ej. prueba 7 — 15 puntos consecutivos en zona C
Capacidad del proceso
Capacidad normal
datos = rng.normal(10, 0.1, 100)
res = pp.capability_analysis(
datos,
lsl=9.7, # Límite de Especificación Inferior
usl=10.3, # Límite de Especificación Superior
target=10.0, # objetivo (para Cpm; opcional)
subgroup_size=5, # con subgrupos: sigma_dentro ≠ sigma_general
)
print(res.summary())
# Cp, CPL, CPU, Cpk, Pp, PPL, PPU, Ppk, Cpm, Z.Bench sup/inf, PPM total
res.to_frame() # todos los índices como DataFrame
res.plot() # histograma con curvas dentro / general y especificaciones
Diferencia Cp/Cpk vs Pp/Ppk:
| Índice | σ usada | Interpreta |
|---|---|---|
| Cp, Cpk | sigma dentro de subgrupos | capacidad potencial del proceso estable |
| Pp, Ppk | sigma general (todos los datos) | rendimiento real incluyendo variación entre subgrupos |
Si el proceso está en control, Cpk ≈ Ppk. Una diferencia grande indica inestabilidad o variación entre subgrupos.
Capacidad no normal
Cuando los datos no siguen una distribución normal (confirmado con normality_test)
se pueden usar 9 distribuciones alternativas:
res_nn = pp.capability_nonnormal(
datos,
lsl=1.0,
usl=20.0,
distribution="weibull", # ver lista abajo
)
print(res_nn.summary())
Distribuciones disponibles:
"normal", "lognormal", "weibull", "gamma", "exponential",
"loglogistic", "logistic", "largest_extreme", "smallest_extreme"
Los parámetros se ajustan por máxima verosimilitud. Los índices Pp/Ppk se calculan por el método de percentiles (ISO 22514-2), que es compatible con Minitab.
Capacidad con transformación Box-Cox
res_bc = pp.capability_boxcox(
datos,
lsl=1.0,
usl=20.0,
# lam=None # si es None, se estima por máxima verosimilitud
)
print(res_bc.summary())
res_bc.transform # {'lambda': 0.42}
Capability Sixpack
Genera las 6 vistas del Capability Sixpack de Minitab en una sola figura: carta de control (dentro), rango/desviación (dentro), últimas 25 obs/subgrupos, histograma de capacidad, gráfico de probabilidad normal y gráfico de capacidad.
fig, res, carta = pp.capability_sixpack(
datos,
lsl=9.7,
usl=10.3,
subgroup_size=5,
tests=(1,),
)
plt.show()
# fig: figura de matplotlib
# res: CapabilityResult con todos los índices
# carta: ControlChart (Xbar-R, Xbar-S o I-MR según el tamaño de subgrupo)
Normalidad, Pareto y constantes SPC
Prueba de normalidad
result = pp.normality_test(
datos,
method="ad", # 'ad' Anderson-Darling (defecto), 'shapiro', 'dagostino'
)
print(result.summary())
# Estadístico: 0.312, Valor p: 0.534, Conclusión: no se rechaza normalidad (α=0.05)
result.statistic # valor del estadístico
result.pvalue # valor p
result.normal # True si no se rechaza normalidad a α = 0.05
# Gráfico de probabilidad normal con Anderson-Darling
pp.probability_plot(datos)
Pareto
defectos = ["Rayado", "Abolladura", "Rayado", "Pintura", "Rayado",
"Abolladura", "Otro", "Rayado", "Pintura", "Abolladura"]
tabla = pp.pareto(defectos)
print(tabla)
# categoria frecuencia porcentaje acumulado
# 0 Rayado 4 40.0 40.0
# 1 Abolladura 3 30.0 70.0
# 2 Pintura 2 20.0 90.0
# 3 Otro 1 10.0 100.0
pp.plot_pareto(tabla) # diagrama de Pareto con curva acumulada
Constantes SPC
Calculadas por integración numérica para cualquier n ≥ 2 —no solo para los
valores tabulados hasta n = 25 que suelen publicarse en libros.
pp.d2(5) # 2.3259 (factor para estimar sigma desde R; n=5)
pp.d3(5) # 0.8641 (para el límite del rango móvil)
pp.c4(5) # 0.9400 (factor para estimar sigma desde s)
pp.c5(5) # 0.3412 (para el límite de la desviación estándar)
# Tabla completa de constantes para n=5
pp.control_chart_constants(5)
# {'n': 5, 'd2': 2.326, 'd3': 0.864, 'c4': 0.940, 'c5': 0.341,
# 'A2': 0.577, 'A3': 1.342, 'D3': 0.0, 'D4': 2.115, 'B3': 0.0, 'B4': 2.089}
Acceso a los datos del resultado
Todas las cartas de control devuelven un objeto ControlChart (las multivariadas
devuelven MultivariateChart). Se puede acceder a todos los datos calculados:
carta = pp.imr_chart(x, tests=(1, 2, 3))
# --- Acceso por nombre de panel ---
panel_i = carta["I"] # panel de individuales
panel_mr = carta["MR"] # panel de rango móvil
# Arrays NumPy directos
panel_i.values # valores graficados
panel_i.center # línea central (LC)
panel_i.ucl # límite de control superior (LCS)
panel_i.lcl # límite de control inferior (LCI)
panel_i.sigma # sigma estimada punto a punto
panel_i.stage # etiqueta de etapa de cada punto
panel_i.flagged # índices base-0 de puntos marcados
# --- DataFrame de un panel ---
panel_i.to_frame()
# columnas: punto, etapa, valor, LC, LCS, LCI, pruebas_fallidas
# --- DataFrame ancho (todos los paneles) ---
carta.to_frame()
# columnas: punto, etapa, I_valor, I_LC, I_LCS, I_LCI, I_pruebas_fallidas,
# MR_valor, MR_LC, MR_LCS, MR_LCI, MR_pruebas_fallidas
# --- Puntos fuera de control ---
carta.violations()
# columnas: panel, punto, prueba, valor, descripcion
# --- Parámetros estimados ---
carta.params # lista de dicts, uno por etapa
carta.params[0] # {'stage': 1, 'media': 10.2, 'sigma': 0.31, 'MR_prom': 0.35, 'n': 30}
# --- Estado del proceso ---
carta.in_control # True si no hay ningún punto fuera de control
carta.summary() # resumen en texto
# --- Acceso programatico a violaciones por prueba ---
carta.panels[0].violations # dict {prueba: array de índices}
Validación
186 pruebas automatizadas. Las referencias son independientes de pccpy:
- Constantes d2, d3, c4 frente a tablas publicadas (Montgomery).
- Límites I-MR, Xbar-R y Xbar-S frente al cálculo manual con A2, D3, D4, A3, B3, B4.
- Anderson-Darling frente a
statsmodels(coincide a 9 decimales). - EWMA y CUSUM frente a la recursión manual.
- Las 8 pruebas de causas especiales frente a casos construidos a mano, incluidos los casos límite.
- T²: valores frente a
scipy.spatial.distance.mahalanobis; límites de Fase I y II por simulación Monte Carlo. - Varianza generalizada: constantes b1 y b2 por simulación de matrices de covarianza.
- MEWMA: el límite para p=2, λ=0.1, ARL=200 da 8.63 (publicado: 8.64, Prabhu y Runger 1997).
- G y T: cuantiles frente a
scipy.stats, y máxima verosimilitud Weibull por su ecuación de score.
Nota: pccpy sigue las fórmulas y convenciones que Minitab documenta, pero no se ha comparado corrida a corrida contra el software Minitab por ausencia de licencia. Si encuentras una diferencia, abre un issue.
Desarrollo
git clone https://github.com/LeoSanta15/pccpy.git
cd pccpy
pip install -e ".[dev]"
pytest --cov=pccpy # pruebas + cobertura
ruff check src/ # estilo y errores comunes
mypy src/pccpy # verificación de tipos
Para generar la documentación localmente:
pip install -e ".[docs]"
sphinx-build -b html docs/source docs/build
# Abrir docs/build/index.html
Ver CHANGELOG.md para el historial de versiones y
CONTRIBUTING.md para las normas de contribución.
Licencia
MIT — ver LICENSE.
Release files for pccpy 0.4.9
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pccpy-0.4.9.tar.gz | 76.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pccpy-0.4.9-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 132.1 kB
Release files / pccpy-0.4.9.tar.gz
| Download URL | pccpy-0.4.9.tar.gz |
|---|---|
| Size | 76.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
763b023bc19870472c56c97895d966b7326caaec1f1766b11cb6a48176eb029b
|
|
BLAKE2b-256 checksum How to use checksums |
9d656495ea2a6f961cc3de7873b20f97283c6988b4e35f72814091a3860371c0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.
Transparency logRelease files / pccpy-0.4.9-py3-none-any.whl
| Download URL | pccpy-0.4.9-py3-none-any.whl |
|---|---|
| Size | 55.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e34e8c7f0b380fce19feb6cb728d3c7ff9420721a4147ff65c703101cedc5dc7
|
|
BLAKE2b-256 checksum How to use checksums |
660a5fff56fd80e56fcda079e3320d6a7eb2bdfa4349118d81be71899f17552c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.
Transparency log