¿Es posible conocer la autoría de una obra literaria por las palabras y la frecuencia de uso de éstas que contiene? Esta es una pregunta recurrente entre los estudios de obras que nos han llegado hasta hoy como anónimas y de las que se sospecha una autoría que no ha podido ser confirmada por estudios historico-literarios tradicionales.
Dos matemáticos y un físico, DaríoBenedetto, Emanuele Caglioti y Vittorio Loreto de la Universidad deLa Sapienza en Roma, decidieron poner a prueba el algoritmo Lempel-Ziv como método de identificación de creadores literarios. Su objetivo era identificar a los autores de obras literarias. Noventa textos escritos por 11 autores italianos (entre ellos Dante Alighieri y Pirandello) sirvieron como material de base. Se elegía el texto de un autor determinado y se le unían dos pequeños textos de igual tamaño: uno del mismo autor y otro de un autor diferente. Se introducían estos archivos en un programa de compresión, como el popular WinZip, y los científicos comparaban cuánto espacio de almacenamiento necesitaba cada uno. Conjeturaron que la entropía relativa del texto combinado les daría una idea sobre la autoría del texto anónimo. Si ambos eran obra del mismo autor, el algoritmo necesitaría menos espacio de almacenamiento que si el texto adjunto estaba escrito por otro diferente. En el segundo caso, la entropía relativa sería mayor, dado que el algoritmo tendría que considerar los distintos estilos y palabras usadas por ambos autores. En consecuencia, necesitaría más espacio para almacenar el archivo. Cuanto más pequeño fuera el archivo comprimido de los dos textos combinados, más probable era que el texto original y el adjunto pertenecieran al mismo autor. Los resultados del experimento fueron francamente increíbles. Cerca del 95% de las veces los programas de compresión permitieron identificar correctamente al autor.
Seguramente embargados por la emoción
del éxito de su nuevo enfoque, los tres científicos no se dieron
cuenta, o al menos olvidaron mencionar en su bibliografía, que su
método no era tan original como creían. De hecho, no fueron los
primeros en pensar que los métodos matemáticos se podrían usar para atribuir textos literarios a
sus autores. George Zipf, profesor de Lingüística en Harvard, ya
había abordado temas como la frecuencia de palabras en 1932. Y el
escocés George Yule había demostrado en 1944, en un artículo
titulado Estudio estadístico del vocabulario literario, cómo había
podido atribuir el manuscrito De imítatione Christi al conocido
místico Tomás de Kempis, que vivió en los Países Bajos en el
siglo XV. Y por supuesto, hay que mencionar los papeles federalistas del siglo XVIII, cuya
autoría por parte de Alexander Hamilton, Iames Madison y Iohn Iay
fue determinada por los estadísticos americanos R. Prederick
Mosteller y David L. Wallace.
Dado que todo les había ido tan bien,
Benedetto, Caglioti y Loreto decidieron llevar a cabo otro
experimento. Analizaron los grados de afinidad entre lenguajes
diferentes. Dos lenguas que pertenezcan a la misma familia
lingüística deberían tener una entropía(1) relativa baja. Por tanto,
podría comprimirse de forma más eficiente una combinación de dos
textos escritos en lenguas que estén emparentadas que dos que
pertenezcan a familias diferentes. Los científicos analizaron 52
lenguas europeas. De nuevo, tuvieron éxito. Usando el programa de
compresión, pudieron clasificar cada lengua en su grupo lingüístico
correspondiente. El italiano y el francés, por ejemplo, tienen una
entropía relativa baja y por tanto pertenecen a la misma familia. El
sueco y el croata, por otro lado, tienen una entropía relativa alta
y por tanto han de provenir de grupos lingüísticos diferentes.
WinZip consiguió incluso identificar el maltés, el vasco y el
húngaro como lenguajes aislados que no pertenecían a ninguno de los
grupos lingüísticos conocidos.
El estudio completo se puede consultar en. Dario Benedetto, Emanuele Caglioti, Vittorio Loreto, "Language
Trees and Zipping", Phys.
Rev. Lett., 88, 048702 (2002)
(1)
(1)
Para entender la compresión de datos,
es necesario familiarizarse con el concepto de entropía.
En física, la entropía es una medida del
desorden de un sistema, por ejemplo un gas. En telecomunicaciones, la
entropía es una medida del contenido en información
de un mensaje. Un mensaje que consista, por ejemplo, en 1.000
repeticiones del número 0 tiene muy poco
contenido en información y una entropía
muy baja. Se puede comprimir a la pequeña formula 1000x0 Por otro lado, una secuencia totalmente aleatoria de unos y
ceros tiene una entropía muy alta. No se puede comprimir en
absoluto, y la única forma de almacenar dicha secuencia es
repitiendo todos sus caracteres. La entropía relativa indica cuánto
espacio de almacenamiento se ocupa si una
secuencia de caracteres se comprime, con un método que se había
optimizado para una secuencia diferente. El código
morse, concebido para el inglés, puede ser un ejemplo. La letra que
aparece mas frecuentemente en inglés, la e, obtuvo el código
mas corto: un punto. Las letras que aparecen menos obtienen códigos
mas largos, por ejemplo <<—.-» para la -q-. Para otras
lenguas, el código morse no es idóneo, porque
las longitudes de los códigos no corresponden con la frecuencia de
las letras. La entropía relativa mide entonces cuántos
puntos y guiones adicionales se necesitan para transmitir un texto,
digamos en italiano, con un código que
esta pensado para el inglés.
La mayoría de las rutinas de
compresión de datos estén basadas en algoritmos desarrollados a
finales de los años setenta por dos científicos israelíes
del Technion en Haifa. El método que desarrollaron Abraham Lempel,
informático, y de Jacob Ziv, ingeniero
electrónico, se basa en el hecho de que en
un archivo aparecen secuencias idénticas de bits y bytes. La primera
vez que una secuencia aparece en el texto, se introduce en una
especie de diccionario. Cuando vuelve a aparecer la misma secuencia,
un marcador señala el lugar adecuado del
diccionario. Dado que el marcador ocupa menos espacio que la
secuencia, el texto se comprime. Pero aún hay mas. La
distribución de la tabla que lista todas las secuencias no sigue las
reglas de clasificación de un diccionario
normal, si no que se adapta al archivo en concreto que queremos comprimir. El algoritmo <<aprende>>
a distinguir qué secuencias aparecen mas a menudo y adapta la
compresión a ellas. Cuando el tamaño del
archivo aumenta, el espacio necesario para almacenarlo crece hacia la
entropía del texto.
Fuente: La vida secreta de los números. GEORGE G. SZPIRO, ALMUZARA, 2009 ISBN 9788492573288
Este artículo es mi primera colaboración con la Edición 2.8 del Carnaval de Matemáticas, que en esta ocasión organiza Ciencia Conjunta.
Este artículo es mi primera colaboración con la Edición 2.8 del Carnaval de Matemáticas, que en esta ocasión organiza Ciencia Conjunta.
Los números parecen vivir a escondidas (pero muy activos) detrás de la pura apariencia que nuestros defectuosos sentidos nos comunican. El "lenguaje matemático", que es una creación humana, muestra sus logros.
ResponderEliminarEl trabajo interesantísimo que aquí se comenta, encuentra (analizando los resultados de WinZip) lo que hay de similar entre lenguas en principio muy diferentes. Así también constatan el estilo que identifica a un autor literario.
Es la capacidad del hombre de fugarse desde la entropía (entendida como este universo que no comprendemos, en “desorden”) hacia el orden (el mundo, creado por nosotros mismos, de lo que "comprendemos"). La humana necesidad de certezas.
¡Muy interesante!
Genial artículo. Solo apuntar que la identificación de la autoría de obras, tanto literarias como musicales, a partir de frecuencias y otros análisis estadísticos (y algoritmos informacionales, como el de Lempel-Ziv) no es algo que hayan inventado recientemente.
ResponderEliminarYa es casualidad leer hoy este artículo... precisamente ayer, como pasatiempo escribí un pequeño script python que cuenta las palabras de un fichero de texto. Bajé algunos libros del proyecto Gutenberg en formato texto (como por ejemplo La Regenta, o El Lazarillo) y a contar...
ResponderEliminarPor si a alguien (con un conocimiento mínimo de programación) le interesa, ahí va.
-------------8<--------------------------
# cuenta_palabras.py
#
# lee un fichero de texto nombre_de_fichero.txt
# y genera un fichero de salida con dos listas:
# 1) palabras - num.apariciones ordenado por palabras
# 2) num.apariciones - palabras ordenado por apariciones
#
# Pasar como unico argumento el fichero de texto a leer
#
# -*- coding: cp1252 -*-
import sys
args = sys.argv
#nombre de archivo
fn = "la_regenta.txt" # valor por defecto
if len(args) > 1:
fn = args[1]
#abrimos archivo
f = open(fn, "rt");
#lo leemos sobre una cadena
fulltext = f.read();
#y lo cerramos
f.close()
print "leido fichero " + fn + " - longitud = " + str(len(fulltext)) + " bytes."
#eliminamos signos de puntuacion
punctuation = ".,:;*_-()¡¿?!'«º»[]{}#"+'"'
for i in range(len(punctuation)):
fulltext = fulltext.replace(punctuation[i], ' ')
#convertimos palabras a minuscula
fulltext = fulltext.lower()
#lineas crudas
lines = fulltext.split("\n")
print "numero de lineas (incluyendo vacias): " + str(len(lines))
#lista de palabras
words = [];
#recorremos las lineas
for line in lines:
#palabras que hay en la linea
lwords = line.split()
for word in lwords:
#cada palabra, la limpiamos y aniadimos a la lista
word = word.strip(punctuation)
if word:
words.append(word)
print "numero de palabras: " + str(len(words))
#ordenamos las palabras
words.sort()
#vamos a contar las apariciones de palabras mediante un diccionario
#que mapea palabra -> numero de apariciones
dict = {}
keys = []
for word in words:
#si la palabra no esta en el diccionario, la aniadimos con valor 1
if not word in dict:
dict[word] = 1
keys.append(word)
#si esta, incrementamos el valor
else:
dict[word] += 1
#diccionario inversio, numero de apariciones -> lista de palabras que aparecen
#ese numero de veces
dict2 = {}
for key in keys:
key2 = dict[key]
if not key2 in dict2:
dict2[key2] = [key]
else:
dict2[key2].append(key)
#ordenamos las claves (numero de apariciones) para visualizarlas ordenadas
keys2 = []
for key2 in dict2:
keys2.append(key2)
keys2.sort()
fn2 = fn + ".wordcount.txt"
f2 = open(fn2, "wt")
f2.write("***********************************\n")
f2.write("***********************************\n")
f2.write("informe sobre "+fn+"\n")
f2.write("numero de palabras: " + str(len(words))+"\n")
f2.write("numero de palabras unicas: " + str(len(keys))+"\n")
f2.write("***********************************\n")
f2.write("***********************************\n")
for key in keys:
s = "" + key + " : " + str(dict[key]) + '\n'
f2.write(s)
f2.write("\n\n\n\n****************\n\n\n\n")
for key2 in keys2:
words2 = dict2[key2]
for word in words2:
s2 = "" + str(key2) + " : " + word + "\n"
f2.write(s2)
f2.close()
print "numero de palabras distintas: " + str(len(keys))
print "file " + fn2 + " written."
Para que el script fun
Vaya, en los comentarios no aparecen los tabuladores, y en python son necesarios. Vuelvo a pegar el código, cambiando los tabuladores por ·
ResponderEliminar# -*- coding: cp1252 -*-
# cuenta_palabras.py
#
# lee un fichero de texto nombre_de_fichero.txt
# y genera un fichero de salida con dos listas:
# 1) palabras - num.apariciones ordenado por palabras
# 2) num.apariciones - palabras ordenado por apariciones
#
# Pasar como unico argumento el fichero de texto a leer
import sys
args = sys.argv
#nombre de archivo
fn = "la_regenta.txt" # valor por defecto
if len(args) > 1:
·fn = args[1]
#abrimos archivo
f = open(fn, "rt");
#lo leemos sobre una cadena
fulltext = f.read();
#y lo cerramos
f.close()
print "leido fichero " + fn + " - longitud = " + str(len(fulltext)) + " bytes."
#eliminamos signos de puntuacion
punctuation = ".,:;*_-()¡¿?!'«º»[]{}#"+'"'
for i in range(len(punctuation)):
·fulltext = fulltext.replace(punctuation[i], ' ')
#convertimos palabras a minuscula
fulltext = fulltext.lower()
#lineas crudas
lines = fulltext.split("\n")
print "numero de lineas (incluyendo vacias): " + str(len(lines))
#lista de palabras
words = [];
#recorremos las lineas
for line in lines:
·#palabras que hay en la linea
·lwords = line.split()
·for word in lwords:
··#cada palabra, la limpiamos y aniadimos a la lista
··word = word.strip(punctuation)
··if word:
···words.append(word)
····
print "numero de palabras: " + str(len(words))
#ordenamos las palabras
words.sort()
#vamos a contar las apariciones de palabras mediante un diccionario
#que mapea palabra -> numero de apariciones
dict = {}
keys = []
for word in words:
·#si la palabra no esta en el diccionario, la aniadimos con valor 1
·if not word in dict:
··dict[word] = 1
··keys.append(word)
·#si esta, incrementamos el valor
·else:
··dict[word] += 1
#diccionario inversio, numero de apariciones -> lista de palabras que aparecen
#ese numero de veces
dict2 = {}
for key in keys:
·key2 = dict[key]
·if not key2 in dict2:
··dict2[key2] = [key]
·else:
··dict2[key2].append(key)
#ordenamos las claves (numero de apariciones) para visualizarlas ordenadas
keys2 = []
for key2 in dict2:
·keys2.append(key2)
keys2.sort()
fn2 = fn + ".wordcount.txt"
f2 = open(fn2, "wt")
f2.write("***********************************\n")
f2.write("***********************************\n")
f2.write("informe sobre "+fn+"\n")
f2.write("numero de palabras: " + str(len(words))+"\n")
f2.write("numero de palabras unicas: " + str(len(keys))+"\n")
f2.write("***********************************\n")
f2.write("***********************************\n")
for key in keys:
·s = "" + key + " : " + str(dict[key]) + '\n'
·f2.write(s)
f2.write("\n\n\n\n****************\n\n\n\n")
for key2 in keys2:
·words2 = dict2[key2]
·for word in words2:
··s2 = "" + str(key2) + " : " + word + "\n"
··f2.write(s2)
·
f2.close()
print "numero de palabras distintas: " + str(len(keys))
print "file " + fn2 + " written."
Entra y descubre como ganar dinero por lo que haces en internet.
ResponderEliminarHay muchos métodos no te arrepentiras y todo sin invertir NADA! 100% efectivo
http://adf.ly/3pqsZ
Genial artículo, nunca lo hubiera imaginado.
ResponderEliminarValora en upnews.es: ¿Es posible conocer la autoría de una obra literaria por las palabras y la frecuencia de uso de éstas que contiene? Esta es una pregu...
Hombre, antes de decir que no se habían dado cuenta hay que leer complejidad de Kolgomorov y métricas universales
ResponderEliminarLa justificación de la utilización del zip como máquina de turing .... por ejemplo http://cdsweb.cern.ch/record/1397873
Buen artículo, también hay algoritmos que calculan la entropia de los textos que calculan la vericidad del texto.
ResponderEliminarHombre, antes de decir que no se habían dado cuenta hay que leer complejidad de Kolgomorov y métricas universales
ResponderEliminarQue su método no era tan original? Lo dudo.
ResponderEliminar