[PYTHON] Prétraitement de texte japonais sans instruction for dans les pandas

Un rappel que lors du traitement de texte avec des pandas, vous n'obtenez pas "Je ne sais pas, alors utilisez une phrase pour".

Collectez des informations dans le but de prétraiter le texte japonais.

J'apprécierais que vous me disiez s'il existe une meilleure méthode de traitement.

Environnement d'exécution

pandas 0.25.3

TL;DR

Exemple de données

Stockez des informations sur les marques de mode pour femmes extraites de HP. Le nom de l'entreprise, le nom de la marque, le nom du magasin et l'adresse sont stockés dans csv.

Puisqu'il est gratté à partir de plusieurs HP, il n'est pas unifié tel que demi-largeur pleine largeur et vierge. Le code postal peut être inclus ou non.

Le tableau ci-dessous est un exemple de données. Le résultat de l'exécution est également décrit en utilisant ces données à titre d'exemple.

company brand location address
pal BONbazaar Bombazare Tokyo Dome City La Coeur 1-1 Kasuga, Bunkyo-ku, Tokyo-1 Bâtiment La Coeur 2F
world index Style Emio 1 Takada Baba, Shinjuku-ku, Tokyo-35-3 Style Emio 1F
pal Whim Gazette Magasin Marunouchi 〒100-6390 2 Marunouchi, Chiyoda-ku, Tokyo-4-1 Bâtiment Marunouchi B1F
stripe SEVENDAYS=SUNDAY Centre commercial Aeon Urawa Misono 2F 5-50-1, Misono, Midori-ku, Saitama-shi, Saitama Aeon Mall Urawa Misono
pal mystic Magasin Funabashi 〒273-0012 2 Hamacho, Funabashi City, Préfecture de Chiba-1-1 LaLaport TOKYO-BAY LaLaport 3
pal pual ce cin Magasin Ofuna Lumine Wing 〒247-0056 1 Ofuna, ville de Kamakura, préfecture de Kanagawa-4-1 Aile Lumine 4F
stripe Green Parks Boutique sara Chapo Koiwa 7 Minamikoiwa, Edogawa-ku, Tokyo-24-15 Chapo Koiwa 1F
pal Discoat Discoat Petit Ikebukuro Shopping Park 〒171-8532 1 Minami Ikebukuro, Toyoshima-ku, Tokyo-29-1 Ikebukuro SP B1F
adastoria niko and... Atre Kawagoe 105 Wakita-cho, Kawagoe-shi, Saitama Atre Kawagoe 4F
pal CIAOPANIC TYPY Magasin Kameari 〒125-0061 3 Kameari, Katsushika-ku, Tokyo-49-3 Ario Kameari 2F

Comme une seule colonne (colonne ʻaddress`) est utilisée pour l'explication, le traitement de Series est presque introduit, mais le traitement de DataFrame est également décrit autant que possible.

En traitement

Fondamentalement, dans Series.str, méthode de chaîne python et [opération d'expression régulière] Vous pouvez appeler (https://docs.python.org/ja/3/library/re.html), vous pouvez donc les utiliser.

――Extraits d'articles fréquemment utilisés --Si vous souhaitez vérifier toutes les méthodes, veuillez vous référer au document officiel. --Référence: Résultats de la recherche Series.str - Working with text data — pandas 1.0.1 documentation

Système de méthode de chaîne de caractères

strip

Series.str.strip

Supprimez les caractères vides au début et à la fin de la chaîne de caractères.

df['strip']=df['address'].str.strip()

Bien entendu, «Series.str.rstrip», qui ne supprime que le début, et «lstrip», qui ne supprime que la fin, sont également implémentés.

split, rsplit

Series.str.split

--Split la chaîne par le séparateur spécifié et retourne-la dans * list * --Si vous définissez ʻexpand = True`, vous pouvez diviser en plusieurs colonnes.

df['address'].str.split(expand=True)
0 1 2
1-1 Kasuga, Bunkyo-ku, Tokyo-1 Édifice La Coeur 2F
1 Takada Baba, Shinjuku-ku, Tokyo-35-3 Style Emio 1F
〒100-6390 2 Marunouchi, Chiyoda-ku, Tokyo-4-1 Bâtiment Marunouchi B1F
5-50-1, Misono, Midori-ku, Saitama-shi, Saitama Centre commercial Aeon Urawa Misono None
〒273-0012 2 Hamacho, Funabashi City, Préfecture de Chiba-1-1 LaLaport TOKYO-BAY LaLaport 3 None
〒247-0056 1 Ofuna, ville de Kamakura, préfecture de Kanagawa-4-1 Lumine Wing 4F
7 Minamikoiwa, Edogawa-ku, Tokyo-24-15 Chapo Koiwa 1F None
〒171-8532 1 Minami Ikebukuro, Toyoshima-ku, Tokyo-29-1 Ikebukuro SP B1F None
Ville de Wakita, ville de Kawagoe, préfecture de Saitama 105 Atre Kawagoe 4F
〒125-0061 3 Kameari, Katsushika-ku, Tokyo-49-3 Ario Kameari 2F None None
df['address'].str.rsplit(expand=True, n=1)
0 1
1-1 Kasuga, Bunkyo-ku, Tokyo-1 Édifice La Coeur 2F
1 Takada Baba, Shinjuku-ku, Tokyo-35-3 style Emio 1F
〒100-6390 2 Marunouchi, Chiyoda-ku, Tokyo-4-1 Bâtiment Marunouchi B1F
5-50-1, Misono, Midori-ku, Saitama-shi, Saitama Centre commercial Aeon Urawa Misono
〒273-0012 2 Hamacho, Funabashi City, Préfecture de Chiba-1-1 LaLaport TOKYO-BAY LaLaport 3
〒247-0056 1 Ofuna, ville de Kamakura, préfecture de Kanagawa-4-1 Lumine Wing 4F
7 Minamikoiwa, Edogawa-ku, Tokyo-24-15 Chapo Koiwa 1F
〒171-8532 1 Minami Ikebukuro, Toyoshima-ku, Tokyo-29-1 Ikebukuro SP B1F
105 Wakita-cho, Kawagoe-shi, Saitama Atre Kawagoe 4F
〒125-0061 3 Kameari, Katsushika-ku, Tokyo-49-3 Ario Kameari 2F None

find

Series.str.find

df['address'].str.find('Tokyo')
>> 0    0
1    0
2    10
3    -1
4    -1
5    -1
6    0
7    9
8    -1
9    9
#Pour le moment"Tokyo"Il est également possible de spécifier une colonne qui ne contient pas
df.query('address.str.find("Tokyo")!=-1')

normalize Series.str.normalize

Principalement, les nombres et les symboles pleine largeur sont convertis en demi-largeur et le katakana demi-largeur est converti en pleine largeur. Spécifiez «NFKC» (forme normale KC) pour la forme.

# string
import unicodedata
unicodedata.normalize('NFKC', '123! ?? @ # Hankaku Katakana')
>> '123!?@#Hankaku Katakana'

# pandas
df['normalize'] = df['address'].str.normalize(form='NFKC')

Référence: Liste des caractères normalisés par unicodedata.normalize ('NFKC', x) en Python

Système d'expression régulière

findall

Series.str.findall

--Equivalent à re.findall ()

df['address'].str.findall('(.{2}quartier)')
>> 0    [Quartier Bunkyo]
1    [Quartier Shinjuku]
2    [Quartier de Shirota]
3    [Quartier de la ville de Midori]
4       []
5       []
6    [Quartier Togawa]
7    [Quartier de Toshima]
8       []
9    [Katsushika]

contains

Series.str.contains

--contain ** s **, alors soyez prudent --Fonctionnellement re.match () --Parce que la valeur booléenne est renvoyée, elle peut être utilisée pour affiner les données.

df['address'].str.contains('.{2}quartier')
>> 0     True
1     True
2     True
3     True
4    False
5    False
6     True
7     True
8    False
9     True

#  "○○ salle"Afficher uniquement les données contenant
df.query('address.str.contains(".{2}quartier")')['address']
>>0 1-1 Kasuga, Bunkyo-ku, Tokyo-1 Bâtiment La Coeur 2F
1 Takada Baba, Shinjuku-ku, Tokyo 1-35-3 Style Emio 1F
2    〒100-6390 2 Marunouchi, Chiyoda-ku, Tokyo-4-1 Bâtiment Marunouchi B1F
3 5-50-1 Misono, Midori-ku, Saitama-shi, Saitama Aeon Mall Urawa Misono
6 Minamikoiwa, Edogawa-ku, Tokyo 7-24-15 Chapo Koiwa 1F
7             〒171-8532 1 Minami Ikebukuro, Toyoshima-ku, Tokyo-29-1 Ikebukuro SP B1F
9               〒125-0061 3 Kameari, Katsushika-ku, Tokyo-49-3 Ario Kameari 2F
Marquer les colonnes contenant des chaînes

En convertissant la valeur booléenne en valeur int, vous pouvez créer une colonne avec «1» dans les données contenant une certaine chaîne de caractères. Pratique pour l'ingénierie de quantité d'entités pour créer des quantités d'entités.

#Drapeau de données tokyo y compris Tokyo_Créer flg
df['tokyo_flg'] = df['address'].str.contains("Tokyo").astype(int)
df['tokyo_flg']
>> 0    1
1    1
2    1
3    0
4    0
5    0
6    1
7    1
8    0
9    1

extract Series.str.extract

--Retourne le motif correspondant. --Retourne None s'il n'y a pas de modèle, donc dropna () si pas nécessaire --Si vous définissez un nom de groupe nommé, ce nom sera le nom de la colonne tel quel

df['address'].str.extract('(Tokyo|Préfecture de Kanagawa)([^Ville de quartier]+[Ville de quartier])').dropna()

df['address'].str.extract('(?P<pref>Tokyo|Préfecture de Kanagawa)(?P<city>[^Ville de quartier]+[Ville de quartier])').dropna()
pref city
0 Tokyo Quartier Bunkyo
1 Tokyo Quartier Shinjuku
2 Tokyo Quartier Chiyoda
5 Préfecture de Kanagawa Ville de Kamakura
6 Tokyo Quartier Edogawa
7 Tokyo Quartier de Toshima
9 Tokyo Katsushika

Vous pouvez créer des tables pour XX Ward à Tokyo et XX City dans la préfecture de Kanagawa.

replace

Series.str.replace

--Equivalent à re.sub () --Series.str.replace (pat, repl) convertit la chaîne qui correspond à pat en repl

#Supprimer le code postal
df['address'] = df['address'].str.replace("〒[0-9]{3}\-[0-9]{4}", "")

Au fait, Series.replace est différent de «Series.str.replace» au format dictionnaire. Peut être passé

Faites quelque chose que les pandas n'ont pas

Si vous souhaitez utiliser vos propres fonctions ou fonctions packagées (neologdn, mecab, etc.)

Utilisez Series.apply. En passant une fonction comme Series.apply (func), vous pouvez exécuter le traitement de cette fonction sur les données de Series. Vous pouvez également passer une fonction lambda.

#Au début du texte'adresse de rue'Insérer
df['address'].apply(lambda x:  'adresse de rue' + x)

Le prétraitement réel du texte sera résumé ci-dessous.

neologdn (prétraitement de texte)

neologdn 0.4

Un package de normalisation de texte japonais qui peut normaliser de longues notes et des refroidisseurs qui ne peuvent pas être traités par la bibliothèque standard Normaliser seule.

Bien sûr, avant d'analyser avec mecab Si vous l'utilisez avant d'obtenir la chaîne de caractères avec une expression régulière, l'expression régulière à écrire sera simplifiée, il est donc préférable de l'exécuter d'abord pour le texte japonais.

import neologdn
df['neologdn'] = df['address'].apply(neologdn.normalize)

#DataFrame avec fonction lambda.Vous pouvez également postuler
df['neologdn'] = df.apply(lambda x: neologdn.normalize(x['address']), axis=1)

Partage

mecab-python3

mecab-python3 0.996.3

Si vous ne voulez que le résultat de la division, spécifiez -Owakati.

import MeCab

# `-d`Spécifiez le chemin du dictionnaire avec
tagger = MeCab.Tagger('-Owakati -d /usr/local/lib/mecab/dic/ipadic/')
df['neologdn'].apply(tagger.parse)

Dans ce cas, le dernier saut de ligne \ n est également attaché, donc si vous souhaitez le supprimer, vous pouvez définir votre propre fonction ou utiliser l'instruction lambda.

tagger = MeCab.Tagger('-Owakati -d /usr/local/lib/mecab/dic/ipadic/')

#Définir la fonction
def my_parser(text):
    res = tagger.parse(text)
    return res.strip()

df['neologdn'].apply(my_parser)


#Pas besoin de déclarer une fonction avec la fonction lambda
df['neologdn'].apply(lambda x : tagger.parse(x).strip())
>>0 Kasuga 1-1, Bunkyo-ku, Tokyo-1 Bâtiment La Coeur 2 F
1 Takada Baba, Shinjuku-ku, Tokyo 1- 35 -3 Style Emio 1 F
2 Marunouchi, Chiyoda-ku, Tokyo 2- 4 -1 Bâtiment Marunouchi B 1 F
3 5-50 Misono, Midori-ku, Saitama City, Saitama Prefecture 1 Aeon Mall Urawa Misono
4 Hamacho, ville de Funabashi, préfecture de Chiba 2- 1 -1 LaLaport TOKYO-BAY LaLaport 3
5 Ofuna, ville de Kamakura, préfecture de Kanagawa 1- 4 -1 Aile Lumine 4 F
6 Minamikoiwa, Edogawa-ku, Tokyo 7- 24 -15 Chapo Koiwa 1 F
7 Minami Ikebukuro, Toyoshima-ku, Tokyo 1- 29 -1 Ikebukuro SP B 1 F
8 Wakita Town, Kawagoe City, Préfecture de Saitama 105 Atre Kawagoe 4 F
9 Kameari, Katsushika-ku, Tokyo 3- 49 -3 Ario Kameari 2 F

Sudachipy

SudachiDict-core 20190718
SudachiPy 0.4.2

Dans SudachiPy, si vous souhaitez obtenir le résultat de la division comme le mecab ci-dessus, vous devez créer une fonction qui ne renvoie que la couche de surface de l'objet de résultat d'analyse.

from sudachipy import tokenizer
from sudachipy import dictionary


tokenizer_obj = dictionary.Dictionary().create()
mode = tokenizer.Tokenizer.SplitMode.C

def sudachi_tokenize(text):
    res = tokenizer_obj.tokenize(text, mode)
    return ' '.join([m.surface() for m in res])

df['address'].apply(sudachi_tokenize)
>>0 1-chome, Kasuga, Bunkyo-ku, Tokyo-1 Bâtiment La Coeur 2 F
1 Takada Baba, Shinjuku-ku, Tokyo 1- 35 -3 Style Emio 1 F
2 Marunouchi, Chiyoda-ku, Tokyo 2- 4 -1 Bâtiment Marunouchi B 1 F
3 5-50 Misono, Midori-ku, Saitama City, Saitama Prefecture 1 Aeon Mall Urawa Misono
4 Hamacho, ville de Funabashi, préfecture de Chiba 2- 1 -1 LaLaport TOKYO-BAY LaLaport 3
5 Ofuna, ville de Kamakura, préfecture de Kanagawa 1- 4 -1 Aile Lumine 4 F
6 Minamikoiwa, Edogawa-ku, Tokyo 7- 24 -15 Chapo Koiwa 1 F
7 Minami Ikebukuro, Toyoshima-ku, Tokyo 1- 29 -1 Ikebukuro SP B 1 F
8 105 Wakita-cho, Kawagoe-shi, Saitama Atre Kawagoe 4 F
9 Kameari, Katsushika-ku, Tokyo 3- 49 -3 Ario Kameari 2 F

Au fait, contrairement à l'ipadic de mecab, le SplitMode.C de Sudachi semble rassembler les adresses. (Traitez-vous préfecture + ville / quartier / ville / village comme une expression unique?)

Passer le mode comme argument

En plus des résultats ci-dessus Sudachi a 3 unités séparées (Split Mode), vous pouvez donc utiliser la fonction sudachi_tokenize pour spécifier le mode. Essayez de personnaliser.

Puisque Series.apply peut transmettre des arguments de longueur variable, vous pouvez ajouter les arguments du côté fonction et spécifier les arguments du côté appliquer.

def sudachi_tokenize_with_mode(text, mode):
    res = tokenizer_obj.tokenize(text, mode)
    return ' '.join([m.surface() for m in res])

df['address'].apply(sudachi_tokenize_with_mode, mode=tokenizer.Tokenizer.SplitMode.A)
>>0 Kasuga 1-1, Bunkyo-ku, Tokyo-1 Bâtiment La Coeur 2 F
1 Takada Baba, Shinjuku-ku, Tokyo 1- 35 -3 Style Emio 1 F
2 Marunouchi, Chiyoda-ku, Tokyo 2- 4 -1 Bâtiment Marunouchi B 1 F
3 5-50 Misono, Midori-ku, Saitama City, Saitama Prefecture 1 Aeon Mall Urawa Misono
4 Hamacho, ville de Funabashi, préfecture de Chiba 2- 1 -1 LaLaport TOKYO-BAY LaLaport 3
5 Ofuna, ville de Kamakura, préfecture de Kanagawa 1- 4 -1 Aile Lumine 4 F
6 Minamikoiwa, Edogawa-ku, Tokyo 7- 24 -15 Chapo Koiwa 1 F
7 Minami Ikebukuro, Toyoshima-ku, Tokyo 1- 29 -1 Ikebukuro SP B 1 F
8 Atre Kawagoe 4F, 105 Wakita-cho, Kawagoe-shi, Saitama
9 Kameari, Katsushika-ku, Tokyo 3- 49 -3 Ario Kameari 2 F

Avec SplitMode.A, le résultat était presque le même que celui de mecab.

Utiliser expand

Sudachi a une fonction de normalisation qui modifie * simulation * en * simulation *.

Envisagez de renvoyer normalized_form en même temps et d'en faire un DataFrame.

Puisque Series.apply n'a pas de fonction d'expansion, essayez de l'exécuter en spécifiant result_type = 'expand' dans DataFrame.apply.

def sudachi_tokenize_multi(text):
    res = tokenizer_obj.tokenize(text, mode)
    return ' '.join([m.surface() for m in res]), ' '.join([m.normalized_form() for m in res])

df.apply(lambda x: sudachi_tokenize_multi(x['neologdn']), axis=1, result_type='expand')
0 1
0 1-1 Kasuga, Bunkyo-ku, Tokyo-1 Bâtiment La Coeur 2 F 1-1 Kasuga, Bunkyo-ku, Tokyo-1 La Coeur 2 f
1 1 Takada Baba, Shinjuku-ku, Tokyo- 35 -3 Style Emio 1 F 1 Takada Baba, Shinjuku-ku, Tokyo- 35 -3 Style Emio 1 f
2 2 Marunouchi, Chiyoda-ku, Tokyo- 4 -1 Bâtiment Marunouchi B 1 F 2 Marunouchi, Chiyoda-ku, Tokyo- 4 -1 Bâtiment Marunouchi b 1 f
3 5-50, Midori-ku, Saitama-shi, Saitama Aeon Mall Urawa Misono 5-50, Midori-ku, Saitama-shi, Saitama Aeon Mall Urawa Misono
4 2 Hamacho, ville de Funabashi, préfecture de Chiba- 1 -1 LaLaport TOKYO-BAY LaLaport 3 2 Hamacho, ville de Funabashi, préfecture de Chiba- 1 -1 LaLaport Tokyo-Baie LaLaport 3
5 1 Ofuna, ville de Kamakura, préfecture de Kanagawa- 4 -1 Aile Lumine 4 F 1 Ofuna, ville de Kamakura, préfecture de Kanagawa- 4 -1 Aile Lumine 4 f
6 7 Minamikoiwa, Edogawa-ku, Tokyo- 24 -15 Chapo Koiwa 1 F 7 Minamikoiwa, Edogawa-ku, Tokyo- 24 -15 Shappo Koiwa 1 f
7 1 Minami Ikebukuro, Toyoshima-ku, Tokyo- 29 -1 Ikebukuro SP B 1 F 1 Minami Ikebukuro, Toyoshima-ku, Tokyo- 29 -1 Ikebukuro SP b 1 f
8 105 Wakita-cho, Kawagoe-shi, Saitama Atre Kawagoe 4F 105 Wakita-cho, Kawagoe-shi, Saitama Atre Kawagoe 4 f
9 3 Kameari, Katsushika-ku, Tokyo- 49 -3 Ario Kameari 2 F 3 Kameari, Katsushika-ku, Tokyo- 49 -3 Ario Kameari 2 f

Dans le cas de l'adresse, je pensais que cela n'aurait aucun effet particulier, mais * Chapo * a été converti en * Shappo *, et * TOKYO --BAY * a été converti en * Tokyo --Bay *. Les caractères alphabétiques tels que F sont également inférieurs pour une raison quelconque.

Autre

Quant à l'ordre de prétraitement personnel

  1. neologdn
  2. Supprimez les chaînes inutiles avec des expressions régulières et remplissez les valeurs manquantes
  3. Séparation avec mecab

Cependant, si vous utilisez SudachiPy, il dispose également d'une fonction de normalisation, vous pouvez donc le tokeniser d'abord, puis supprimer ou compléter les caractères.

Comme je l'ai écrit au début, j'apprécierais que vous me disiez s'il existe une meilleure méthode de traitement.

Recommended Posts

Prétraitement de texte japonais sans instruction for dans les pandas
Prétraitement japonais pour l'apprentissage automatique
Changer la liste dans l'instruction for
Précautions lors de l'utilisation de l'instruction for dans les pandas
Inversez les pandas DataFrame à l'envers avec seulement 15 caractères sans utiliser l'instruction for
N'utilisez pas readlines () dans votre instruction Python for!
[Python] Lire le csv japonais avec des pandas sans caractères déformés (extraire davantage les colonnes écrites en japonais)
For Else déclaration
Double boucle dans l'instruction for puis impression du comportement de l'instruction
Résumé des méthodes de prétraitement pour les débutants en Python (trame de données Pandas)
Pratique pour utiliser les sous-graphiques matplotlib dans l'instruction for
Lorsque vous voulez plt.save dans l'instruction for
[Mémo] Correspondance de texte dans le cadre de données pandas à l'aide de Flashtext