Habraiting: construyendo una nube de palabras de habla rusa en el ejemplo de los encabezados de Habra

Hola Habr

En la última parte de Habraiting, se publicó un método para construir una nube de palabras para términos en inglés. Por supuesto, la tarea de analizar las palabras rusas es mucho más complicada, pero como se sugiere en los comentarios, hay bibliotecas listas para esto.

Vamos a descubrir cómo construir una imagen así:



También veremos una nube de artículos de Habr para todos los años.

A quién le importa lo que pasó, por favor, debajo del gato.

Analizando


El conjunto de datos inicial, como en el caso anterior, es csv con los encabezados de los artículos de Habr de 2006 a 2019. Si alguien está interesado en probarlo usted mismo, puede descargarlo aquí .

Para comenzar, cargue los datos en el Marco de datos de Pandas y seleccione los encabezados para el año requerido.

df = pd.read_csv(log_path, sep=',', encoding='utf-8', error_bad_lines=True, quotechar='"', comment='#') if year != 0: dates = pd.to_datetime(df['datetime'], format='%Y-%m-%dT%H:%MZ') df['datetime'] = dates df = df[(df['datetime'] >= pd.Timestamp(datetime.date(year, 1, 1))) & ( df['datetime'] < pd.Timestamp(datetime.date(year + 1, 1, 1)))] # Remove some unicode symbols def unicode2str(s): try: return s.replace(u'\u2014', u'-').replace(u'\u2013', u'-').replace(u'\u2026', u'...').replace(u'\xab', u"'").replace(u'\xbb', u"'") except: return s titles = df["title"].map(unicode2str, na_action=None) 

La función unicode2str es necesaria para eliminar varios caracteres unicode difíciles de la salida de la consola, como las comillas no estándar; en OSX esto también funcionó, y al generar en Windows Powershell, se emitió el error "UnicodeEncodeError: el códec 'charmap' no puede codificar el carácter". Era demasiado vago para lidiar con la configuración de Powershell, por lo que este método resultó ser el más fácil.

El siguiente paso es separar las palabras en ruso de todas las demás. Es bastante simple: traducimos los caracteres a codificación ascii y vemos lo que queda. Si quedan más de 2 caracteres, consideramos la palabra "completo" (la única excepción que viene a la mente es el lenguaje Go, sin embargo, aquellos que lo deseen pueden agregarlo por su cuenta).

 def to_ascii(s): try: s = s.replace("'", '').replace("-", '').replace("|", '') return s.decode('utf-8').encode("ascii", errors="ignore").decode() except: return '' def is_asciiword(s): ascii_word = to_ascii(s) return len(ascii_word) > 2 

La siguiente tarea es normalizar la palabra: para derivar una nube de palabras, cada palabra debe mostrarse en un caso y declinación. Para el inglés, simplemente eliminamos las "'s" al final y también eliminamos otros caracteres ilegibles, como los corchetes. No estoy seguro de que este método sea científicamente correcto (y no soy lingüista), pero para esta tarea es suficiente.

 def normal_eng(s): for sym in ("'s", '{', '}', "'", '"', '}', ';', '.', ',', '[', ']', '(', ')', '-', '/', '\\'): s = s.replace(sym, ' ') return s.lower().strip() 

Ahora, lo más importante, por el hecho de que todo comenzó realmente, es el análisis de las palabras rusas. Como se recomienda en los comentarios a la parte anterior, para Python esto se puede hacer usando la biblioteca pymorphy2. Veamos como funciona.

 import pymorphy2 morph = pymorphy2.MorphAnalyzer() res = morph.parse(u"") for r in res: print r.normal_form, r.tag.case 

Para este ejemplo, tenemos los siguientes resultados:

  NOUN,inan,masc sing,datv datv  NOUN,inan,masc sing,loc2 loc2  NOUN,inan,neut sing,datv datv  NOUN,inan,masc sing,gen2 gen2 

Para la palabra "mundo", MorphAnalyzer definió "forma normal" como el sustantivo "mundo" (o "mundo", sin embargo, no sé qué es), casos singulares y posibles como dativ, genitiv o locativo.

Usar el análisis MorphAnalyzer es bastante simple: asegúrese de que la palabra sea un sustantivo y obtenga su forma normal.

 morph = pymorphy2.MorphAnalyzer() def normal_rus(w): res = morph.parse(w) for r in res: if 'NOUN' in r.tag: return r.normal_form return None 

Queda por recopilar todo junto y ver qué pasó. El código se parece a esto (fragmentos irrelevantes eliminados):

 from collections import Counter c_dict = Counter() for s in titles.values: for w in s.split(): if is_asciiword(w): # English word or digit n = normal_eng(w) c_dict[n] += 1 else: # Russian word n = normal_rus(w) if n is not None: c_dict[n] += 1 

En la salida tenemos un diccionario de palabras y su número de ocurrencias. Derivamos los primeros 100 y formamos de ellos una nube de popularidad de palabras:

 common = c_dict.most_common(100) wc = WordCloud(width=2600, height=2200, background_color="white", relative_scaling=1.0, collocations=False, min_font_size=10).generate_from_frequencies(dict(common)) plt.axis("off") plt.figure(figsize=(9, 6)) plt.imshow(wc, interpolation="bilinear") plt.title("%d" % year) plt.xticks([]) plt.yticks([]) plt.tight_layout() file_name = 'habr-words-%d.png' % year plt.show() 

El resultado, sin embargo, resultó ser muy extraño:



En forma de texto, se veía así:

   3958  3619  1828  840 2018 496  389  375  375 

Las palabras "realizar", "segundo" y "siglo" fueron lideradas por un margen enorme. Y aunque, en principio, es posible (puede imaginar un encabezado como "Buscar contraseñas a una velocidad de 1000 veces por segundo llevará un siglo"), pero era sospechoso que hubiera tantas de estas palabras. Y no en vano, como mostró la depuración, MorphAnalyzer definió la palabra "c" como "segundo", y la palabra "c" como "siglo". Es decir en el encabezado "Uso de tecnología ..." MorphAnalyzer resaltó 3 palabras: "segundo", "ayuda", "tecnología", que obviamente es incorrecto. Las siguientes palabras oscuras fueron "cuándo" ("Cuando se usa ...") y "ya", que se definieron como el sustantivo "directo" y "ya", respectivamente. La solución fue simple: al analizar, considere solo palabras de más de 2 caracteres e ingrese una lista de palabras de excepción en idioma ruso que se excluirían del análisis. De nuevo, tal vez esto no sea del todo científico (por ejemplo, un artículo sobre "observar un cambio de color ya" habría abandonado el análisis), pero para esta tarea ya :) es suficiente.

El resultado final es más o menos similar a la verdad (con la excepción de Go y posibles artículos sobre serpientes). Queda por guardar todo esto en un gif (el código de generación de gif se encuentra en la parte anterior ), y obtenemos un resultado animado en forma de popularidad de palabras clave en los títulos de Habr de 2006 a 2019.



Conclusión


Como puede ver, el análisis del texto ruso con la ayuda de bibliotecas preparadas resultó ser bastante simple. Por supuesto, con algunas reservas, el lenguaje hablado es un sistema flexible con muchas excepciones y la presencia de un sentido de contexto que depende del contexto, y probablemente sea imposible obtener el 100% de certeza aquí. Pero para la tarea en cuestión, el código anterior es suficiente.

El trabajo con textos cirílicos en Python, por cierto, está lejos de ser perfecto: problemas menores con la salida de caracteres a la consola, salida rota de matrices por impresión, la necesidad de agregar "" en líneas para Python 2.7, etc. Es incluso extraño que en el siglo XXI, cuando parece que todos los atavismos como KOI8-R o CP-1252 se han extinguido, los problemas de codificación de cadenas siguen siendo relevantes.

Finalmente, es interesante observar que agregar palabras en ruso a la nube de texto prácticamente no aumentó el contenido de información de la imagen en comparación con la versión en inglés ; casi todos los términos de TI son de habla inglesa, por lo que la lista de palabras en ruso ha cambiado mucho menos significativamente en 10 años. Probablemente, para ver los cambios en el idioma ruso, debe esperar de 50 a 100 años; después del tiempo especificado, habrá una ocasión para actualizar el artículo nuevamente;)

Source: https://habr.com/ru/post/442626/


All Articles