Páginas

Mostrando las entradas con la etiqueta teoinfo. Mostrar todas las entradas
Mostrando las entradas con la etiqueta teoinfo. Mostrar todas las entradas

miércoles, 29 de mayo de 2013

[TEORÍA DE LA INFORMACIÓN] Resumen de bioinformática

Identification of complex metabolic states in critically injured patients using bioinformatic cluster analysis

Autores: Mitchell J. Cohen, Adam D. Grossman, Diane Morabito, M. Margaret Knudson, Atul J. Butte y Geoffrey T. Manley.

Linka al artículo: http://www.biomedcentral.com/content/pdf/cc8864.pdf

1. Introducción

La unidad de cuidados intensivos (ICU) está inundada de un flujo continuo de datos multivariados producidos a partir de varios monitores, ventiladores, datos de laboratorio y documentación personal médica.

Las comunidades de cuidados intensivos han recurrido a estos monitores y los datos que producen para comprender mejor la fisiología después de la lesión y la reanimación y el tratamiento manual. A pesar de las mejoras, y en el aumento de la dependencia de la tecnología de monitoreo, estos datos multivariados todavía registran de manera intermitente en muchas unidades de cuidados intensivos, a menudo con la menor frecuencia cada hora, en una hoja de papel.

Incluso en unidades de cuidados intensivos donde la hoja de papel ha sido sustituido por un registro médico electrónico, estos sistemas no son adecuados para el seguimiento y el análisis de las relaciones multivariantes complejas. Además, este sistema anticuado, no relacional de la recolección y presentación de datos limita nuestra capacidad de comprender las complejas relaciones entre las variables e impide el análisis longitudinal de las tendencias y el desarrollo de patofisiología en el paciente.

Aquí se muestra que estas metodologías de clustering de la bioinformática son aplicables a  datos fisiológicos multivariados rapidamente cambiantes en pacientes con lesiones críticas, dando datos importantes en la fisiología y los resultados de los pacientes. Se define que en cualquier momento, el estado del paciente se compone de un patrón complejo de variables que en conjunto constituyen el medio de resucitación y del metabolismo.

2. Materiales y métodos

2.1 Colección de datos

El sistema integra información continua de los monitores de pacientes. Datos intermitentes de laboratorio, medicamentos e intervenciones de enfermería se obtuvieron a partir del sistema de documentación de enfermería electrónico e integrado con los datos continuos. Los datos se almacenan en un servidor dedicado en la ICU.

Los pacientes fueron seleccionados como una muestra secuencial pero todos resultaron heridos gravemente y requirieron ingreso en la ICU y reanimación en curso. Los pacientes fueron monitoreados hasta el alta o la muerte, y todas las complicaciones, como infecciones y disfunción de órganos, fueron documentados en la base de datos del estudio.

La puntuación ordinal MOF (falla orgánica múltiple) se convirtió en una variable de resultado binario MOF con puntaje ≥ 4 designados como falla orgánica múltiple. Otras variables de resultado fueron la mortalidad y la infección.

2.2 Clustering jerárquico

Un total de 45 variables de datos fisiológicos, clínicos, y de tratamientos se recogieron cada minuto. Para el análisis de clustering se ha utilizado sólo variables continuos para las cuales los datos fueron completados, lo que resulta en 52 000 puntos a través de 14 variables.

El algorítmo de clustering procede en dos pasos principales: Cálculos de distancias por pares y la vinculación del clúster. Para los cálculos de distancia, se utilizó la distancia euclidiana estándar entre cada punto de los datos. Con una enumeración completa de las distancias por pares entre todas las observaciones, el algoritmo de vinculación combina los dos clusters más cercanos en uno solo, en donde un grupo también puede unirse como un punto de datos.

2.3 Clasificador lineal univariado

Al utilizar las técnicas de análisis multidimensional, es importante tener en cuenta si las técnicas univariadas simples pueden producir resultados similares. Por lo tanto se ha tratado de capacitar a un clasificador lineal univariante utilizando el análisis discriminante lineal (LDA) para clasificar el resultado binario.

2.4 Análisis de correlación entre clusters

A continuación se calcularon los coeficientes de correlación de Pearson para cada par de variables dentro de los clusters con las probabilidades más altas y más bajas de la muerte.

Por último, se comparó los coeficientes de correlación correspondientes entre los dos clusters de interés.

3. Resultados

3.1 Datos demográficos

Se incluyó a 17 pacientes con lesiones graves ingresados ​​en la Unidad Quirúrgica de Cuidados Intensivos en el Hospital General de San Francisco, los pacientes recibieron heridas de gravedad con un Injury Severity Score promedio de 28 ± 10, una estancia media en la ICU de 24 días y una estancia hospitalaria promedio total de 40 día.

El seguimiento sandard se inició en la admisión a la ICU. Debido a que estos pacientes a menudo fueron sometidos a diagnóstico y reanimación significativa en el departamento de emergencia (ED), pruebas de imagen en radiología, o procedimientos quirúrgicos en el quirófano.

3.2 Agrupación jerárquica

Para analizar los datos multivariantes se utilizó un algoritmo de agrupamiento jerárquico para colocar cada uno de los 52.000 minutos de datos a 1 de 10 clusters para representar los estados de los pacientes. Se eligió el número de grupos para proporcionar un equilibrio adecuado entre la maximización de intercluster y reducir al mínimo la distancia entre clusters.

Para determinar si el método de agrupación estaba produciendo resultados fisiológicamente razonables y agrupar las variables que esperamos fisiológicamente a agruparse, lo primero que examinó el dendrograma variable y encontramos que las variables conocidas fisiológicamente relacionadas se agrupan.

3.3 La evaluación clínica de los clusters

A continuación se examinó los estados producidos a partir de la agrupación para determinar si cualquiera de los clusters representados fisiología que sería obvia para un clínico astuto.

La evaluación de los datos clínicos en estos estados por cuatro médicos con experiencia se tradujo en la imposibilidad de definir clínicamente cualquiera de los estados, enfermo o sano, resucitado o no resucitado, y así sucesivamente, poniendo de relieve la dificultad de obtener una predicción clínica tradicional o el significado de estos patrones.

A continuación se trató de probar la capacidad de predicción del método de agrupamiento mediante el cálculo de la distribución de los pacientes con resultados particulares a través de los clusters.

Para probar si las variables individuales fueron predictores estadísticamente significativos de los resultados se realizó un análisis discriminante lineal (LDA). LDA muestra que hay una variable individual que era capaz de predecir correctamente el resultado del paciente significativamente mejor que el nivel de probabilidad de 10,8%. De hecho, todos menos dos variables que fallaron para clasificar correctamente un único punto de datos como pertenecientes a un paciente que murió.

3.4 Representación de las nuevos relaciones fisiológicas

Habiendo determinado que: 1) el análisis univariado no proporcionó factores predictivos adecuados y 2) que la agrupación jerárquica proporciona predicción superior de los resultados, el próximo objetivo era determinar por qué esto era así. La hipótesis de que los clusters contenían nuevas relaciones fisiológicas y que las correlaciones entre pares de variables serían diferentes según el estado del paciente. Además, secreía que estas correlaciones cambiantes probablemente reflejen cambios en las relaciones fisiológicas en función de la lesión o cambiar el estado de reanimación de un paciente.

El examen de estos resultados fue muy revelador y proporciona pruebas tanto de la discriminación de la técnica de agrupación y la capacidad de esta técnica para identificar las relaciones fisiológicas que de otro modo sería imposible de discernir.

Aunque estos resultados proporcionan pruebas convincentes de que el proceso de agrupación es fisiológicamente significativa, el próximo buscó la correlación que eran dispares entre clusters.

4. Resultados y discución

Se ha demostrado aquí la utilidad de la agrupación jerárquica como un esquema de clasificación no lineal sin supervisión en la predicción de los resultados en los pacientes de trauma con lesiones graves.

Estos grupos no sólo estaban dominados por unos pocos pacientes específicos con un resultado particular.

Por último, la información pronóstica incorporada en los resultados de la agrupación no era obtenible por el análisis estadístico tradicional y persiste en la cara de análisis univariado que no podrían predecir cualquiera de estos resultados.

Si bien estos monitores son excelentes como alarmas instantáneas sobre los parámetros críticos, no hacen nada para ayudar a predecir los resultados a largo plazo. Las mejoras en el diagnóstico y la atención han resultado tradicionalmente, tanto mejor perspicacia clínica y avances científicos, sobre todo en datos circundantes del examen científico de un solo o un pequeño grupo de adjuntos.

El uso de aprendizaje no supervisado con grandes datos multivariantes establece compuesto por los datos continuos representa una combinación poco frecuente de las técnicas para predecir y mejorar los resultados del paciente.

Existen varias limitaciones a este estudio preliminar. En primer lugar, el análisis aquí se basa en un número limitado de pacientes (17) y puntos de datos (52.000) . Los estudios futuros deben incorporar a más pacientes (y más datos) que representa los resultados primarios.

5. Conclusión

5.1 Conclusión de los autores

En resumen, se ha demostrado la aplicabilidad de la agrupación jerárquica de los datos fisiológicos a un grado muy alto. Profundizando en los resultados de la agrupación nos permitió aprender más sobre los cambios en la fisiología que son más representativos de los pacientes que mueren o viven de lo que podría determinarse utilizando todos los datos, de forma agregada, de los pacientes individuales que vivieron o murieron. Comparando los coeficientes de correlación de pares coincidentes de las variables entre los grupos revelaron diferencias predictivos de la vida y la muerte y las relaciones fisiológicas dispares dependiendo de la lesión y el estado de reanimación.

5.2 Conclusión personal

Creo que es algo complicado estudiar la fisiología humana pues todos los seres vivos funcionamos de manera diferente, algunos más parecidos a otros pero no de manera similar. Utilizar métodos de agrupación para determinar o predecir si un paciente vivirá o morirá parece una buena solución pero siempre pueden existir cambios que generen datos nuevos que no son tomados en cuenta por estos métodos. Por ejemplo, las medicinas cambiarán el comportamiento del ser y or lo tanto los resultados.

Las pruebas fueron hechas solo con pacientes que recibieron heridas de gravedad, pienso que se debió tomar en cuenta pacientes con heridas y enfermedades variadas para tener un análisis completo.

Referencias:

[1] Mitchell J. Cohen, Adam D. Grossman, Diane Morabito, M. Margaret Knudson, Atul J. Butte, Geoffrey T. Manley, "Identification of complex metabolic states in critically injured patients using bioinformatic cluster analysis", Critical Care 2010, 14:R10

jueves, 9 de mayo de 2013

[TEORÍA DE LA INFORMACIÓN] Código de corrección de errores

Para esta tarea se encargó implementar un algoritmo para corrección de errores. En este caso el Hamming (7,4).

Consiste en dividir el contenido de la información en bloques de 4 bits y codificar estos bloques, de tal manera se puede generar un bloque de 7 bits agregando 3 bits de paridad. Estos bloques de 7 bits son una codificación limitada a unas cuantas combinaciones, así que son estos bloques los que se envían y que pueden sufrir alteraciones, y mediante una operación de matrices se puede obtener las posiciones de bits donde hubo alteraciones.

Hamming (7,4) está limitado a la corrección y detección de un error de bit por bloque. Para poder distinguir entre dos errores se puede utilizar el Hamming extendido.

La matriz generadora G que utilicé es la siguiente:
La matriz de chequeo de paridad H es la siguiente:
El código es el siguiente:

Se utilizó el siguiente archivo de texto:

Y la pantalla donde corre el programa muestra al final el texto decodificado:

jueves, 25 de abril de 2013

[TEORÍA DE LA INFORMACIÓN] Codificación Adaptativa

Para esta semana se encargó realizar un algoritmo de codificación adaptativa basado en la codificación Huffman.

Realicé unas modificaciones a la tarea anterior para hacerlo lo más adaptativo posible.

Anteriormente procesaba todo el texto en una sola iteración y generaba una tabla de frecuencias de caracteres. Después generaba una lista de nodos y al final generaba un árbol.

Ahora he cambiado ciertas cosas en el código, no proceso el texto de la misma manera, sino que ahora lo divido en palabras de N caracteres y cada una las proceso por separado, genero los nodos para esa palabra y por cada palabra modifico un árbol con los nuevos nodos.


Al correr el programa, se genera y se imprime la lista de palabras de N caracteres, despues se corren los algoritmos, finalmente se imprime el texto original junto con el texto decodificado. Tambien se imprimen los datos de la corrida del programa.

Pensé que generar varios arboles optimizaría un poco el tiempo puesto que se procesan más rápido y la codificación se genera con mayor velocidad, una vez generada el arbol se mantendrá constante, a diferencia de la versión anterior, que una vez procesado el texto generaba el arbol de forma recursiva y con tiempos ligeramente más elevados.

El código es el siguiente:
Realmente es algo demasiado sencillo pero cumple con las especificaciones:
  • No hay un calculo de las frecuencias en un principio (solo se calcula frecuencias de caracteres por cada palabra generada).
  • No hay conocimiento de la distribución de símbolos.
Algo que destaca es que dependiendo de el valor de N el algoritmo se comportará distinto, se puede observar que para pocas letras no hay eficiencia, llegando a compresiones que generan archivos mayores al original.

Para hacer unas pruebas, usé un archivo de texto con 10000 caracteres aproximadamente, se puede ver como en un principio hay dificultades, pero se estabiliza.

Como se puede ver, a medida que la cantidad de caracteres por palabra generada aumenta, el radio de compresión disminuye.

El tiempo que tarda en procesar cada palabra generada también disminuye, se puede ver que aproximadamente 10 caracteres por palabra es lo más óptimo para el texto que seleccioné.

Comparado con la implementación normal estos fueron los resultados:


Para los radios de compresión, la implementación anterior es constante.


Los tiempos son muy variables. Depende de la computadora.

Mi conclusión es que se puede mejorar el algoritmo, puesto que bajo ciertas circunstancias tiene un nivel de compresión ligeramente mejor, y sus tiempos son buenos comparados con la implementación normal, el algoritmo hace demasiado uso de recursiones y excepciones para generar la codificación, y cada recursión significa menos eficiencia, y las excepciones son una mala práctica, combinarlas es algo que mejor se debe evitar. 

Así que lo mejor que se puede hacer para mejorar el rendimiento es buscar una alternativa. A nivel compresión seguiría teniendo la misma eficiencia, a nivel de tiempo podría mejorar.

jueves, 11 de abril de 2013

[TEORÍA DE LA INFORMACIÓN] Fundamentos de compresión - Codificación Huffman

Para esta tarea se encargó realizar un programa que al introducirle una cadena de texto genere una codificación Huffman.

David Huffman propuso un método estadístico que permitía asignar un código binario a cada caracter  La longitud de cada código no es idéntica para todos los caracteres: se asignan códigos cortos a los caracteres utilizados con más frecuencia, mientras que los caracteres menos frecuentes reciben códigos binarios más largos.

El algoritmo es simple:
  1. Se recorre la cadena de texto y se hace una tabla de frecuencias para cada caracter.
  2. Creamos un nodo por cada caracter, éste tendrá 2 valores, el caracter y la frecuencia.
  3. Ordenamos de forma ascendente con respecto a las frecuencias y se toman los dos nodos con frecuencias menores.
  4. Se agrega un nodo padre para los 2 nodos anteriores y su peso es la suma de frecuencias de ambos. Se agrega a la lista de nodos en su posición correspondiente y se eliminan los nodos hijos.
  5. Se repite el proceso hasta que quede un solo nodo en la lista.
El gif de ejemplo de wikipedia:

Y el código es el siguiente:
Y su salida es la siguiente:

Pero ahora realizaré un par de experimentos; será el análisis del peor y el típico caso. Para ésto generaré un par de archivos de texto con las siguientes características.
  • El peor caso, es donde existe la misma cantidad de frecuencias para cada caracter.
  • El típico caso es donde las frecuencias son generadas aleatoriamente.
Analicé el tamaño original VS el tiempo que tarda, el resultado es el siguiente:
En teoría el tiempo del peor caso es menor puesto que todas sus frecuencias son iguales.

En cambio se puede ver que las compresiones son muy similares, siendo apenas un poco menor la del caso típico.

Finalmente comparo el radio de compresión, puesto que en el peor caso siempre hay frecuencias de caracteres fijos, parece mantener un radio constante.

jueves, 28 de febrero de 2013

[TEORÍA DE LA INFORMACIÓN] Resumen

Accelerating Protein Classification Using Suffix Trees
Bogdan Dorohonceanu and C.G. Nevill-Manning

Introducción

Las matrices de búsqueda de posición específica han sido usadas extensamente para reconocer regiones altamente conservadas de proteinas. Dorohonceanu y Nevill-Manning presentan un método para acelerar las búsquedas usando estructura de arboles de sufijos calculada desde las secuencias que se buscarán.

Estas matrices de búsqueda capturan la distribución característica de aminoácidos. Son más sensitivas que los métodos basados en expresión regular coo PROSITE y EMOTIF pero requieren menos información que los modelos ocultos de Markov.

Su principal desventaja contra PROSITE y EMOTIF es su velocidad. Debido a que en esos métodos permiten hacer saltos en cualquier discrepancia, en una matriz de búsqueda siempre se acierta con la misma probabilidad, por lo que hacer saltos es algo problemático.

La desventaja de usar arboles de sufijos es que es muy caro en términos de memoria; requiere 37 bytes por símbolo de entrada. Sin embargo los autores lograron reducir esto a 17 bytes.

Matices de búsqueda

Una matriz de búsqueda de posición específica S representa un alineamiento local sin pausas de una familia de secuencias. El alineamiento consiste en varias posiciones contiguas, cada posición representada por una columna en la matriz. Cada columna j consiste en un vector Sj(r), un resultado por cada posible residuo r.

Una matriz de búsqueda puede ser usada en análisis de secuencias, pasando la matriz por la secuencia y calculando el resultado del segmento. Cada resultado es la suma de las entradas apropiadas de la matriz, donde cada residuo corresponde a un resultado en una columna de la matriz.

Intuitivamente, un resultado del segmento mayor indica un mayor probabilidad de que la secuencia sea igual que la matriz de búsqueda.

Muchas implementaciones de PSSM's para funciones de predicción de proteínas aplican la matriz a cada segmento de cada proteína en la entrada. ordenan los segmentos por sus resultados y presentan los mejores resultados.

Arboles de sufijos

Un árbol de sufijos es un árbol compacto de sufijos en una cadena, para cada sufijo de una cadena hay un camino en su árbol correspondiente desde la raíz hasta las hojas que contengan la cadena.
La imagen anterior muestra un árbol de sufijos para la cadena "abab$". Este árbol es compactado de la siguiente manera. Donde sea que dos aristas inicien en el mismo nodo que comparta un prefijo, una nueva arista y un nodo son creados, y la arista tendrá la misma cadena. Por lo que las aristas anteriores ya no comparten el prefijo. Esto se hace hasta que ninguna arista comparta prefijos.

Para encontrar un segmento de buenos resultados en un set de secuencias de proteínas, primero se crea un arreglo de secuencias. Después se hace un DFT (búsqueda de profundidad) del árbol, calculando los resultados para las cadenas de las aristas.

Donde sea que el resultado alcance el umbral, todas las subcadenas representadas por las hojas de ese nodo deben también alcanzarlo, y pueden ser reportadas.

Esa es la llave para la aceleración, muchas subcadenas pueden ser descontinuadas basado en un simple camino. La siguiente imagen muestra dos casos: un subarbol que acierta y uno que no lo hace.

Arboles de sufijos compactos

Un problema significante es que los arboles son su tamaño en memoria primaria. Los aminoacidos consisten en 20 elementos, en la base de datos se registran 20 millones de aminoacidos y con aproximadamente 30 millones de nodos. Esto es 30,000,000 nodos x 22 punteros por nodo x 4 bytes por puntero dando como resultado 2.6 Gb. Pero no todos los nodos cuentan con almentos 20, se puede ahorrar memoria al usar listas enlazadas a sus hijos.

Esto da a un total de 30,000,000 nodos x 4 bytes por nodo x 4 bytes por puntero dando resultado a 480 Mb.

Fuente:
http://www.aaai.org/Papers/ISMB/2000/ISMB00-013.pdf

jueves, 21 de febrero de 2013

[TEORÍA DE LA INFORMACIÓN] String Matching

Para esta entrada se encargó analizar los algoritmos de "String matching" vistos en clase, estos son el algorimo de Boyer-Moore y el algoritmo de Knuth-Morris-Pratt, yo no alcancé a implementar el algoritmo Boyer-Moore por lo que utilicé en su lugar el algoritmo de fuerza bruta (comparar caracter por carácter) para comparar con el de Knuth-Morris-Pratt.

Boyer-Moore:

Éste algoritmo es un eficiente algoritmo de búsqueda de cadenas, y ha sido el punto de referencia estándar para la literatura de búsqueda de cadenas práctica. El algoritmo preprocesa la cadena objetivo que está siendo buscada, pero no en la cadena en que se busca.

El tiempo de ejecución del algoritmo Boyer-Moore, aunque es lineal en el tamaño de la cadena siendo buscada, puede tener un factor significativamente más bajo que muchos otros algoritmos de búsqueda: no necesita comprobar cada carácter de la cadena que es buscada, puesto que salta algunos de ellos.

Generalmente el algoritmo es más rápido cuanto más grande es la clave que es buscada, usa la información conseguida desde un intento para descartar tantas posiciones del texto como sean posibles en donde la cadena no coincida.

Su principal característica es que su búsqueda la realiza de derecha a izquierda, de esta manera se sabe que si no coincide la última letra, entonces no hay por que comparar el resto, lo que ahorra tiempo.

Antes de iniciar con la búsqueda, se preprocesa una tabla llamada "bad character" que contiene las posiciones que hay que saltar para determinado caracter.

El tiempo promedio para este algoritmo es de O(n log(m/n)), pero en el peor caso genera un tiempo de O(mn).

Lógica:
  • Al no haber coincidencia, el carácter del texto se compara con el patrón de búsqueda para determinar el salto hacia la derecha.
  • Si el carácter no existe en el patrón de búsqueda se salta la cadena completa.
  • Si tras varias coincidencias no se acertó, se salta en función de la repetición de patrones en la secuencia de búsqueda, y se alinea de nuevo usando ese valor.
  • Se toma como salto el mayor de los dos valores.
Ejemplo:

Knuth-Morris-Pratt:

KMP es un algoritmo de búsqueda de subcadenas simple y por lo tanto su objetivo es buscar la existencia de una subcadena dentro de una cadena. Para ello utiliza información basada en los fallos previos, aprovechando la información que la propia palabra a buscar contiene de sí , para determinar donde podría darse la siguiente existencia, sin necesidad de analizar más de 1 vez los caracteres de la cadena donde se busca.

Con KPM se pre-calcula una tabla donde se localizan las posibles coincidencias de patrón. Una vez calculadas, se procede a tomar la primera celda de la tabla. Si el caracter coincide se procede con el siguiente, si no, el algoritmo se corta y busca la siguiente posible posición. 

Debido a que el algoritmo consta de 2 partes donde se analiza una cadena en cada parte, la complejidad resultante es O(m) y O(n), cuya suma resulta ser O(m+n).

Mi código es el siguiente:
Al correrlo me da como resultado lo siguiente:

La imagen muestra que son 1000 caracteres los que se generan aleatoriamente, despues se muestra la tabla de posibles coincidencias, al final muestra el total de caracteres y el tiempo de ejecución ademas de la unica coincidencia en la posición 717.

Analicé esto con gnuplot, haciendo correr el programa varias veces e imprimiendo los resultados en un archivo.

El resultado es:
Vemos por el eje Y que casi alcanzaba los 0.0004 segundos de ejecución por texto.

Por ultimo tambien decidí realizar un analisis del algoritmo fuerza bruta que compara caracter por caracter. La complejidad del algoritmo es O(m) ya que solo opera en una sola corrida.

El código es el siguiente:
Utilicé el mismo scripto para correrlo varias veces e imprimirlo a un archivo de texto, el resultado es el siguiente:
Se puede ver que para este, el máximo tiempo estuvo cerca de 0.0018 segundos. A diferencia del anterior, se puedenotar que crece más rapido.

La comparativa entre las 2:

El script que corre el algoritmo es el siguiente:
El script de gnuplot, al ser un ploteo sencillo, es el que sigue:

plot "Bruteforce.txt" with lines, "KMP.txt" with lines

Liga al proyecto:

https://github.com/victoralex911/teoria-informacion

Fuentes:
https://sites.google.com/site/busquedasecuencialdetexto/algoritmo-boyer-moore
http://es.wikipedia.org/wiki/Algoritmo_Knuth-Morris-Pratt
http://es.wikipedia.org/wiki/Algoritmo_de_b%C3%BAsqueda_de_cadenas_Boyer-Moore

jueves, 14 de febrero de 2013

[TEORÍA DE LA INFORMACIÓN] Noisy channel simmulation

Para esta primera entrada de clase, realizamos una simulación de transmición de palabras binarias. Para esto escribí un pequeño programa que genera palabras en base a ciertos parámetros:

1 - Porcentaje 0 y 1
2 - Largo de palabra
3 - Numero de palabras
4 - Probabilidad de que 0 se quede como 0
5 - Probabilidad de que 1 se quede como 1
6 - Repeticiones por palabra

Mi código genera de estos datos N palabras de N largo, para eso yo genero un caracter (0 o 1) y lo agrego a un string. Despues agrego ese string a una lista y al terminar de generar todas las palabras inmediatamente las transmito.

Por cada transmición genero N palabras de la original. Al regresar, comparo cada una con su original y saco los errores que se generaron.

El código que realiza la función de generación de palabras es el siguiente:
El código que transmite la palabra es:

Después generé un script que corre el programa de transmición y generación de palabras:

Utilizé los parametros del script para generar 30 palabras de largos 1 a 9 (elevados a 2) con 30 transmiciones por palabra.

Y los resultados son los siguientes:

En el eje "y" tengo la probabilidad de error y en el eje "x" el largo de la palabra. Como se puede ver el comportamiento es que al aumentar la probabilidad de cambio (tanto en 0 como 1) tambien aumenta la cantidad de errores, al mismo tiempo disminuí la probabilidad de que exista un error, aún así hubo transmiciones completamente erroneas.

La liga al proyecto:
https://github.com/victoralex911/teoria-informacion