- Оригинальный адрес:Analysing 1.4 billion rows with python
- Оригинальный автор:Steve Stagg
- Перевод с:Программа перевода самородков
- Постоянная ссылка на эту статью:GitHub.com/rare earth/gold-no…
- Переводчик:Ryden Sun
- Корректор:luochen1992 allen
Анализ 1,4 миллиарда фрагментов данных с помощью Python
Использование pytubes, numpy и matplotlib
Google Ngram viewer— это забавный и полезный инструмент, который использует огромную сокровищницу данных, которые Google сканирует из книг, чтобы отображать использование слов с течением времени. Например, словоPython(деликатный случай):
Эта картинка из:books.Google.com/ngrams/ и рэп…, изображающий использование слова «Python» с течением времени.
это от гуглаn-gramНа основе набора данных регистрирует использование определенного слова или фразы в Google Книгах за каждый год издания книги. Однако это неполный список (он не включает каждую опубликованную книгу!), в наборе данных миллионы книг, охватывающих период с 16 века по 2008 год. наборы данных могутСкачать бесплатно отсюда.
Я решил использовать Python и мою новую библиотеку загрузки данныхPyTubesДавайте посмотрим, как легко регенерировать график выше.
вызов
Набор данных в 1 грамм может быть расширен до 27 ГБ данных на жестком диске, что является большим объемом данных при чтении в Python. Python может легко обрабатывать гигабайты данных за один раз, но когда данные повреждены и обработаны, он работает медленнее и менее эффективно использует память.
В общей сложности эти 1,4 миллиарда фрагментов данных (1 430 727 243) разбросаны по 38 исходным файлам, что в сумме составляет 24 миллиона (24 359 460) слов (и тегов частей речи, см. ниже), рассчитанных с 1505 по 2008 год.
При работе с 1 миллиардом строк данных он быстро замедляется. И собственный Python не оптимизирован для обработки этих данных. К счастью,numpyДействительно хорошо справляется с большими объемами данных. Используя несколько простых приемов, мы можем сделать этот анализ возможным, используя numpy.
Обработка строк в python/numpy сложна. Накладные расходы памяти на строки в python значительны, и numpy может обрабатывать только строки известной и фиксированной длины. Исходя из этой ситуации, большинство слов имеют разную длину, так что это не идеально.
Loading the data
Весь приведенный ниже код/примеры выполняются на8 ГБ ОЗУМакбук Про 2016 года. Он будет работать лучше, если аппаратное обеспечение или облачный экземпляр имеют лучшую конфигурацию оперативной памяти.
Данные по 1 грамму хранятся в файле в форме, разделенной табуляцией, и выглядят следующим образом:
Python 1587 4 2
Python 1621 1 1
Python 1651 2 2
Python 1659 1 1
Каждая часть данных содержит следующие поля:
1. Word
2. Year of Publication
3. Total number of times the word was seen
4. Total number of books containing the word
Чтобы сгенерировать диаграмму в соответствии с требованиями, нам нужно знать только эту информацию, а именно:
1. 这个单词是我们感兴趣的?
2. 发布的年份
3. 单词使用的总次数
Извлекая эту информацию, игнорируются дополнительные затраты на обработку строковых данных разной длины, но нам все равно нужно сравнивать значения разных строк, чтобы различать, какие строки данных имеют интересующие поля. Вот что умеет pytubes:
import tubes
FILES = glob.glob(path.expanduser("~/src/data/ngrams/1gram/googlebooks*"))
WORD = "Python"
# Set up the data load pipeline
one_grams_tube = (tubes.Each(FILES)
.read_files()
.split()
.tsv(headers=False)
.multi(lambda row: (
row.get(0).equals(WORD.encode('utf-8')),
row.get(1).to(int),
row.get(2).to(int)
))
)
# 将数据读入一个 numpy 数组。通过设置一个大概的精准度
# 预估行数,pytubes 优化分配模式
# fields=True 这里是冗余的,但是确保了返回的 ndarray
# 使用字段,而不是一个单独的多维数组 one_grams = one_grams_tube.ndarray(estimated_rows=500_000_000, fields=True)
Спустя почти 170 секунд (3 минуты)one_gramsпредставляет собой массив numpy, содержащий почти 1,4 миллиарда строк данных, который выглядит следующим образом (заголовок таблицы добавлен для иллюстрации):
╒═══════════╤════════╤═════════╕
│ Is_Word │ Year │ Count │
╞═══════════╪════════╪═════════╡
│ 0 │ 1799 │ 2 │
├───────────┼────────┼─────────┤
│ 0 │ 1804 │ 1 │
├───────────┼────────┼─────────┤
│ 0 │ 1805 │ 1 │
├───────────┼────────┼─────────┤
│ 0 │ 1811 │ 1 │
├───────────┼────────┼─────────┤
│ 0 │ 1820 │ ... │
╘═══════════╧════════╧═════════╛
Отсюда просто нужно что-то вычислить с помощью метода numpy:
Общее использование слов в год
Google показывает процент вхождений каждого слова (количество вхождений определенного слова в год / общее количество вхождений всех слов в год), что более полезно, чем просто подсчет исходного слова. Чтобы рассчитать этот процент, нам нужно знать, каково общее количество слов.
К счастью, numpy делает это очень просто:
last_year = 2008
YEAR_COL = '1'
COUNT_COL = '2'
year_totals, bins = np.histogram(
one_grams[YEAR_COL],
density=False,
range=(0, last_year+1),
bins=last_year + 1,
weights=one_grams[COUNT_COL]
)
Нарисуйте этот график, чтобы показать, сколько слов Google собирает каждый год:
Понятно, что до 1800 года общий объем данных быстро уменьшался, поэтому это время искажает конечный результат и скрывает интересующие нас закономерности. Чтобы избежать этой проблемы, мы импортируем данные только после 18:00:
one_grams_tube = (tubes.Each(FILES)
.read_files()
.split()
.tsv(headers=False)
.skip_unless(lambda row: row.get(1).to(int).gt(1799))
.multi(lambda row: (
row.get(0).equals(word.encode('utf-8')),
row.get(1).to(int),
row.get(2).to(int)
))
)
Это возвращает 1,3 миллиарда строк данных (всего 3,7% до 1800 года).
Процент Python в год
Получить процент питона в каждом году теперь очень просто.
Используя простой прием для создания массива на основе лет, элементы 2008 long означают, что индекс каждого года равен номеру года, поэтому, например, 1995 — это просто вопрос получения элементов для 1995 года.
Ничто из этого не стоит работать с numpy:
# 找到匹配的行 (column 是 Ture)
word_rows = one_grams[IS_WORD_COL]
# 创建一个空数组来保存每年占比百分数的值
word_counts = np.zeros(last_year+1)
# 迭代至每条匹配的数据 (匹配一个单词时,应该只有几千行数据)
for _, year, count in one_grams[word_rows]:
# 设置相关的 word_counts 行为计算后的数值
word_counts[year] += (100*count) / year_totals[year]
Постройте результат word_counts:
Форма похожа на версию Google
Фактические проценты не совпадают, я думаю, это потому, что загруженный набор данных содержит разные слова (например: Python_VERB). Этот набор данных не очень хорошо объяснен на странице Google и вызывает несколько вопросов:
- Как люди используют Python в качестве глагола?
- Включает ли общее количество вычислений для «Python» «Python_VERB»? Ждать
К счастью, мы все знаем, что метод, который я использовал, создает значок, очень похожий на Google, и ни одна из связанных тенденций не затрагивается, поэтому я не собираюсь пытаться исправить это для этого исследования.
представление
Google генерирует изображение примерно за 1 секунду, что разумно по сравнению с 8 минутами для этого скрипта. Базовая часть подсчета слов Google исходит из очевидного представления подготовленного набора данных.
Например, заранее подсчитав общее количество использованных слов за предыдущий год и сохранив его в отдельной таблице поиска, можно значительно сэкономить время. Аналогичным образом, хранение использования слова в отдельной базе данных/файле, а затем индексирование первого столбца сократит почти все время обработки.
это исследованиеВ самом делепоказал, что можно загружать, обрабатывать и извлекать произвольную статистику из наборов данных из миллиардов строк данных в разумные сроки, используя numpy и неоперившиеся pytube, а также стандартное общедоступное оборудование и Python,
языковая война
Чтобы продемонстрировать концепцию на чуть более сложном примере, я решил сравнить три родственных упомянутых языка программирования:Питон, Паскаль,иPerl.
Исходные данные зашумлены (в них присутствуют все используемые английские слова, а не только упоминания языков программирования, и, например, у python есть и нетехнические значения!), чтобы скорректировать это, мы сделали две вещи:
- Сопоставляются только имена с заглавной буквы (Python, а не python)
- Общее количество упоминаний для каждого языка было преобразовано в среднее процентное значение от 1800 до 1960, что должно иметь разумный базовый уровень, учитывая, что Паскаль впервые упоминается в 1970 году.
результат:
По сравнению с Гуглом (без каких-либо базовых корректировок):
Время выполнения: чуть более 10 минут
Код:gist.GitHub.com/Саттер говорит, что он просто/91…
Будущие улучшения PyTubes
На данном этапе у pytubes есть концепция только одного целого числа, которое составляет 64 бита. Это означает, что массивы numpy, созданные pytubes, используют dtypes i8 для всех целых чисел. В некоторых местах (например, данные ngrams) 8-битные целые числа немного излишние и тратят память (общий размер ndarray составляет 38 ГБ, dtypes может легко уменьшить его на 60%). Я планирую добавить некоторую поддержку 1-, 2- и 4-битных целых чисел класса (GitHub.com/Саттер говорит, что он просто/друзья…)
Больше логики фильтрации. Tube.skip_unless() — это более простой способ фильтрации строк, но в нем отсутствует возможность комбинировать условия (И/ИЛИ/НЕ). В некоторых случаях это может уменьшить размер загружаемых данных быстрее.
Улучшенное сопоставление строк — можно легко добавить такие простые тесты, как:startwith,endwith, contains и is_one_of, чтобы значительно повысить эффективность загрузки строковых данных.
Как всегда всем очень радыpatches!
Программа перевода самородковэто сообщество, которое переводит высококачественные технические статьи из Интернета сНаггетсДелитесь статьями на английском языке на . Охват контентаAndroid,iOS,внешний интерфейс,задняя часть,блокчейн,продукт,дизайн,искусственный интеллекти другие поля, если вы хотите видеть больше качественных переводов, пожалуйста, продолжайте обращать вниманиеПрограмма перевода самородков,официальный Вейбо,Знай колонку.