сопоставить названия географического словаря из текста в python - PullRequest
0 голосов
/ 18 февраля 2019

У меня есть список названий городов GeoNames, которые я использую для экспорта названий мест из таблицы текста.Как сопоставить многосегментное имя (например, «Санта-Барбара», «Лос-Анджелес» и т. Д.) Из списка названий городов с текстом?Названия городов, содержащие более одного слова, не распознаются.

Код, который я пробовал:

import csv
import time

#import tab-delimited keywords file
f = open('cities_key.txt','r')
allKeywords = f.read().lower().split(\n)
f.close()
#print(len(allKeywords))

allTexts = []
fullRow = []
with open('adrl_title_desc.csv') as csvfile:
    reader = csv.DictReader(csvfile)
    for row in reader:
        #the full row for each entry, which will be used to recreate the improved CSV file in a moment
        fullRow.append((row['title'], row['description']))

        #the column we want to parse for our keywords
        row = row['description'].lower()
        allTexts.append(row)
        #print(len(row))

#a flag used to keep track of which row is being printed to the CSV file
counter = 0

#use the current date and time to create a unique output filename
timestr = time.strftime(%Y-%m-%d-(%H-%M-%S))
filename = 'output-' + str(timestr) + '.csv'

#Open the new output CSV file to append ('a') rows one at a time.
with open(filename, 'a') as csvfile:

    #define the column headers and write them to the new file
    fieldnames = ['title', 'description', 'place']
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
    writer.writeheader()

    #define the output for each row and then print to the output csv file
    writer = csv.writer(csvfile)

    #this is the same as before, for currentRow in fullRow:
    for entry in allTexts:

        matches = 0
        storedMatches = []

        #for each entry:
        #HOW TO RESOLVE MULTI-PART NAMES? e.g. Santa Barbara
        allWords = entry.split(' ')
        for words in allWords:

            #remove punctuation that will interfere with matching
            words = words.replace(',', '')
            words = words.replace('.', '')
            words = words.replace(';', '')

            #if a keyword match is found, store the result.
            if words in allKeywords:
                if words in storedMatches:
                    continue
                else:
                    storedMatches.append(words)
                matches += 1

        #send any matches to a new row of the csv file.
        if matches == 0:
            newRow = fullRow[counter]
        else:
            matchTuple = tuple(storedMatches)
            newRow = fullRow[counter] + matchTuple

        #write the result of each row to the csv file
        writer.writerows([newRow])
        counter += 1

Названия городов:

enter image description here

Описание:

1 Ответ

0 голосов
/ 19 февраля 2019

Хорошая работа, приложив усилия, прежде чем просить о помощи.Вот мои изменения в вашем коде.Я сохранил ваш код и прокомментировал его, чтобы вы знали, что я делал.Использование регулярных выражений - лучший выбор для вас в этой ситуации.Я использую те же петли, что и вы.Я не разделил описание.Вместо этого я просмотрел полное описание в поисках названий городов с помощью модуля регулярных выражений.Я также не использовал список для сохраненных соответствий.Использование набора гарантирует, что вы не добавляете дубликаты.Проверка, был ли город уже добавлен - еще одна проверка, которая вам не нужна.Я использовал Python 3.7.

Я использовал import re для импорта модуля регулярных выражений.

import csv
import time
#Raj006 import regular expression module
import re

#import tab-delimited keywords file
f = open('cities_key.txt','r')
#Raj006 Not making the keywords lower. Will match with lower using regex
#allKeywords = f.read().lower().split('\n')
allKeywords = f.read().split('\n')
f.close()
#print(len(allKeywords))

allTexts = []
fullRow = []
with open('adrl_title_desc.csv') as csvfile:
    reader = csv.DictReader(csvfile)
    for row in reader:
        #the full row for each entry, which will be used to recreate the improved CSV file in a moment
        fullRow.append((row['title'], row['description']))

        #the column we want to parse for our keywords
        #row = row['description'].lower()
        #Raj006 not making description lower as regular expression takes care of case-insensitive search.
        row = row['description']
        allTexts.append(row)
        #print(len(row))

#a flag used to keep track of which row is being printed to the CSV file
counter = 0

#use the current date and time to create a unique output filename
timestr = time.strftime("%Y-%m-%d-(%H-%M-%S)")
filename = 'output-' + str(timestr) + '.csv'

#Open the new output CSV file to append ('a') rows one at a time.
with open(filename, 'a') as csvfile:

    #define the column headers and write them to the new file
    fieldnames = ['title', 'description', 'place']
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
    writer.writeheader()

    #define the output for each row and then print to the output csv file
    writer = csv.writer(csvfile)

    #this is the same as before, for currentRow in fullRow:
    for entry in allTexts:

        #matches = 0
        #Raj006 Changed this to set to make sure the list is unique (which is basically the definiton of the set)
        storedMatches = set()
        #Raj006 looping through all cities and checking if the city name exists in the description.
        #Raj006 re.search looks for the lookup word in the entire string (re.search(lookupword,string)).
        for eachcity in allKewords:
            if re.search('\\b'+eachcity+'\\b',entry,re.IGNORECASE):
                #Adding the matched city to the set
                storedMatches.add(eachcity)
        #for each entry:
        #HOW TO RESOLVE MULTI-PART NAMES? e.g. Santa Barbara
        #allWords = entry.split(' ')
        #for words in allWords:

            #remove punctuation that will interfere with matching
            #words = words.replace(',', '')
            #words = words.replace('.', '')
            #words = words.replace(';', '')

            #if a keyword match is found, store the result.
            #if words in allKeywords:
                #if words in storedMatches:
                    #continue
                #else:
                    #storedMatches.append(words)
                #matches += 1

        #send any matches to a new row of the csv file.
        #if matches == 0:
        #Raj006 Just using the length of the set to determine if any matches found. Reducing one more unnecessary check.
        if len(storedMatches)==0:
            newRow = fullRow[counter]
        else:
            matchTuple = tuple(storedMatches)
            newRow = fullRow[counter] + matchTuple

        #write the result of each row to the csv file
        writer.writerows([newRow])
        counter += 1

Обновление: в re.search добавлен регистр игнорирования.

Я улучшилприведенный выше код для удаления ненужных циклов и путаницы в именах переменных.У меня нет исходного файла, поэтому я не смог его проверить.Если я обнаружу какие-либо проблемы, я обновлю их позже.

import csv
import time
import re
allCities = open('cities_key.txt','r').readlines()
timestr = time.strftime("%Y-%m-%d-(%H-%M-%S)")
with open('adrl_title_desc.csv') as descriptions,open('output-' + str(timestr) + '.csv', 'w', newline='') as output:
    descriptions_reader = csv.DictReader(descriptions)
    fieldnames = ['title', 'description', 'cities']
    output_writer = csv.DictWriter(output, delimiter='|', fieldnames=fieldnames)
    output_writer.writeheader()
    for eachRow in descriptions_reader:
        title = eachRow['title']
        description = eachRow['description']
        citiesFound = set()
        for eachcity in allCities:
            eachcity=eachcity.strip()
            if re.search('\\b'+eachcity+'\\b',description,re.IGNORECASE):
                citiesFound.add(eachcity)
        if len(citiesFound)>0:
            output_writer.writerow({'title': title, 'description': description, 'cities': ", ".join(citiesFound)})

Этот код имеет разделитель csv, установленный на | вместо ,, как я использовал его для городов.

Тестовые файлы.towns_key.txt

San Francisco
San Gabriel
San Jacinto
San Jose
San Juan Capistrano
Haiti
San Mateo

adrl_title_desc.csv

key,title,description
1,title1,"some description here with San Francisco"
2,title2,"some, more description here with Haitian info"
3,title3,"some city not a wordSan Mateo"
4,title4,"some city San Juan Capistrano just normal"
5,title5,"multiple cities in one San Jacinto,San Jose and San Gabriel end"

Вывод кода

title|description|cities
title1|some description here with San Francisco|San Francisco
title4|some city San Juan Capistrano just normal|San Juan Capistrano
title5|multiple cities in one San Jacinto,San Jose and San Gabriel end|San Jacinto, San Jose, San Gabriel

@ itsme, теперь это не должно идти не так с Python 3.x,Я исправил ошибку с '\\b'+eachcity+'\\b' (пропущенный + знак).Вы не смогли найти совпадений, потому что когда вы по какой-то причине используете readlines(), он сохраняет окончания строк.Я использовал strip(), чтобы удалить их.Мне пришлось использовать newline='' в диалоге открытия файла, так как писатель CSV создавал новую строку после каждой строки.Вы можете видеть, что в моем примере вы не можете найти город для ключа 2 и ключа 3, поскольку города не были отделены в виде слов от остальной части текста.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...