Saltar al contenido

Construyendo una Matriz de Transición usando palabras en Python/Numpy

Entiende el código de forma correcta antes de usarlo a tu trabajo si tquieres aportar algo puedes compartirlo con nosotros.

Solución:

Si no te importa usar pandashay una línea para extraer las probabilidades de transición:

pd.crosstab(pd.Series(days[1:],name='Tomorrow'),
            pd.Series(days[:-1],name='Today'),normalize=1)

Producción:

Today      clouds      rain       sun
Tomorrow                             
clouds    0.40625  0.230769  0.309524
rain      0.28125  0.423077  0.142857
sun       0.31250  0.346154  0.547619

Aquí la probabilidad (adelante) de que mañana estará soleado dado que hoy llovió se encuentra en la columna ‘lluvia’, fila ‘sol’. Si desea tener probabilidades hacia atrás (cuál podría haber sido el clima ayer dado el clima de hoy), cambie los dos primeros parámetros.

Si desea tener las probabilidades almacenadas en filas en lugar de columnas, establezca normalize=0 pero tenga en cuenta que si hiciera eso directamente en este ejemplo, obtendrá probabilidades hacia atrás almacenadas como filas. Si desea obtener el mismo resultado que el anterior pero transpuesto, puede a) sí, transponer o b) cambiar el orden de los dos primeros parámetros y establecer normalize a 0.

Si solo desea mantener los resultados como numpy 2-d array (y no como un marco de datos de pandas), escriba .values después del último paréntesis.

Me gusta una combinación de pandas y itertools para esto. El bloque de código es un poco más largo que el anterior, pero no confunda verbosidad con velocidad. (Los window func debe ser muy rápido; la parte de los pandas será más lenta sin duda).

Primero, haga una función de “ventana”. Aquí hay uno del libro de cocina de itertools. Esto te lleva a un lista de tuplas de transiciones (estado1 a estado2).

from itertools import islice

def window(seq, n=2):
    "Sliding window width n from seq.  From old itertools recipes."""
    it = iter(seq)
    result = tuple(islice(it, n))
    if len(result) == n:
        yield result
    for elem in it:
        result = result[1:] + (elem,)
        yield result

# list(window(days))
# [('rain', 'rain'),
#  ('rain', 'rain'),
#  ('rain', 'clouds'),
#  ('clouds', 'rain'),
#  ('rain', 'sun'),
# ...

Luego use una operación pandas groupby + value counts para obtener una matriz de transición de cada estado1 a cada estado2:

import pandas as pd

pairs = pd.DataFrame(window(days), columns=['state1', 'state2'])
counts = pairs.groupby('state1')['state2'].value_counts()
probs = (counts / counts.sum()).unstack()

Tu resultado se ve así:

print(probs)
state2  clouds  rain   sun
state1                    
clouds    0.13  0.09  0.10
rain      0.06  0.11  0.09
sun       0.13  0.06  0.23

Aquí hay una solución numérica “pura” que crea tablas de 3×3 donde el cero dim (número de fila) corresponde a hoy y el último dim (número de columna) corresponde a mañana.

La conversión de palabras a índices se realiza truncando después de la primera letra y luego usando una tabla de búsqueda.

para contar numpy.add.at se usa

Esto fue escrito con la eficiencia en mente. Hace un millón de palabras en menos de un segundo.

import numpy as np

report = [
  'rain', 'rain', 'rain', 'clouds', 'rain', 'sun', 'clouds', 'clouds', 
  'rain', 'sun', 'rain', 'rain', 'clouds', 'clouds', 'sun', 'sun', 
  'clouds', 'clouds', 'rain', 'clouds', 'sun', 'rain', 'rain', 'sun',
  'sun', 'clouds', 'clouds', 'rain', 'rain', 'sun', 'sun', 'rain', 
  'rain', 'sun', 'clouds', 'clouds', 'sun', 'sun', 'clouds', 'rain', 
  'rain', 'rain', 'rain', 'sun', 'sun', 'sun', 'sun', 'clouds', 'sun', 
  'clouds', 'clouds', 'sun', 'clouds', 'rain', 'sun', 'sun', 'sun', 
  'clouds', 'sun', 'rain', 'sun', 'sun', 'sun', 'sun', 'clouds', 
  'rain', 'clouds', 'clouds', 'sun', 'sun', 'sun', 'sun', 'sun', 'sun', 
  'clouds', 'clouds', 'clouds', 'clouds', 'clouds', 'sun', 'rain', 
  'rain', 'rain', 'clouds', 'sun', 'clouds', 'clouds', 'clouds', 'rain', 
  'clouds', 'rain', 'sun', 'sun', 'clouds', 'sun', 'sun', 'sun', 'sun',
  'sun', 'sun', 'rain']

# create np array, keep only first letter (by forcing dtype)
# obviously, this only works because rain, sun, clouds start with different
# letters
# cast to int type so we can use for indexing
ri = np.array(report, dtype='|S1').view(np.uint8)
# create lookup
c, r, s = 99, 114, 115 # you can verify this using chr and ord
lookup = np.empty((s+1,), dtype=int)
lookup[[c, r, s]] = np.arange(3)
# translate c, r, s to 0, 1, 2
rc = lookup[ri]
# get counts (of pairs (today, tomorrow))
cnts = np.zeros((3, 3), dtype=int)
np.add.at(cnts, (rc[:-1], rc[1:]), 1)
# or as probs
probs = cnts / cnts.sum()
# or as condional probs (if today is sun how probable is rain tomorrow etc.)
cond = cnts / cnts.sum(axis=-1, keepdims=True)

print(cnts)
print(probs)
print(cond)

# [13  9 10]
#  [ 6 11  9]
#  [13  6 23]]
# [[ 0.13  0.09  0.1 ]
#  [ 0.06  0.11  0.09]
#  [ 0.13  0.06  0.23]]
# [[ 0.40625     0.28125     0.3125    ]
#  [ 0.23076923  0.42307692  0.34615385]
#  [ 0.30952381  0.14285714  0.54761905]]

Agradecemos que desees añadir valor a nuestro contenido informacional colaborando tu veteranía en las ilustraciones.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *