NaturalLanguage для Swift: полное руководство с примерами
Библиотека NaturalLanguage (фреймворк NaturalLanguage) — это мощный инструмент для обработки естественного языка (NLP), встроенный непосредственно в экосистему Apple. Она предоставляет разработчикам Swift доступ к передовым алгоритмам машинного обучения для анализа текста, не требуя внешних зависимостей или облачных сервисов. С её помощью можно выполнять такие задачи, как токенизация, распознавание языка, лемматизация, выделение именованных сущностей (NER), определение частей речи (POS) и многое другое.
Зачем нужна NaturalLanguage? В современной разработке приложений для iOS, macOS, watchOS и tvOS часто возникает необходимость «понимать» текст, введённый пользователем. Это может быть анализ отзывов, поиск ключевых слов, автоматический перевод, проверка орфографии или создание интеллектуальных чат-ботов. NaturalLanguage позволяет решать эти задачи на устройстве, что обеспечивает конфиденциальность данных (всё обрабатывается локально), высокую скорость работы и возможность функционирования в офлайн-режиме.
Фреймворк тесно интегрирован с другими технологиями Apple, такими как Core ML и Create ML. Это означает, что вы можете не только использовать готовые модели, но и обучать собственные на основе NaturalLanguage. Библиотека оптимизирована для работы на всех устройствах Apple, от iPhone до Mac, и поддерживает более 50 языков. В этой статье мы подробно разберём все ключевые возможности NaturalLanguage, начиная с установки и заканчивая сложными практическими примерами.
1. Установка
Поскольку NaturalLanguage является частью стандартных SDK Apple, его не нужно устанавливать через менеджеры пакетов (CocoaPods, Swift Package Manager, Carthage). Для использования достаточно импортировать фреймворк в ваш проект.
Точная команда (не требуется):
// Установка не требуется. Просто импортируйте фреймворк в файл Swift.
import NaturalLanguage
Настройка в Xcode:
- Откройте ваш проект в Xcode.
- В файле, где вы планируете использовать NLP, добавьте в самом верху:
import NaturalLanguage. - Убедитесь, что ваш проект настроен на iOS 12+ или macOS 10.14+ (проверьте в настройках проекта: Deployment Target).
Если вы используете Swift Package Manager для управления зависимостями, вам не нужно добавлять NaturalLanguage — он уже доступен. Для CocoaPods или Carthage также не требуется никаких дополнительных действий.
2. Быстрый старт — минимальный рабочий пример
Давайте начнём с простейшего примера: определения языка текста. Это одна из самых востребованных функций.
import NaturalLanguage
// Текст для анализа
let text = "Bonjour le monde! Как дела? Hello world!"
// Создаем распознаватель языка
let recognizer = NLLanguageRecognizer()
// Обрабатываем текст
recognizer.processString(text)
// Получаем основной язык
if let dominantLanguage = recognizer.dominantLanguage {
print("Основной язык текста: \(dominantLanguage.rawValue)") // Например: "fr" (французский)
} else {
print("Не удалось определить язык.")
}
// Получаем гипотезы по всем языкам
let languageHypotheses = recognizer.languageHypotheses(withMaximum: 3)
for (language, confidence) in languageHypotheses {
print("Язык: \(language.rawValue), уверенность: \(confidence * 100)%")
}
Этот пример показывает, как за несколько строк кода определить, на каком языке написан текст, и даже получить список вероятных языков с процентом уверенности. Всё работает локально, без интернета.
3. Основные методы/функции/классы
Рассмотрим 8 ключевых компонентов NaturalLanguage, которые покроют 90% задач NLP.
3.1 NLLanguageRecognizer — распознавание языка
class NLLanguageRecognizer
Что делает: Определяет язык текста. Может возвращать как доминирующий язык, так и список гипотез с вероятностями.
import NaturalLanguage
let text = "This is an English sentence."
let recognizer = NLLanguageRecognizer()
recognizer.processString(text)
if let language = recognizer.dominantLanguage {
print("Язык: \(language.rawValue)") // "en"
}
// Гипотезы
let hypotheses = recognizer.languageHypotheses(withMaximum: 2)
for (lang, prob) in hypotheses {
print("\(lang.rawValue): \(prob)")
}
3.2 NLTokenizer — токенизация текста
class NLTokenizer
Что делает: Разбивает текст на токены (слова, предложения, абзацы, документы). Позволяет получить диапазоны (NSRange) каждого токена.
import NaturalLanguage
let text = "Hello, world! How are you? I am fine."
let tokenizer = NLTokenizer(unit: .word) // .word, .sentence, .paragraph, .document
tokenizer.string = text
tokenizer.enumerateTokens(in: text.startIndex..<text.endIndex) { tokenRange, _ in
let token = text[tokenRange]
print("Токен: '\(token)'")
return true // продолжаем перечисление
}
// Вывод:
// Токен: 'Hello'
// Токен: 'world'
// Токен: 'How'
// ... и т.д.
3.3 NLTagger — тегирование (лемматизация, POS, NER)
class NLTagger
Что делает: Универсальный класс для лемматизации, определения частей речи (POS), распознавания именованных сущностей (NER) и других видов тегирования.
import NaturalLanguage
let text = "Steve Jobs founded Apple in Cupertino."
let tagger = NLTagger(tagSchemes: [.lemma, .nameType, .lexicalClass])
tagger.string = text
let range = text.startIndex..<text.endIndex
tagger.enumerateTags(in: range, unit: .word, scheme: .nameType, options: [.omitWhitespace]) { tag, tokenRange in
if let tag = tag {
let token = text[tokenRange]
print("Сущность: '\(token)' -> \(tag.rawValue)")
}
return true
}
// Вывод: Сущность: 'Steve' -> PersonalName, 'Jobs' -> PersonalName, 'Apple' -> OrganizationName, 'Cupertino' -> PlaceName
3.4 NLModel — использование обученных моделей
class NLModel
Что делает: Позволяет загружать и использовать модели машинного обучения (созданные в Create ML или Core ML) для классификации текста или анализа тональности.
import NaturalLanguage
// Предположим, у нас есть обученная модель SentimentClassifier.mlmodel
guard let model = try? NLModel(mlModel: SentimentClassifier().model) else {
fatalError("Не удалось загрузить модель")
}
let text = "This product is amazing! I love it."
let prediction = model.predictedLabel(for: text)
print("Тональность: \(prediction ?? "неизвестно")") // "positive"
// Получить вероятности для всех классов
let hypotheses = model.predictedLabelHypotheses(for: text, maximumCount: 3)
for (label, probability) in hypotheses {
print("\(label): \(probability * 100)%")
}
3.5 NLSequence — работа с последовательностями
class NLSequence
Что делает: Представляет последовательность токенов (например, слов) для передачи в модели, работающие с последовательностями (RNN, LSTM). Используется редко в простых задачах, но важен для продвинутых сценариев.
import NaturalLanguage
let words = ["I", "love", "Swift"]
let sequence = NLSequence(words: words, types: [.word])
// Используется в паре с NLModel для предсказания последовательностей
// Например, для тегирования частей речи на уровне последовательности
let tagger = NLTagger(tagSchemes: [.lexicalClass])
tagger.string = words.joined(separator: " ")
let tags = tagger.tags(in: words.startIndex..<words.endIndex, unit: .word, scheme: .lexicalClass)
print(tags) // Массив опциональных тегов
3.6 NLTagScheme — схемы тегирования
struct NLTagScheme
Что делает: Определяет, какие типы тегов вы хотите получить от NLTagger. Встроенные схемы: .lemma, .lexicalClass (POS), .nameType (NER), .sentimentScore, .script и другие.
import NaturalLanguage
let text = "She sells seashells by the seashore."
let tagger = NLTagger(tagSchemes: [.lexicalClass, .lemma])
tagger.string = text
let range = text.startIndex..<text.endIndex
tagger.enumerateTags(in: range, unit: .word, scheme: .lexicalClass, options: [.omitWhitespace]) { tag, tokenRange in
if let tag = tag {
let token = text[tokenRange]
print("\(token) -> \(tag.rawValue)") // 'She' -> Pronoun, 'sells' -> Verb, etc.
}
return true
}
3.7 NLTag — сами теги
struct NLTag
Что делает: Представляет собой конкретный тег, возвращаемый NLTagger. Например, .personalName, .organizationName, .placeName, .verb, .noun, .adjective и т.д.
import NaturalLanguage
let tagger = NLTagger(tagSchemes: [.nameType])
tagger.string = "Tim Cook works at Apple."
tagger.enumerateTags(in: tagger.string!.startIndex..<tagger.string!.endIndex,
unit: .word,
scheme: .nameType,
options: [.omitWhitespace]) { tag, range in
if let tag = tag {
print("Тег: \(tag.rawValue)") // PersonalName, OrganizationName
}
return true
}
3.8 NLTokenizer — продвинутая токенизация с единицами
func enumerateTokens(in: Range<String.Index>, using: (Range<String.Index>, NLTokenizer.Attributes) -> Bool)
Что делает: Позволяет перечислять токены с дополнительными атрибутами, такими как числовые значения, даты и т.д. (доступно для unit .word).
import NaturalLanguage
let text = "I bought 3 apples for $5.99 on 2023-10-05."
let tokenizer = NLTokenizer(unit: .word)
tokenizer.string = text
tokenizer.enumerateTokens(in: text.startIndex..<text.endIndex) { tokenRange, attributes in
let token = text[tokenRange]
if attributes.contains(.numeric) {
print("Число: '\(token)'")
} else if attributes.contains(.hasDate) {
print("Дата: '\(token)'")
} else {
print("Слово: '\(token)'")
}
return true
}