Определение ключевых слов (языка программирования)
Это продолжение моего недавнего вопроса ( Код для определения языка программирования в текстовом файле). Я очень благодарен за все ответы, которые я получил, это мне очень помогло. Мой код для этой задачи завершен, и он работает довольно хорошо - быстро и достаточно точно.
Метод, который я использовал, заключается в следующем: у меня есть "обучающий" Perl-скрипт, который идентифицирует наиболее часто используемые слова в языке, выполняя гистограмму слов по набору файлов примеров. Эти данные затем загружаются программой C++, которая затем проверяет заданный текст и накапливает баллы для каждого языка на основе найденных слов, а затем просто проверяет, какой язык набрал наибольшее количество баллов.
Теперь я хотел бы сделать это еще лучше и немного поработать над качеством идентификации. Проблема в том, что я часто получаю "неизвестность" в результате (многие языки набирают небольшой балл, но ни один не превышает мой порог). После некоторой отладки, исследований и т. Д. Я обнаружил, что это, вероятно, связано с тем, что все слова считаются равными. Это означает, что просмотр "#include", например, имеет тот же эффект, что и "while" - оба указывают на то, что это может быть c/ C++ (сейчас я игнорирую тот факт, что "while" используется во многих других языки), но, конечно, в больших файлах.cpp может быть тонна "while", но в большинстве случаев только несколько "#include".
Поэтому тот факт, что "#include" является более важным, игнорируется, потому что я не смог придумать, как определить, является ли слово более важным, чем другое. Теперь имейте в виду, что скрипт, который создает данные, довольно глуп, его гистограмма всего лишь слово, и для каждого выбранного слова он присваивает оценку 1. Он даже не смотрит на слова (поэтому, если есть "#&|?/"в файле очень часто это может быть выбрано как хорошее слово).
Также я хотел бы, чтобы часть создания данных была полностью автоматизирована, поэтому никто не должен смотреть на данные и изменять их, менять оценки, менять слова и т. Д. Все "brainz" должно быть в скрипте и программе cpp.
У кого-нибудь есть предложение, как определить ключевые слова или, в более общем смысле, важные слова? Некоторые вещи, которые могут помочь: у меня есть количество вхождений каждого слова и общее количество слов (поэтому можно рассчитать соотношение). Я также думал о том, чтобы уничтожить такие символы, как; и т. Д., Так как скрипт гистограммы часто помещает, например, "продолжить"; в результате, но важное слово "продолжить". Последнее замечание: все проверки на равенство выполняются для точного соответствия - без подстрок, с учетом регистра. Это в основном из-за скорости, но подстроки могут помочь (или повредить, я не знаю)...
ПРИМЕЧАНИЕ: спасибо всем, кто удосужился ответить, вы мне очень помогли.
Моя работа с этим почти закончена, поэтому я опишу, что я сделал, чтобы получить хорошие результаты.
1) Получите приличный обучающий набор, около 30-50 файлов на язык из разных источников, чтобы избежать смещения стиля кодирования
2) Напишите Perl-скрипт, который выполняет гистограмму слова. Реализация черного и белого списков (подробнее об этом ниже)
3) добавить фиктивные слова в черный список, такие как "лицензия", "и т. Д.". Они часто встречаются в начале файла в информации о лицензии.
4) добавить около пяти самых важных слов для каждого языка в белый список. Это слова, которые встречаются в большинстве исходных кодов данного языка, но не достаточно часто встречаются в гистограмме. Например, для C/C++ у меня были: #include, #define, #ifdef, #ifndef и #endif в белом списке.
5) Подчеркните начало файла, поэтому дайте больше очков словам, найденным в первых 50-100 строках.
6) при выполнении гистограммы слова токенизируйте файл, используя @words = split(/[\s\(\){}\[\];.,=]+/, $_);
Это должно быть хорошо для большинства языков, я думаю (дает мне лучшие результаты). Для каждого языка, есть около 10-20 наиболее часто встречающихся слов в окончательных результатах.
7) Когда гистограмма будет завершена, удалите все слова, найденные в черном списке, и добавьте все те, которые находятся в белом списке.
8) Напишите программу, которая обрабатывает текстовый файл так же, как скрипт - токенизируйте по тем же правилам. Если в данных гистограммы найдено слово, добавьте точки на нужный язык. Слова в гистограмме, которые соответствуют только одному языку, должны добавлять больше точек, а те, которые принадлежат нескольким языкам, должны добавлять меньше.
Комментарии приветствуются. В настоящее время около 1000 текстовых файлов я получаю 80 неизвестных (в основном на очень короткие файлы - в основном JavaScript с одной или двумя строками). Около 20 файлов распознаются неправильно. Размер файлов составляет около 11 КБ в диапазоне от 100 до 100 КБ (почти 11 МБ). Обработка их всех занимает одну секунду, что для меня достаточно.
4 ответа
Я думаю, что вы подходите к этому с неправильной точки зрения. Из вашего описания звучит, как будто вы строите классификатор. Хороший классификатор должен различать разные классы; ему не нужно точно оценивать соответствие между входом и наиболее вероятным классом.
Практически: ваш классификатор не должен точно оценивать, насколько близок к C++ определенный ввод; ему просто нужно определить, больше ли ввод похож на C, чем на C++. Это делает вашу работу намного проще - большинство ваших текущих "неизвестных" дел будут близки к одному или двум языкам, даже если они не превышают ваш базовый порог.
Теперь, когда вы поймете это, вы также увидите, что нужно вашему классификатору: не какой-то случайный аспект файлов примеров, а то, что отличает два языка. Следовательно, когда вы проанализировали ваши сэмплы C и ваши сэмплы C++, вы увидите, что #include
не выделяет их Тем не мение, class
а также template
будет гораздо чаще встречаться в C++. С другой стороны, #include
делает различие между C++ и Java.
Конечно, есть и другие аспекты, помимо ключевых слов, которые вы можете использовать. Например, наиболее очевидным будет частота {
, а также ;
аналогично отличительный. Еще одна очень полезная функция для вашего классификатора - это маркеры комментариев для разных языков. Конечно, основной проблемой будет их автоматическая идентификация. Опять хардкод //
, /*
, '
, --
, #
а также !
как псевдо-ключевые слова помогут.
Это также определяет другое правило классификации: SQL часто будет иметь --
в начале строки, тогда как в C это часто будет появляться где-то еще. Таким образом, вашему классификатору может быть полезно учитывать контекст.
Используйте Google Code Search, чтобы узнать весовые коэффициенты для набора ключевых слов: #include в C++ получает 672 000 показов, в Python только ~5000.
Вы можете нормализовать результаты, посмотрев общее количество результатов для языка: C++ дает около 770 000 файлов, тогда как Python возвращает 120 000.
Таким образом, "#include" крайне редко встречается в файлах Python, но существует почти в каждом файле C++. (Теперь вам все еще нужно научиться различать C++ и C. Конечно, все, что осталось, - это правильно рассуждать о вероятностях.
Вы должны получить некоторую исключительность в ваших данных поиска.
При изучении языков программирования, которые вы ожидаете, вы должны искать слова, типичные для одного или нескольких языков. Если слово появляется в нескольких кодовых файлах одного и того же языка, но встречается в нескольких или ни в одном из других языковых файлов, это сильный совет для этого языка.
Таким образом, оценка слова может быть рассчитана на стороне поиска путем выбора слов, которые являются исключительными для языка или группы языков. Найдите несколько из этих слов и получите их пересечение, сложив баллы, и найдите свой язык, который у вас будет.
В ответ на ваш другой вопрос кто-то порекомендовал наивный байесовский классификатор. Вы должны реализовать это предложение, потому что техника хороша в разделении по отличительным признакам. Вы упомянули while
ключевое слово, но это вряд ли будет полезно, потому что его используют многие языки - и байесовский классификатор не будет считать его полезным.
Интересная часть вашей проблемы - как маркировать неизвестную программу. Куски, разделенные пробелами, - неплохое начало, но выходить за рамки этого будет непросто.