Архив за месяц: Июль 2014

Функция токенизации текста на python

Токенизация — это разбиение текста на более мелкие части, токены. К токенам относятся как слова, так и знаки пунктуации. Достаточно часто стоит задача представить текст в виде массива значимых слов. Тогда после токенизации необходимо произвести чистку на предмет знаков пунктуации и не значимых слов (например предлогов). Так как почти всегда в задачах обработки естественного языка ставится такая задача, то я написал небольшую функцию хелпер:

# -*- coding: utf-8 -*-
import nltk
import string
from nltk.corpus import stopwords

def tokenize_me(file_text):
    #firstly let's apply nltk tokenization
    tokens = nltk.word_tokenize(file_text)

    #let's delete punctuation symbols
    tokens = [i for i in tokens if ( i not in string.punctuation )]

    #deleting stop_words
    stop_words = stopwords.words('russian')
    stop_words.extend(['что', 'это', 'так', 'вот', 'быть', 'как', 'в', '—', 'к', 'на'])
    tokens = [i for i in tokens if ( i not in stop_words )]

    #cleaning words
    tokens = [i.replace("«", "").replace("»", "") for i in tokens]

    return tokens

Поясню код. Во первых я воспользовался стандартной функцией из хорошо известной python библиотеки nltk word_tokenize(). Не смотря на все прелести данной функции, она расчитана для работы с множеством языков, а нас интересует русский язык. Из-за этого возникают некоторые неточности, которые мы обработаем дальше. К тому же эта функция не избавляет нас от знаков препинания. На следующем этапе мы избавляемся от знаков препинания, проверив каждое слово на string.punctuation. На следующем этапе вспомним про множество вспомогательных слов в русском языке, и подумаем, а нужны ли они нам? Если не нужны, то можно сделать так же как я — импортировать стоп слова из всё той же библиотеки для работы с естественным языком NLTK и исключить их из нашего конечного списка. Более того, для своих нужд я расширил этот список словами, которые не нужны в конечном итоге. На последнем шаге подчищаем результаты, убирая из слов возможный мусор. В результате получаем список слов для дальнейшей обработки.

Получение координат места по адресу

Пусть перед нами поставлена следующая задача: есть файл in.txt со списком адресов в разных городах по России. Нам необходимо написать программу, результатом работы которой будет выходной файл out.txt , в соответствующей строке должна быть широта и долгота места.

Решение данной задачи предполагает использовать метод геокодирования, который предлагает Yandex static API.

Для этого напишем следующий код на PHP

//by default max execution time is 30 seconds. But grabber need more time.. so let's set to unlimited
set_time_limit(0);

$file = fopen('in.txt', 'r');
$res = array();
while ($line = fgets($file)){
    echo $line;
    echo "
";

    $params = array(
        'geocode' => $line, //address
        'format'  => 'json', //response format
        'results' => 1, //number of output result, first is the best
    );
    $response = json_decode(file_get_contents('http://geocode-maps.yandex.ru/1.x/?' . http_build_query($params, '', '&')));

    if ($response->response->GeoObjectCollection->metaDataProperty->GeocoderResponseMetaData->found > 0)
    {
        $res[] = $response->response->GeoObjectCollection->featureMember[0]->GeoObject->Point->pos;
    }else{
        $res[] = ' - ';
    }
    //wait a bit (0.2 sec). it will predict blocking
    usleep(200000);
}
fclose($file);

//writing into file
file_put_contents('out.txt', implode("\n", $res));

В принципе всё очень просто, но немного прокомментирую:
1) как и в любом пауке, загрузка может занять много времени, поэтому не забываем увеличить время исполнения скрипта — set_time_limit()
2) Все файлы должны находится в кодировке utf-8
3) Иногда для одного запроса может находится несколько подобных мест, поэтому мы ограничиваем результат в 1 ответ — он по умолчанию самый подходящий
4) Если ничего не нашлось, то в файл будет записан прочерк
5) Брутфорсить и закидывать запросами ресурс не очень хорошо, поэтому чтобы нас не отключили за бомбёжку ставим задержку. Здесь поставлена задержка в 0.2 секунды

В результате исполнения данного скрипта, появится файл out.txt c географическими координатами каждого адреса, написанного на естественном языке. Более того, даже если адреса написаны с орфографической ошибкой, очень большой шанс что яндекс правильно интерпретирует и найдет в своей базе именно нужный объект.

Подключаем к arduino четыре сонара HC-SR04

Сонар или ультразвуковой датчик позволяет получать данные о расстоянии до препятствия. Принцип работы много где описан и расчитывается исходя из дельты по времени за которое отраженный пучок звука отразится от ближайшей поверхности. В данной статье подробно опишу как подключить несколько таких датчиков с помощью Arduino UNO и получить результат на компьютере с помощью языка python для дальнейшей обработки на более высоком уровне. Объединение нескольких датчиков расстояния может понадобится для случая, когда необходимо отслеживать наличие препятствий одновременно в разных областях. Согласно спецификации эффективный угол составляет +-15 градусов. Поэтому располагать несколько сонаров имеет смысл под углом в 30 градусов относительно друг друга. Однако для тестового запуска мы их направим в одну сторону, ибо так легче разместить на макетной плате.

Итак, на первом этапе необходимо собрать схему. У меня получилось так, где красный провод — 5 вольт, черный — земля:

схема с четырьмя сонарами

Arduino UNO и четыре ультразвуковых датчика

На втором этапе напишем код для Arduino. Нам понадобится библиотека для ультразвукового датчика. Подключается библиотека через меню Sketch->Import library…->Add library. Взять библиотеку для HC-SR04 можно здесь. Не забываем указать тип платы и верный порт — в нашем случае «COM3″

#include "Ultrasonic.h"

Ultrasonic us_4(8, 9); // Trig - first, Echo - second
Ultrasonic us_3(6, 7);
Ultrasonic us_2(4, 5);
Ultrasonic us_1(2, 3);

void setup()
{
  Serial.begin(9600); 			// start the serial port
}

void loop()
{
  float d_1 = us_1.Ranging(CM); 	// get distance
  float d_2 = us_2.Ranging(CM); 	// get distance
  float d_3 = us_3.Ranging(CM); 	// get distance
  float d_4 = us_4.Ranging(CM); 	// get distance
  Serial.print(d_1);
  Serial.print("cm, ");
  Serial.print(d_2);
  Serial.print("cm, ");
  Serial.print(d_3);
  Serial.print("cm, ");
  Serial.print(d_4);
  Serial.println("cm."); 		// print the distance
  
  delay(500); 								// arbitrary wait time.
}

Уже на данном этапе можно открыть просмотр «сериал порта» в Arduino среде и посмотреть какие расстояния показывают наши датчики. Однако теперь мы попробуем использовать данные с сонаров для дальнейшей обработки на python. Для этого напишем следующий код:

import serial

ser = serial.Serial('COM3')
print ( "connected to: " + ser.portstr )                   

while True:
    print ser.readline()

ser.close()

Порт следует указать тот же, что и в ардуино. Теперь данные с нескольких сонаров можно использовать например для навигации робота — каждые 500 миллисекунд бортовой компьютер будет получать данные об окружающем пространстве. Но об этом напишу в одном из следующих постов.