Как анализировать данные на Python с Pandas: первые шаги

Мария Жарова Эксперт по Python и математике для Data Science, ментор одного из проектов на курсе по Data Science.
Pandas — главная Python-библиотека для анализа данных. Она быстрая и мощная: в ней можно работать с таблицами, в которых миллионы строк. Вместе с Марией Жаровой, ментором проекта на курсе по Data Science, рассказываем про команды, которые позволят начать работать с реальными данными.
Среда разработки
Pandas работает как в IDE (средах разработки), так и в облачных блокнотах для программирования. Как установить библиотеку в конкретную IDE, читайте тут. Мы для примера будем работать в облачной среде Google Colab. Она удобна тем, что не нужно ничего устанавливать на компьютер: файлы можно загружать и работать с ними онлайн, к тому же есть совместный режим для работы с коллегами. Про Colab мы писали в этом обзоре. Пройдите тест и узнайте, какой вы аналитик данных и какие перспективы вас ждут. Ссылка в конце статьи.

Освойте профессию «Data Scientist» на курсе с МГУ
Data Scientist с нуля до PRO
Освойте профессию Data Scientist с нуля до уровня PRO на углубленном курсе совместно с академиком РАН из МГУ. Изучите продвинутую математику с азов, получите реальный опыт на практических проектах и начните работать удаленно из любой точки мира.

25 месяцев
Data Scientist с нуля до PRO
Создавайте ML-модели и работайте с нейронными сетями
5 658 ₽/мес 11 317 ₽/мес

Анализ данных в Pandas
-
Создание блокнота в Google Colab На сайте Google Colab сразу появляется экран с доступными блокнотами. Создадим новый блокнот:

Импортирование библиотеки Pandas недоступна в Python по умолчанию. Чтобы начать с ней работать, нужно ее импортировать с помощью этого кода:
import pandas as pd

pd — это распространенное сокращенное название библиотеки. Далее будем обращаться к ней именно так.
И прочитать с помощью такой команды:
Это можно сделать через словарь и через преобразование вложенных списков (фактически таблиц).

Если нужно посмотреть на другое количество строк, оно указывается в скобках, например df.head(12) . Последние строки фрейма выводятся методом .tail() .
Также чтобы просто полностью красиво отобразить датасет, используется функция display() . По умолчанию в Jupyter Notebook, если написать имя переменной на последней строке какой-либо ячейки (даже без ключевого слова display), ее содержимое будет отображено.

Характеристики датасета Чтобы получить первичное представление о статистических характеристиках нашего датасета, достаточно этой команды: df.describe()


Обзор содержит среднее значение, стандартное отклонение, минимум и максимум, верхние значения первого и третьего квартиля и медиану по каждому столбцу.
Работа с отдельными столбцами или строками
Выделить несколько столбцов можно разными способами.
1. Сделать срез фрейма df[[‘Место в рейтинге’, ‘Ожидаемая продолжительность здоровой жизни’]]

Срез можно сохранить в новой переменной: data_new = df[[‘Место в рейтинге’, ‘Ожидаемая продолжительность здоровой жизни’]]
Теперь можно выполнить любое действие с этим сокращенным фреймом.
2. Использовать метод loc
Если столбцов очень много, можно использовать метод loc, который ищет значения по их названию: df.loc [:, ‘Место в рейтинге’:’Социальная поддержка’]

В этом случае мы оставили все столбцы от Места в рейтинге до Социальной поддержки.

Станьте дата-сайентистом на курсе с МГУ и решайте амбициозные задачи с помощью нейросетей
3. Использовать метод iloc
Если нужно вырезать одновременно строки и столбцы, можно сделать это с помощью метода iloc: df.iloc[0:100, 0:5]
Первый параметр показывает индексы строк, которые останутся, второй — индексы столбцов. Получаем такой фрейм:

В методе iloc значения в правом конце исключаются, поэтому последняя строка, которую мы видим, — 99.
4. Использовать метод tolist()
Можно выделить какой-либо столбец в отдельный список при помощи метода tolist(). Это упростит задачу, если необходимо извлекать данные из столбцов: df[‘Баллы’].tolist()
Часто бывает нужно получить в виде списка названия столбцов датафрейма. Это тоже можно сделать с помощью метода tolist(): df.columns.tolist()

Добавление новых строк и столбцов
В исходный датасет можно добавлять новые столбцы, создавая новые «признаки», как говорят в машинном обучении. Например, создадим столбец «Сумма», в который просуммируем значения колонок «ВВП на душу населения» и «Социальная поддержка» (сделаем это в учебных целях, практически суммирование этих показателей не имеет смысла): df[‘Сумма’] = df[‘ВВП на душу населения’] + df[‘Социальная поддержка’]

Можно добавлять и новые строки: для этого нужно составить словарь с ключами — названиями столбцов. Если вы не укажете значения в каких-то столбцах, они по умолчанию заполнятся пустыми значениями NaN. Добавим еще одну страну под названием Country: new_row = df = df.append(new_row, ignore_index=True)

Важно: при добавлении новой строки методом .append() не забывайте указывать параметр ignore_index=True, иначе возникнет ошибка.
Иногда бывает полезно добавить строку с суммой, медианой или средним арифметическим) по столбцу. Сделать это можно с помощью агрегирующих (aggregate (англ.) — группировать, объединять) функций: sum(), mean(), median(). Для примера добавим в конце строку с суммами значений по каждому столбцу: df = df.append(df.sum(axis=0), ignore_index = True)

Удаление строк и столбцов
Удалить отдельные столбцы можно при помощи метода drop() — это целесообразно делать, если убрать нужно небольшое количество столбцов. df = df.drop([‘Сумма’], axis = 1)
В других случаях лучше воспользоваться описанными выше срезами.
Обратите внимание, что этот метод требует дополнительного сохранения через присваивание датафрейма с примененным методом исходному. Также в параметрах обязательно нужно указать axis = 1, который показывает, что мы удаляем именно столбец, а не строку.
Соответственно, задав параметр axis = 0, можно удалить любую строку из датафрейма: для этого нужно написать ее номер в качестве первого аргумента в методе drop(). Удалим последнюю строчку (указываем ее индекс — это будет количество строк): df = df.drop(df.shape[0]-1, axis = 0)
Копирование датафрейма
Можно полностью скопировать исходный датафрейм в новую переменную. Это пригодится, если нужно преобразовать много данных и при этом работать не с отдельными столбцами, а со всеми данными: df_copied = df.copy()
Уникальные значения
Уникальные значения в какой-либо колонке датафрейма можно вывести при помощи метода .unique(): df[‘Страна или регион’].unique()
Чтобы дополнительно узнать их количество, можно воспользоваться функцией len(): len(df[‘Страна или регион’].unique())
Подсчет количества значений
Отличается от предыдущего метода тем, что дополнительно подсчитывает количество раз, которое то или иное уникальное значение встречается в колонке, пишется как .value_counts(): df[‘Страна или регион’].value_counts()

Группировка данных
Некоторым обобщением .value_counts() является метод .groupby() — он тоже группирует данные какого-либо столбца по одинаковым значениям. Отличие в том, что при помощи него можно не просто вывести количество уникальных элементов в одном столбце, но и найти для каждой группы сумму / среднее значение / медиану по любым другим столбцам.
Рассмотрим несколько примеров. Чтобы они были более наглядными, округлим все значения в столбце «Баллы» (тогда в нем появятся значения, по которым мы сможем сгруппировать данные): df[‘Баллы_new’] = round(df[‘Баллы’])
1) Сгруппируем данные по новому столбцу баллов и посчитаем, сколько уникальных значений для каждой группы содержится в остальных столбцах. Для этого в качестве агрегирующей функции используем .count(): df.groupby(‘Баллы_new’).count()
Получается, что чаще всего страны получали 6 баллов (таких было 49):

2) Получим более содержательный для анализа данных результат — посчитаем сумму значений в каждой группе. Для этого вместо .count() используем sum(): df.groupby(‘Баллы_new’).sum()

3) Теперь рассчитаем среднее значение по каждой группе, в качестве агрегирующей функции в этом случае возьмем mean(): df.groupby(‘Баллы_new’).mean()

4) Рассчитаем медиану. Для этого пишем команду median(): df.groupby(‘Баллы_new’).median()

Это самые основные агрегирующие функции, которые пригодятся на начальном этапе работы с данными.
Вот пример синтаксиса, как можно сагрегировать значения по группам при помощи сразу нескольких функций:
df_agg = df.groupby(‘Баллы_new’).agg(< 'Баллы_new': 'count', 'Баллы_new': 'sum', 'Баллы_new': 'mean', 'Баллы_new': 'median' >)
Сводные таблицы
Бывает, что нужно сделать группировку сразу по двум параметрам. Для этого в Pandas используются сводные таблицы или pivot_table(). Они составляются на основе датафреймов, но, в отличие от них, группировать данные можно не только по значениям столбцов, но и по строкам.
В ячейки такой таблицы помещаются сгруппированные как по «координате» столбца, так и по «координате» строки значения. Соответствующую агрегирующую функцию указываем отдельным параметром.
Разберемся на примере. Сгруппируем средние значения из столбца «Социальная поддержка» по баллам в рейтинге и значению ВВП на душу населения. В прошлом действии мы уже округлили значения баллов, теперь округлим и значения ВВП: df[‘ВВП_new’] = round(df[‘ВВП на душу населения’])
Теперь составим сводную таблицу: по горизонтали расположим сгруппированные значения из округленного столбца «ВВП» (ВВП_new), а по вертикали — округленные значения из столбца «Баллы» (Баллы_new). В ячейках таблицы будут средние значения из столбца «Социальная поддержка», сгруппированные сразу по этим двум столбцам: pd.pivot_table(df, index = [‘Баллы_new’], columns = [‘ВВП_new’], values = ‘Социальная поддержка’, aggfunc = ‘mean’)

Сортировка данных
Строки датасета можно сортировать по значениям любого столбца при помощи функции sort_values(). По умолчанию метод делает сортировку по убыванию. Например, отсортируем по столбцу значений ВВП на душу населения: df.sort_values(by = ‘ВВП на душу населения’).head()

Видно, что самые высокие ВВП совсем не гарантируют высокое место в рейтинге.
Чтобы сделать сортировку по убыванию, можно воспользоваться параметром ascending (от англ. «по возрастанию») = False: df.sort_values(by = ‘ВВП на душу населения’, ascending=False)

Фильтрация
Иногда бывает нужно получить строки, удовлетворяющие определенному условию; для этого используется «фильтрация» датафрейма. Условия могут быть самые разные, рассмотрим несколько примеров и их синтаксис:
1) Получение строки с конкретным значением какого-либо столбца (выведем строку из датасета для Норвегии): df[df[‘Страна или регион’] == ‘Norway’]

2) Получение строк, для которых значения в некотором столбце удовлетворяют неравенству. Выведем строки для стран, у которых «Ожидаемая продолжительность здоровой жизни» больше единицы:
df[df[‘Ожидаемая продолжительность здоровой жизни’] > 1]

3) В условиях фильтрации можно использовать не только математические операции сравнения, но и методы работы со строками. Выведем строки датасета, названия стран которых начинаются с буквы F, — для этого воспользуемся методом .startswith():
df[df[‘Страна или регион’].str.startswith(‘F’)]

4) Можно комбинировать несколько условий одновременно, используя логические операторы. Выведем строки, в которых значение ВВП больше 1 и уровень социальной поддержки больше 1,5: df[(df[‘ВВП на душу населения’] > 1) & (df[‘Социальная поддержка’] > 1.5)]

Таким образом, если внутри внешних квадратных скобок стоит истинное выражение, то строка датасета будет удовлетворять условию фильтрации. Поэтому в других ситуациях можно использовать в условии фильтрации любые функции/конструкции, возвращающие значения True или False.
Применение функций к столбцам
Зачастую встроенных функций и методов для датафреймов из библиотеки бывает недостаточно для выполнения той или иной задачи. Тогда мы можем написать свою собственную функцию, которая преобразовывала бы строку датасета как нам нужно, и затем использовать метод .apply() для применения этой функции ко всем строкам нужного столбца.
Рассмотрим пример: напишем функцию, которая преобразует все буквы в строке к нижнему регистру, и применим к столбцу стран и регионов: def my_lower(row): return row.lower() df[‘Страна или регион’].apply(lower)

Очистка данных
Это целый этап работы с данными при подготовке их к построению моделей и нейронных сетей. Рассмотрим основные приемы и функции.
1) Удаление дубликатов из датасета делается при помощи функции drop_duplucates(). По умолчанию удаляются только полностью идентичные строки во всем датасете, но можно указать в параметрах и отдельные столбцы. Например, после округления у нас появились дубликаты в столбцах «ВВП_new» и «Баллы_new», удалим их: df_copied = df.copy() df_copied.drop_duplicates(subset = [‘ВВП_new’, ‘Баллы_new’])
Этот метод не требует дополнительного присваивания в исходную переменную, чтобы результат сохранился, — поэтому предварительно создадим копию нашего датасета, чтобы не форматировать исходный.
Строки-дубликаты удаляются полностью, таким образом, их количество уменьшается. Чтобы заменить их на пустые, можно использовать параметр inplace = True. df_copied.drop_duplicates(subset = [‘ВВП_new’, ‘Баллы_new’], inplace = True)

2) Для замены пропусков NaN на какое-либо значение используется функция fillna(). Например, заполним появившиеся после предыдущего пункта пропуски в последней строке нулями: df_copied.fillna(0)

3) Пустые строки с NaN можно и вовсе удалить из датасета, для этого используется функция dropna() (можно также дополнительно указать параметр inplace = True): df_copied.dropna()
Построение графиков
В Pandas есть также инструменты для простой визуализации данных.
1) Обычный график по точкам.
Построим зависимость ВВП на душу населения от места в рейтинге: df.plot(x = ‘Место в рейтинге’, y = ‘ВВП на душу населения’)

2) Гистограмма.
Отобразим ту же зависимость в виде столбчатой гистограммы: df.plot.hist(x = ‘Место в рейтинге’, y = ‘ВВП на душу населения’)

3) Точечный график.
df.plot.scatter(x = ‘Место в рейтинге’, y = ‘ВВП на душу населения’)

Мы видим предсказуемую тенденцию: чем выше ВВП на душу населения, тем ближе страна к первой строчке рейтинга.
Сохранение датафрейма на компьютер
Сохраним наш датафрейм на компьютер: df.to_csv(‘WHR_2019.csv’)
Теперь с ним можно работать и в других программах.
Блокнот с кодом можно скачать здесь (формат .ipynb).
Упорядоченные наборы данных
Данная глава знакомит читателя с массивами — коллекциями элементов, упорядоченных по индексу. Глава включает в себя описание массивов и массивоподобных структур, таких как Array и TypedArray .
Array объект
Массив представляется собой упорядоченный набор значений, к которому вы ссылаетесь по имени и индексу. Допустим, у вас есть массив с именем emp, содержащий имена сотрудников и упорядоченный по номеру сотрудников. Следовательно, emp[1] будет представлять собой имя сотрудника номер один, emp[2] — имя сотрудника номер два, и т.д.
Язык JavaScript не содержит явного типа данных «массив». Тем не менее, возможно использовать предопределённый объект Array и его методы для работы с массивами в создаваемых приложениях. Объект Array содержит методы для работы с массивами самыми различными способами, например, есть методы для объединения, переворачивания и сортировки. Объект содержит свойство для определения длины массива, а также свойства для работы с регулярными выражениями.
Создание массива
Следующие выражения создают одинаковые массивы:
var arr = new Array(element0, element1, . , elementN); var arr = Array(element0, element1, . , elementN); var arr = [element0, element1, . , elementN];
element0, element1, . elementN — список значений элементов массива. Если значения заданы, то эти значения будут являться элементами массива после его инициализации. Свойство length у массива будет равно количеству аргументов.
Синтаксис с использованием квадратных скобок называется «литерал массива» (array literal) или «инициализатор массива». Такая запись короче, чем другие способы создания массива, и, как правило, более предпочтительна. См. Array literals.
Для создания массива без элементов, но ненулевой длины, возможно использовать одно из следующих выражений:
var arr = new Array(arrayLength); var arr = Array(arrayLength); // Точно такой же эффект var arr = []; arr.length = arrayLength;
Примечание: в примере выше arrayLength должно иметь числовой тип Number . В противном случае будет создан массив с единственным элементом (указанное значение). Вызванная функция arr.length вернёт значение arrayLength , но на самом деле массив будет содержать пустые элементы (undefined). Использование цикла for. in для обработки значений массива не вернёт ни одного элемента.
Массивы могут быть присвоены свойству нового или уже существующего объекта, как показано ниже:
var obj = >; // . obj.prop = [element0, element1, . , elementN]; // OR var obj = prop: [element0, element1, . ., elementN]>
Если вы хотите инициализировать массив одним элементом и этим элементом является число типа Number, то вы должны использовать квадратные скобки. Если вы создаёте массив с помощью Array (конструктора или функции), а единственным элементом этого массива будет число типа Number, то число это интерпретируется как длина массива (arrayLength), а не как элемент типа Number.
var arr = [42]; // Создаёт массив с одним элементом var arr = Array(42); // Создаёт массив без элементов, // но устанавливает длину массива arr.length в 42 // Это эквивалентно следующему var arr = []; arr.length = 42;
Вызов Array(N) выбросит RangeError, если N не целое значение, чья дробная часть не ноль. Следующий пример иллюстрирует это.
var arr = Array(9.3); // RangeError: Invalid array length
Если ваш код нуждается в создании массива с одним элементом произвольного типа данных, то безопасней использовать литеральную запись. Или создайте пустой массив, а затем добавьте необходимый элемент.
Заполнение массива
Вы можете заполнить массив путём присвоения значений его элементам. Для примера:
var emp = []; emp[0] = "Casey Jones"; emp[1] = "Phil Lesh"; emp[2] = "August West";
Примечание: Если вы используете нецелое значение в операторе [] обращения к элементу массива, то будет создано соответствующее свойство в объекте, представляющем массив, вместо элемента массива (так как массивы в JavaScript являются объектами).
var arr = []; arr[3.4] = "Oranges"; console.log(arr.length); // 0 console.log(arr.hasOwnProperty(3.4)); // true
Вы можете заполнить массив во время создания:
var myArray = new Array("Hello", myVar, 3.14159); var myArray = ["Mango", "Apple", "Orange"];
Работа с элементами массива
Вы можете ссылаться на элементы массива путём использования их порядковых номеров. Для примера, предположим, что вы определили следующий массив:
var myArray = ["Wind", "Rain", "Fire"];
Затем вы сослались на первый элемент массива как myArray[0] и второй элемент массива как myArray[1]. Индексация элементов массива начинается с нуля.
Примечание: оператор обращения к элементу массива (квадратные скобки []) также используется для доступа к свойствам массива (массивы также являются объектами в JavaScript). Например:
var arr = ["one", "two", "three"]; arr[2]; // three arr["length"]; // Вернёт число 3, так как это свойство - длина массива
Понимание length
На уровне реализации, массивы в JavaScript хранят свои элементы как стандартные свойства объекта, используя индекс в качестве имени свойства. Специальное свойство length всегда возвращает индекс последнего элемента плюс один (в примере ниже, элемент ‘Dusty’ размещается под индексом 30, по этому cats.length возвращает 30 + 1). Особо следует запомнить, что в JavaScript массивы индексируются с нуля: отсчёт ведётся с 0, а не с 1. Из этого и следует, что свойство length всегда на единицу больше, чем наибольший индекс хранящийся в массиве:
var cats = []; cats[30] = ["Dusty"]; console.log(cats.length); // 31
Также, вы можете задавать значение для length . Установка значения меньшего, чем количество хранящихся в массиве элементов, обрезает массив с конца; установка length равным 0 очищает массив полностью:
var cats = ["Dusty", "Misty", "Twiggy"]; console.log(cats.length); // 3 cats.length = 2; console.log(cats); // выводит в консоль "Dusty,Misty" - элемент "Twiggy" был удалён cats.length = 0; console.log(cats); // выводит пустую строку; массив cats пуст cats.length = 3; console.log(cats); // выводит [undefined, undefined, undefined]
Перебор содержимого массивов
Очень распространённая задача — это перебор всех элементов массива и обработка каждого элемента некоторой операцией. Вот наипростейший способ сделать это:
var colors = ["red", "green", "blue"]; for (var i = 0; i colors.length; i++) console.log(colors[i]); >
Если вам заранее известно, что ни один элемент массива не будет расценён как false при приведении к boolean — например, каждый элемент массива является DOM (en-US) узлом, тогда вы можете блеснуть чуть более эффективным оборотом:
var divs = document.getElementsByTagName("div"); for (var i = 0, div; (div = divs[i]); i++) /* Обработать div некоторой операцией */ >
Подход в примере выше, позволяет избежать проверки длинны массива при каждой итерации, и лишь убеждается, что переменной div присвоен существующий текущий элемент массива при каждом прохождении цикла.
Метод forEach() предоставляет другой способ перебора элементов:
var colors = ["red", "green", "blue"]; colors.forEach(function (color) console.log(color); >);
Как вариант, вы можете сократить код программы, используя стрелочные функции из ES6:
var colors = ["red", "green", "blue"]; colors.forEach((color) => console.log(color)); // red // green // blue
Функция, переданная в метод forEach , будет выполнена по одному разу для каждого элемента массива, при этом сам элемент массива будет передан как аргумент в эту функцию. Элементы, значения которым не присвоены, не обрабатываются forEach циклом.
Заметьте, что элементы, пропущенные при создании массива не обрабатываются методом forEach , однако, undefined элемент обрабатывается в том случае, когда он присвоен ячейке массива вручную:
var array = ["first", "second", , "fourth"]; array.forEach(function (element) console.log(element); >); // first // second // fourth if (array[2] === undefined) console.log("array[2] is undefined"); // true > array = ["first", "second", undefined, "fourth"]; array.forEach(function (element) console.log(element); >); // first // second // undefined // fourth
Так как в JavaScript элементы массива хранятся как обычные свойства объекта, использование for. in циклов для перебора элементов массива нежелательно, потому что будут обработаны не только элементы массива, но и все перечисляемые свойства массива.
Методы Array
Объект Array имеет следующие методы:
concat() объединяет два массива и возвращает новый массив.
var myArray = new Array("1", "2", "3"); myArray = myArray.concat("a", "b", "c"); // myArray = ["1", "2", "3", "a", "b", "c"]
join(deliminator = ‘,’) объединяет элементы массива в текстовую строку.
var myArray = new Array("Wind", "Rain", "Fire"); var list = myArray.join(" - "); // list = "Wind - Rain - Fire"
push() добавляет один или несколько элементов в конец массива и возвращает результирующую длину.
var myArray = new Array("1", "2"); myArray.push("3"); // myArray =["1", "2", "3"]
pop() удаляет из массива последний элемент и возвращает его.
var myArray = new Array("1", "2", "3"); var last = myArray.pop(); // myArray =["1", "2"], last = "3"
shift() удаляет из массива первый элемент и возвращает его.
var myArray = new Array ("1", "2", "3"); var first = myArray.shift(); // myArray = ["2", "3"], first = "1"
unshift() добавляет один или несколько элементов в начало массива и возвращает его новую длину.
var myArray = new Array("1", "2", "3"); myArray.unshift("4", "5"); // myArray becomes ["4", "5", "1", "2", "3"]
slice(start_index, upto_index) возвращает секцию массива как новый массив.
var myArray = new Array("a", "b", "c", "d", "e"); myArray = myArray.slice(1, 4); // начиная с индекса 1 извлекаются элементы вплоть до индекса 3 // myArray = [ "b", "c", "d"]
splice(index, count_to_remove, addElement1, addElement2, . ) удаляет часть элементов из массива и (опционально) заменяет их. Возвращает удалённые элементы.
var myArray = new Array("1", "2", "3", "4", "5"); myArray.splice(1, 3, "a", "b", "c", "d"); // myArray = ["1", "a", "b", "c", "d", "5"] // Этот код, начиная с ячейки под индексом 1 (в которой находилось значение "2"), // удаляет 3 элемента, и вставляет на их место // элементы, переданные в качестве последующих параметров.
reverse() переставляет элементы массива в обратном порядке: первый элемент становится последним, а последний — первым.
var myArray = new Array("1", "2", "3"); myArray.reverse(); // элементы переставлены myArray = [ "3", "2", "1" ]
sort() сортирует элементы массива.
var myArray = new Array("Wind", "Rain", "Fire"); myArray.sort(); // массив отсортирован myArray = [ "Fire", "Rain", "Wind" ]
Метод sort() может принимать в качестве аргумента callback -функцию, которая определяет каким образом сравнивать элементы массива при сортировке. Функция сравнивает два значения, и возвращает одно из трёх значений (список вариантов значений смотрите после примера):
Пример. Следующий код сортирует массив по последнему символу в строке:
var sortFn = function (a, b) if (a[a.length - 1] b[b.length - 1]) return -1; if (a[a.length - 1] > b[b.length - 1]) return 1; if (a[a.length - 1] == b[b.length - 1]) return 0; >; myArray.sort(sortFn); // массив отсортирован myArray = ["Wind","Fire","Rain"]
- если a меньше чем b в выбранной системе сравнения, возвращаем -1 (или любое отрицательное число)
- если a больше чем b в выбранной системе сравнения, возвращаем 1 (или любое положительное число)
- если a и b считаются равными, возвращаем 0.
indexOf(searchElement[, fromIndex]) ищет в массиве элемент со значением searchElement и возвращает индекс первого совпадения.
var a = ["a", "b", "a", "b", "a"]; console.log(a.indexOf("b")); // выводит 1 // Попробуем ещё раз, начиная с индекса последнего совпадения console.log(a.indexOf("b", 2)); // выводит 3 console.log(a.indexOf("z")); // выводит -1, потому что 'z' не найдено
lastIndexOf(searchElement[, fromIndex]) тоже самое, что и indexOf , но поиск ведётся в обратном порядке, с конца массива.
var a = ["a", "b", "c", "d", "a", "b"]; console.log(a.lastIndexOf("b")); // выводит 5 // Попробуем ещё раз, начиная с индекса, предшествующего индексу последнего совпадения console.log(a.lastIndexOf("b", 4)); // выводит 1 console.log(a.lastIndexOf("z")); // выводит -1
forEach(callback[, thisObject]) выполняет callback -функцию по каждому элементу массива.
var a = ["a", "b", "c"]; a.forEach(function (element) console.log(element); >); // выводит в консоль каждый элемент массива по порядку
map(callback[, thisObject]) возвращает новый массив, содержащий результаты вызова callback -функции для каждого элемента исходного массива.
var a1 = ["a", "b", "c"]; var a2 = a1.map(function (item) return item.toUpperCase(); >); console.log(a2); // выводит A,B,C
filter(callback[, thisObject]) возвращает новый массив, содержащий только те элементы исходного массива, для которых вызов callback -функции вернул true.
var a1 = ["a", 10, "b", 20, "c", 30]; var a2 = a1.filter(function (item) return typeof item == "number"; >); console.log(a2); // выводит 10,20,30
every(callback[, thisObject]) возвращает true, если вызов callback -функции вернул true для всех элементов массива.
function isNumber(value) return typeof value == "number"; > var a1 = [1, 2, 3]; console.log(a1.every(isNumber)); // выводит true var a2 = [1, "2", 3]; console.log(a2.every(isNumber)); // выводит false
some(callback[, thisObject]) возвращает true, если вызов callback -функции вернёт true хотя бы для одного элемента.
function isNumber(value) return typeof value == "number"; > var a1 = [1, 2, 3]; console.log(a1.some(isNumber)); // выводит true var a2 = [1, "2", 3]; console.log(a2.some(isNumber)); // выводит true var a3 = ["1", "2", "3"]; console.log(a3.some(isNumber)); // выводит false
Те из методов выше, что принимают callback -функцию в качестве аргумента, известны как методы итерации (iterative methods), потому что определённым образом проходятся по всем элементам массива. Каждый из таких методов принимает второй, опциональный элемент, называемый thisObject . Если этот аргумент присутствует, то его значение присваивается ключевому слову this в теле callback -функции. Иначе, как и в любом другом случае вызова функции вне явного контекста, this будет ссылаться на глобальный объект ( window ).
В действительности callback -функция вызывается с тремя аргументами. Первый аргумент — текущий элемент массива, второй — индекс этого элемента, и третий — ссылка на сам массив. Однако, в JavaScript, функции игнорируют любые аргументы, которые не перечислены в списке аргументов. Таким образом, нет ничего страшного в использовании функции с одним аргументом, такой как alert .
reduce(callback[, initialValue]) последовательно применяет callback -функцию callback(firstValue, secondValue) для того, чтобы свести все элементы массива к одному значению. В первый параметр функции передаётся предыдущий результат работы функции или первый элемент, а во второй — текущий элемент. Третьим параметром передаётся индекс текущего элемента.
var a = [10, 20, 30]; var total = a.reduce(function (first, second, index) return first + second; >, 0); console.log(total); // выводит 60
reduceRight(callback[, initalvalue]) работает так же как и reduce() , но порядок обхода ведётся от конца к началу.
Методы reduce и reduceRight являются наименее очевидными методами объекта Array. Они должны использоваться в алгоритмах, которые рекурсивно совмещают два элемента массива, для сведения всей последовательности к одному значению.
Многомерные массивы
Массивы могут быть вложенными, то есть массив может содержать массивы в элементах. Используя эту возможность массивов JavaScript, можно построить многомерные массивы.
Следующий код создаёт двумерный массив:
var a = new Array(4); for (i = 0; i 4; i++) a[i] = new Array(4); for (j = 0; j 4; j++) a[i][j] = "[" + i + "," + j + "]"; > >
В этом примере создаётся массив со следующим содержимым:
Ряд 0: [0,0] [0,1] [0,2] [0,3] Ряд 1: [1,0] [1,1] [1,2] [1,3] Ряд 2: [2,0] [2,1] [2,2] [2,3] Ряд 3: [3,0] [3,1] [3,2] [3,3]
Массивы и регулярные выражения
Когда массив является результатом вычислений регулярного выражения над строкой, он содержит свойства и элементы с информацией о совпадениях. Массив возвращается функциями RegExp.exec() , String.match() и String.split() Подробнее о том, как использовать массивы с регулярными выражениями смотрите в Regular Expressions.
Работа с массивоподобными объектами
Некоторые объекты в JavaScript, такие как NodeList , возвращаемые методом document.getElementsByTagName() , или специальный объект arguments , доступный внутри функции, выглядят и ведут себя как обычные массивы, однако не имеет всех присущих массиву методов. Так например, объект arguments имеет свойство length , но не имеет метода forEach() .
Методы из прототипа Array, могут быть вызваны для массивоподобных объектов. Например:
function printArguments() < Array.prototype.forEach.call(arguments, function(item) < console.log(item); >); >
Также методы из прототипа Array могут быть применены и к строкам, потому как строки предоставляют доступ к своим символам сходным образом:
Array.prototype.forEach.call("a string", function (chr) console.log(chr); >);
Типизированные массивы
JavaScript typed arrays (типизированные массивы) являются массивоподобными объектами, которые предоставляют механизм доступа к сырым бинарным данным. Как вы уже знаете, Array массивы динамически растут, сокращаются и могут содержать значения любых типов JavaScript. Движки JavaScript производят оптимизации, благодаря чему, эти операции происходят быстро. Однако, веб приложения становятся все более мощными, добавляются возможности манипуляции со звуковыми и видеоданными, доступ к сырым данным WebSockets, и тому подобное. Становится очевидным, что возможность быстрой и эффективной работы с двоичными данными в JavaScript будет очень полезной. Для чего типизированные массивы и предназначены.
Буферы и представления: архитектура типизированных массивов
Для достижения максимальной гибкости и производительности, реализация типизированных массивов в JavaScript разделена на буферы и представления. Буфер ( ArrayBuffer ) это объект, представляющий из себя блок данных; он не имеет формата и не предоставляет возможности доступа к своему содержимому. Для доступа к памяти буфера вам нужно использовать представление. Представление являет собой контекст, имеющий тип данных, начальную позицию в буфере, и количество элементов — это позволяет представить данные в виде актуального типизированного массива.

ArrayBuffer
Объект ArrayBuffer это стандартный набор бинарных данных с фиксированной длиной. Вы не можете манипулировать содержимым ArrayBuffer напрямую. Вместо этого необходимо создать типизированное представление DataView , которое будет отображать буфер в определённом формате, и даст доступ на запись и чтение его содержимого.
Типизированные представления
Название типизированного представления массива говорит само за себя. Оно представляет массив в распространённых числовых форматах, таких как Int8 , Uint32 , Float64 и так далее. Среди прочих существует специальное представление Uint8ClampedArray . Оно ограничивает значения интервалом от 0 до 255. Это полезно, например, при Обработке данных изображения в Canvas.
| Type | Value Range | Size in bytes | Web IDL type |
|---|---|---|---|
| Int8Array | -128 to 127 | 1 | byte |
| Uint8Array | 0 to 255 | 1 | octet |
| Uint8ClampedArray | 0 to 255 | 1 | octet |
| Int16Array | -32768 to 32767 | 2 | short |
| Uint16Array | 0 to 65535 | 2 | unsigned short |
| Int32Array | -2147483648 to 2147483647 | 4 | long |
| Uint32Array | 0 to 4294967295 | 4 | unsigned long |
| Float32Array | -3.4e38 to 3.4e38 | 4 | unrestricted float |
| Float64Array | -1.8e308 to 1.8e308 | 8 | unrestricted double |
| BigInt64Array | -2 63 to 2 63 — 1 | 8 | bigint |
| BigUint64Array | 0 to 2 64 — 1 | 8 | bigint |
Для получения подробных сведений смотрите Типизированные массивы JavaScript и справочную документацию для TypedArray .
- « Предыдущая статья
- Следующая статья »
Found a content problem with this page?
- Edit the page on GitHub.
- Report the content issue.
- View the source on GitHub.
This page was last modified on 7 авг. 2023 г. by MDN contributors.
Массив Numpy
Первое знакомство с библиотекой NumPy (Numerical Python) состоялось на двенадцатом занятии вводного курса. Затем мы несколько раз использовали эту библиотеку при построении моделей. Пришло время посвятить ее функционалу отдельный раздел.
Библиотека Numpy является основой для многих других библиотек в Питоне, например, Pandas, Matplotlib, scikit-learn или scikit-image. Главный объект библиотеки — массив Numpy (Numpy array). О нем мы поговорим сегодня.
На следующем занятии мы изучим математические операции над массивами, а через одно — рассмотрим работу со случайными числами.
Содержание занятия
- Понятие массива Numpy
- Как создать массив Numpy
- Функция np.array()
- Функция np.arange()
- Тип данных элементов массива
- Массив с нулевой размерностью
- Одномерный массив (вектор)
- Двумерный массив (матрица)
- Трехмерный массив
- Массив из нулей
- Массив из единиц
- Массив, заполненный заданным значением
- Пустой массив Numpy
- Функция np.linspace()
- Функции np.random.rand() и np.random.randint()
- Создание массива из функции
- Матрица csr и метод .toarray()
- Индекс элемента массива
- Срез массива
- Массив 2D
- Массив 3D
- Функция len()
- Вхождение элемента в массив
- Распаковка массива
- Изменение элементов массива
- Сортировка массива и обратный порядок его элементов
- Изменение размерности
- Объединение массивов
- Фильтр (маска) массива
- Вопросы для закрепления
Понятие массива Numpy
Массив Numpy — это многомерный массив (ndarray, n-dimensional array) данных, над которыми можно быстро и эффективно выполнять множество математических, статистических, логических и других операций.
Приведу пример массива с нулевым измерением, а также одно-, двух- и трехмерного массивов.

Теперь посмотрим как работать с этими массивами на практике.
Вначале нужно импортировать библиотеку Numpy.
# библиотеку Numpy принято сокращать как np
import numpy as npКак создать массив Numpy
Рассмотрим два варианта создания одномерного массива.
Функция np.array()
Во-первых, массив можно создать с помощью функции np.array(), которой мы передаем, например, список или кортеж элементов.
# создадим массив из списка
arr = np . array ( [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ] )
array ( [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ] )
# или кортежа
arr = np . array ( ( 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ) )
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])Функция np.arange()
Кроме того, можно воспользоваться функцией np.arange(). Эта функция, как и функция range(), с которой мы уже знакомы, создает последовательность элементов. Обязательным параметром является верхняя граница, которая не входит в последовательность.
# создадим последовательность из 10 элементов
arr = np . arange ( 10 )
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])Нижняя граница и шаг обязательными не являются.
# зададим нижнюю и верхнюю границу и шаг
arr = np . arange ( 2 , 10 , 2 )
print ( arr )
array([2, 4, 6, 8])Отличие range() от функции np.arange() заключается в том, что первая не допускает использования типа float.
# создадим список с помощью функций range() и list()
list ( range ( 2 , 5.5 , 0.5 ) )
При этом в массиве Numpy тип float вполне может использоваться.
np . arange ( 2 , 5.5 , 0.5 )
array([2. , 2.5, 3. , 3.5, 4. , 4.5, 5. ])Тип данных элементов массива
Как вы уже вероятно обратили внимание, в массивах тип данных определяется автоматически. При этом при создании массива мы можем задать этот параметр принудительно.
# создадим массив с элементами типа float
arr_f = np . array ( [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ] , float )
print ( arr_f )
# тип данных можно посмотреть через атрибут dtype
print ( arr_f . dtype )
[0. 1. 2. 3. 4. 5. 6. 7. 8. 9.]Обратите внимание, в отличие, например, от списков, чаще всего в массивах содержатся элементы только одного типа (в частности, int или float).
Свойства (атрибуты) массива
Возьмем массив, который мы создали выше.
array([2, 4, 6, 8])
Важным свойством (или как правильнее говорить атрибутом) массива является количество его измерений, ndim. В данном случае это одномерный массив или вектор.
Теперь, с помощью атрибута shape, посмотрим на количество элементов в каждом измерении.
arr . shape
Обратите внимание, даже когда массив одномерный, результат атрибута shape выводится в виде кортежа (на это указывают круглые скобки и запятая после цифры четыре).
Атрибут size показывает общее количество элементов во всех измерениях.
# пока что у нас одно измерение, в котором четыре элемента
Как уже было сказано выше, атрибут dtype показывает тип данных отдельного элемента.
# в нашем случае — это целое число длиной 64 бита
arr . dtype
dtype(‘int64’)Атрибут itemsize позволяет узнать размер в байтах (один байт состоит из 8 бит) одного элемента. В нашем случае, элемент (число) состоит из 64 бит, что составляет восемь байтов.
# 64 / 8 бит = 8 байтов
arr . itemsizeОбщий размер массива в байтах (nbytes) позволяет понять, в частности, поместится ли массив в оперативную память компьютера.
# у нас четыре элемента по восемь байтов или 32 байта
arr . nbytesТот же результат можно получить, умножив общее количество элементов на размер одного элемента в байтах.
arr . size * arr . itemsize
Измерения массива
Как уже было сказано, ndarray (массив Numpy) — это многомерный массив. Давайте еще раз взглянем на массивы с различными измерениями, добавив только что изученные атрибуты этих массивов.

Теперь подробнее поговорим про размерность. Измерения (dimensions) создаются за счёт вложения одного массива в другой с помощью квадратных скобок []. Начнем с массива с нулевой размерностью.
Массив с нулевой размерностью
Массив с нулевой размерностью — это число (скаляр) и квадратных скобок не имеет.
arr_0D = np . array ( 42 )
Посмотрим на свойства этого массива.
print ( arr_0D . ndim )
print ( arr_0D . shape )
print ( arr_0D . size )Атрибут shape показывает отсутствие размерности, а size указывает на один элемент в массиве.
Одномерный массив (вектор)
Вложив несколько массивов с нулевой размерностью в квадратные скобки, мы получим одномерный массив или вектор.
arr_1D = np . array ( [ 1 , 2 , 3 ] )
array([1, 2, 3])Снова воспользуемся атрибутами массива.
print ( arr_1D . ndim )
print ( arr_1D . shape )
print ( arr_1D . size )Двумерный массив (матрица)
Поместив во вторые квадратные скобки, например, два одномерных массива, мы получим двумерный массив или матрицу.
# с точки зрения синтаксиса — это просто вложенные списки
arr_2D = np . array ( [ [ 1 , 2 , 3 ] , [ 4 , 5 , 6 ] ] )
array([[1, 2, 3],Посмотрим на свойства.
print ( arr_2D . ndim )
print ( arr_2D . shape )
print ( arr_2D . size )Атрибут size двумерного массива более интуитивно понятен. В данном случае два элемента одного измерения умножены на три элемента второго.
Добавлю, что с точки зрения Numpy матрица с одной строкой или одним столбцом — это разные объекты. Начнем с матрицы, которая имеет три вектора по одному элементу.
column = np . array ( [ [ 1 ] , [ 2 ] , [ 3 ] ] )
# посмотрим на размерность
column . shapeТеперь наоборот, создадим матрицу с одной строкой, в которой три элемента.
row = np . array ( [ [ 1 , 2 , 3 ] ] )
array([[1, 2, 3]])
# размерность будет иной
row . shapeТрехмерный массив
Теперь создадим трехмерный массив, внутри которого будут два двумерных массива 2 х 3. Общее количество элементов будет равно двенадцати (2 х 2 х 3). Визуально это можно представить как стэк (наложение) двух матриц.

При этом, вместо того чтобы вручную прописывать все 12 значений, мы последовательно воспользуемся функцией np.arange() и методом np.reshape().
arr_3D = np . arange ( 12 ) . reshape ( 2 , 2 , 3 )
array([[[ 0, 1, 2],Функция np.arange(), как мы уже видели выше, создаст одномерный массив из 12 элементов, а метод np.reshape() распределит их по измерениям. Выведем атрибуты.
print ( arr_3D . ndim )
print ( arr_3D . shape )
print ( arr_3D . size )Обратите внимание, атрибут shape сначала выводит размерность внешнего измерения, в нем две матрицы. Далее в каждую матрицу вложены два одномерных вектора. В каждом векторе по три элемента.
Аналогичным образом создаются четырехмерные массивы, а также массивы с большим количеством измерений.
Понятие тензора
Добавлю, что в математике n-мерный массив называется тензором, а числа (скаляры), векторы и матрицы являются его частными случаями для нуля, одного и двух измерений соответственно.

Другие способы создания массива
Массив из нулей
Иногда бывает полезно создать массив, все элементы которого равны нулю. Для этого используется функция np.zeros().
# ей мы можем передать одно значение для создания одномерного массива
np . zeros ( 5 )
array([0., 0., 0., 0., 0.])
# или кортеж из чисел для указания количества нулей в каждом измерении
np . zeros ( ( 2 , 3 ) )
array([[0., 0., 0.],Массив из единиц
В тех случаях когда нужно создать массив, заполненный единицами, можно воспользоваться функцией np.ones().
# создадим трехмерный массив
np . ones ( ( 2 , 2 , 3 ) )
array([[[1., 1., 1.],Массив, заполненный заданным значением
Функция np.full() создает массив, заполненный заданным значением.
# создадим матрицу 2 х 3 и заполним ее цифрой четыре
np . full ( ( 2 , 3 ) , 4 )
array([[4, 4, 4],Пустой массив Numpy
В отличие от предыдущих инструментов, функция np.empty() возвращает массив заданной размерности, но без инициализации его значений. Другими словами, пустой массив.
# создадим пустую матрицу 3 х 2
np . empty ( ( 3 , 2 ) )
array([[4.65552661e-310, 0.00000000e+000],
[0.00000000e+000, 0.00000000e+000],
[0.00000000e+000, 0.00000000e+000]])Кроме того, любой массив Numpy можно преобразовать в описанные выше массивы с помощью функций np.zeros_like(), np.ones_like(), np.full_like() и np.empty_like(). Приведу пример для np.zeros_like().
# создадим массив 2 x 3 с числами от 1 до 6
a = np . arange ( 1 , 7 ) . reshape ( 2 , 3 )
array([[1, 2, 3],
# и превратим его в массив с нулями
np . zeros_like ( a )
array([[0, 0, 0],Примеры работы с тремя оставшимися функциями можно посмотреть в ноутбуке⧉.
Функция np.linspace()
Функция np.linspace() позволяет указать диапазон начального и конечного значений, а также количество равноудаленных точек внутри этого диапазона (включая начальное и конечное значения).
# создадим диапазон от 0 до 0,9 и
# разделим его на десять точек, включая 0 и 0,9
np . linspace ( 0 , 0.9 , 10 )
array([0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])Обратите внимание, функция np.linspace() сама определяет, где расставить точки. Нам нужно лишь указать их количество. Этим она отличается от функции np.arange(), в которой мы указываем шаг в пределах заданного диапазона.
# с функцией np.arange мы точно знаем, где будут расположены точки
np . arange ( 0 , 1 , 0.1 )
array([0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])Функцию np.linspace() удобно использовать для построения графиков функций.
# импортируем библиотеку matplotlib
import matplotlib . pyplot as plt
# зададим размер графика в дюймах
plt . figure ( figsize = ( 8 , 6 ) )
# зададим интервал, например, от -5 до 5 и сформируем на нем 5000 точек
# это будут наши координаты по оси x
x = np . linspace ( — 5 , 5 , 5000 )
# по оси y отложим квадрат этих точек
# создадим сетку
# выведем кривую и подписи на графике
plt . plot ( x , y )
plt . xlabel ( ‘x’ , fontsize = 14 )
plt . ylabel ( ‘y’ , fontsize = 14 )
# результатом будет парабола
В качестве примера выведем первые 10 точек, созданные функцией np.linspace().
array([-5. , -4.9979996, -4.9959992, -4.9939988, -4.9919984,
-4.989998 , -4.9879976, -4.9859972, -4.9839968, -4.9819964])Функции np.random.rand() и np.random.randint()
Массивы можно также создавать с помощью функций, генерирующих псевдослучайные числа. В частности, функция np.random.rand() создает массив заданной размерности, заполненный числами от 0 до 1 (единица в диапазон не входит).
np . random . rand ( 4 , 3 )
array([[0.13506003, 0.50671081, 0.48772983],
[0.93478513, 0.31008048, 0.96621122],
[0.7404316 , 0.81168816, 0.94700116],
[0.18212183, 0.92247344, 0.2120635 ]])Функция np.random.randint() формирует массив целых чисел в заданном диапазоне (верхняя граница не входит в диапазон) и с заданной размерностью.
# создадим массив размерностью 2 x 3 x 2 c числами [-3, 3)
np . random . randint ( — 3 , 3 , size = ( 2 , 3 , 2 ) )Более подробно с этими и другими похожими функциями мы познакомимся на одиннадцатом занятии.
Создание массива из функции
Помимо вышеупомянутых способов массив можно создавать с помощью собственных функций. Для того чтобы понять, как это работает, вначале давайте вспомним координаты массива Numpy.

Функция np.fromfunction() берет координаты (i, j) каждой ячейки и передает их в собственную функцию. Посмотрим, как это работает на практике.
# создадим собственную функцию, которая принимает два числа
# и возводит первое число в степень второго
def power ( i , j ) :
return i * * jТеперь применим эту функцию к каждой ячейке (координатам) массива с размерностью (3, 3).
np . fromfunction ( power , ( 3 , 3 ) )
В np.fromfunction() можно передать и lambda-функцию.
# напишем lambda-функцию, которая принимает два числа и
# проверяет равны ли они (тогда она выводит True) или нет (тогда False)
lambda i , j : i == j
array([[ True, False, False],
[False, True, False],
[False, False, True]])Матрица csr и метод .toarray()
Кроме этого в случае если данные хранятся в формате csr (сжатое хранения строкой, compressed sparse row), то мы можем преобразовать их обратно в массив Numpy с помощью метода .toarray().
# создадим матрицу с преобладанием нулевых значений
A = np . array ( [ [ 2 , 0 , 0 , 1 , 0 , 0 , 0 ] , [ 0 , 0 , 3 , 0 , 0 , 2 , 0 ] , [ 0 , 0 , 0 , 1 , 0 , 0 , 0 ] ] )
array([[2, 0, 0, 1, 0, 0, 0],
[0, 0, 3, 0, 0, 2, 0],
[0, 0, 0, 1, 0, 0, 0]])Долю нулевых значений несложно посчитать через функцию np.count_nonzero() и атрибут size.
1.0 — np . count_nonzero ( A ) / A . size
0.7619047619047619Преобразуем матрицу в формат csr.
# импортируем функцию csr_matrix()
from scipy . sparse import csr _ matrix
# и применим ее к матрице А
B = csr_matrix ( A )Вернем матрицу csr обратно в формат массива Numpy.
C = B . toarray ( )
array([[2, 0, 0, 1, 0, 0, 0],
[0, 0, 3, 0, 0, 2, 0],
[0, 0, 0, 1, 0, 0, 0]], dtype=int64)Напомню, что с форматом csr мы впервые познакомились, когда изучали рекомендательные системы. Метод .toarray() мы активно применяли на занятии по обработке естественного языка.
Индексы и срезы
Индекс элемента массива
Подобно спискам, к элементам массива можно получить доступ по их индексу. Главное отличие — необходимо учитывать наличие измерений. Вначале рассмотрим индексы массива на схеме.

Если мы хотим получить доступ к элементу массива, то необходимо вначале указать индекс внешнего измерения (оно будет первым по счету в выводе атрибута shape), а затем индекс внутреннего.
Другими словами, мы двигаемся как бы снаружи вовнутрь, перемещаясь из одного измерения в другое.
Посмотрим, как это реализовать на Питоне. Создадим двумерный массив.
a = np . array ( [ [ 1 , 2 , 3 ] , [ 4 , 5 , 6 ] ] )
array([[1, 2, 3],Посмотрим на измерения и количество элементов в каждом из них.
Выведем первый элемент первого (внешнего) измерения.
# первый элемент представляет собой вектор
array([1, 2, 3])Второй индекс позволяет обратиться, например, к первому элементу первого вектора.
Теперь выведем значение шесть.
Срез массива
В массиве Numpy доступны и срезы (slice). Срез одномерного массива очень похож на срез списка.
# создадим одномерный массив
b = np . array ( [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ] )
array([1, 2, 3, 4, 5, 6, 7, 8])Возьмем каждый второй элемент в интервале с 1-го по 6-й индекс.
b [ 1 : 6 : 2 ]
array([2, 4, 6])Посмотрим на схему.

Когда измерений больше одного, внутри квадратных скобок измерения отделяются запятой. Создадим двумерный массив.
c = np . array ( [ [ 1 , 2 , 3 , 4 ] , [ 5 , 6 , 7 , 8 ] ] )
array([[1, 2, 3, 4],Сделаем срез из первой строки (внешнее измерение) и первых двух столбцов (внутреннее измерение).
# 0 указывает на первую строку, диапазон :2 — на первые два столбца
Если нужно взять все элементы одного из измерений, достаточно поставить двоеточие без указания индекса.
# возьмем обе строки во втором столбце
С помощью среза можно вывести конкретный элемент массива.
# выведем элемент в первой строке и первом столбце
Другими словами, c [ 0 , 0 ] == c [ 0 ] [ 0 ] .
Кроме того, обратите внимание, что индекс в формате array[i, j] и координаты элементов массива, которые мы рассмотрели ранее, это одно и то же.
Допускаются срезы с отрицательным индексом.
# выведем элемент в последней строке и последнем столбце
Рассмотрим более сложный пример. Возьмем всю вторую строку [ 1 ] и каждый второй столбец [ :: 2 ] .
Теперь создадим массив с тремя измерениями.
# -1 означает, что Питон сам рассчитает количество элементов в этом измерении
d = np . arange ( 16 ) . reshape ( 4 , 2 , — 1 )Можно сказать, что наш 3D массив состоит из четырех матриц 2 x 2.
Вначале выведем значение десять. Если идти снаружи вовнутрь, получается, что это третья матрица [2], второй вектор [1] и первый элемент [0].
d [ 2 ] [ 1 ] [ 0 ]
Для срезов понадобится две запятых.
# выведем третью и четвертую матрицу [2:]
# и в них вторую строку [1] и все столбцы [:]
array([[10, 11],Если указать только один срез, мы будем работать только во внешнем измерении (с четырьмя матрицами).
# выведем первые две матрицы массива
Прежде чем завершить разговор про срезы, выведем первые строки каждой матрицы.
Оси массива
С концепцией измерения массива тесно связано понятие оси (axis, множественное число — axes). У массива столько же осей, сколько и измерений. Мы уже столкнулись с осями двух и трехмерного массивов, когда работали с изображениями.
Рассмотрим этот вопрос ещё раз.
Массив 2D
В двумерном массиве два измерения и соответственно две оси.

В документации Numpy существует такое понятие как первая и последняя ось. Применительно к двумерному массиву, ось 0 — это первая ось, а ось 1 — последняя.
Многие, в частности, математические и статистические методы в Numpy предполагают указание параметра оси. Продолжим работу с приведенным выше двумерным массивом.
arr_2D = np . array ( [ [ 1 , 2 ] , [ 3 , 4 ] ] )
Сложение вдоль первой оси (axis = 0)
Найдем сумму по столбцам (вдоль оси 0).
np . sum ( arr_2D , axis = 0 )

Сложение вдоль второй оси (axis = 1)
Теперь найдем сумму по строкам (вдоль оси 1).
np . sum ( arr_2D , axis = 1 )

Обратите внимание, хотя axis = 0 принято ассоциировать со строками двумерного массива, сложение происходит вдоль вертикальной оси или по столбцам. Параметр axis = 1, отвечающий за столбцы, наоборот предполагает сложение вдоль горизонтальной оси по строкам.
При таких операциях говорят, что мы агрегируем (aggregate) данные и сворачиваем (collapse) или сокращаем (reduce) измерения вдоль определенной оси. И действительно, в каждой из описанных выше операций двумерный массив превратился в одномерный.
Сложение вдоль обеих осей (axis = (0, 1))
Если в параметр axis передать кортеж с указанием обеих осей (0, 1), сумма будет рассчитана сначала вдоль оси 0, затем вдоль оси 1.
f-строки в Python
Начиная с версии 3.6 в Python появился новый тип строк — f-строки, которые буквально означают «formatted string». Эти строки улучшают читаемость кода, а также работают быстрее чем другие способы форматирования. F-строки задаются с помощью литерала «f» перед кавычками.
>>> "обычная строка" >>> f"f-строка"f-строки — это пятый способ (sic!) форматирования строк в Python, который очень похож на использование метода format().
Вспомним все 5 способов форматирования.
5 способов форматирования строк
1. Конкатенация. Грубый способ форматирования, в котором мы просто склеиваем несколько строк с помощью операции сложения:
>>> name = "Дмитрий" >>> age = 25 >>> print("Меня зовут " + name + ". Мне " + str(age) + " лет.") >>> Меня зовут Дмитрий. Мне 25 лет.2. %-форматирование. Самый популярный способ, который перешел в Python из языка С. Передавать значения в строку можно через списки и кортежи , а также и с помощью словаря. Во втором случае значения помещаются не по позиции, а в соответствии с именами.
>>> name = "Дмитрий" >>> age = 25 >>> print("Меня зовут %s. Мне %d лет." % (name, age)) >>> Меня зовут Дмитрий. Мне 25 лет. >>> print("Меня зовут %(name)s. Мне %(age)d лет." % ) >>> Меня зовут Дмитрий. Мне 25 лет.3. Template-строки. Этот способ появился в Python 2.4, как замена %-форматированию ( PEP 292 ), но популярным так и не стал. Поддерживает передачу значений по имени и использует $-синтаксис как в PHP.
>>> from string import Template >>> name = "Дмитрий" >>> age = 25 >>> s = Template('Меня зовут $name. Мне $age лет.') >>> print(s.substitute(name=name, age=age)) >>> Меня зовут Дмитрий. Мне 25 лет.4. Форматирование с помощью метода format(). Этот способ появился в Python 3 в качестве замены %-форматированию. Он также поддерживает передачу значений по позиции и по имени.
>>> name = "Дмитрий" >>> age = 25 >>> print("Меня зовут <>. Мне <> лет.".format(name, age) >>> Меня зовут Дмитрий. Мне 25 лет. >>> print("Меня зовут Мне лет.".format(age=age, name=name) >>> Меня зовут Дмитрий. Мне 25 лет.5. f-строки. Форматирование, которое появилось в Python 3.6 ( PEP 498 ). Этот способ похож на форматирование с помощью метода format(), но гибче, читабельней и быстрей.
>>> name = "Дмитрий" >>> age = 25 >>> print(f"Меня зовут Мне лет.") >>> Меня зовут Дмитрий. Мне 25 лет.Курс по языку Python 3
- Научитесь программировать на Python с нуля
- Более 130 уроков и 300 заданий
- Поддержка преподавателя на всех этапах
Погружение в f-строки
f-строки делают очень простую вещь — они берут значения переменных, которые есть в текущей области видимости, и подставляют их в строку. В самой строке вам лишь нужно указать имя этой переменной в фигурных скобках.
>>> name = "Дмитрий" >>> age = 25 >>> print(f"Меня зовут Мне лет.") >>> Меня зовут Дмитрий. Мне 25 лет.f-строки также поддерживают расширенное форматирование чисел:
>>> from math import pi >>> print(f"Значение числа pi: ") >>> Значение числа pi: 3.14С помощью f-строк можно форматировать дату без вызова метода strftime():
>>> from datetime import datetime as dt >>> now = dt.now() >>> print(f"Текущее время ") >>> Текущее время 24.02.2017 15:51Они поддерживают базовые арифметические операции. Да, прямо в строках:
>>> x = 10 >>> y = 5 >>> print(f" x / 2 = ") >>> 10 x 5 / 2 = 25.0Позволяют обращаться к значениям списков по индексу:
>>> planets = ["Меркурий", "Венера", "Земля", "Марс"] >>> print(f"Мы живим не планете ") >>> Мы живим не планете ЗемляА также к элементам словаря по ключу:
>>> planet = >>> print(f"Планета . Радиус км.") >>> Планета Земля. Радиус 6378.0 км.Причем вы можете использовать как строковые, так и числовые ключи. Точно так же, как в обычном Python коде:
>>> digits = >>> print(f"0 - , 1 - ") >>> 0 - ноль, 1 - одинВы можете вызывать в f-строках методы объектов:
>>> name = "Дмитрий" >>> print(f"Имя: ") >>> Имя: ДМИТИРИЙА также вызывать функции:
>>> print(f"13 / 3 =") >>> 13 / 3 = 4 f-строки очень гибкий и мощный инструмент для создания самых разнообразных шаблонов.
Со всеми возможностями f-строк вы можете ознакомиться в PEP498.
Производительность
F-строки не только гибкие, но и быстрые. И для сравнения производительности разных подходов к форматированию я подготовил два шаблона:
- простой, в который нужно вставить всего два значения: строку и число;
- сложный, данные для которого собираются из разных переменных, а внутри происходит преобразование даты, вещественного числа, а также округление.
Финальная простая строка получается такой:
Привет, меня зовут Дмитрий. Мне 27 лет.
Сложная строка на выходе такая:
Сегодня 24.02.2017.
Мы живём на планете Земля. Её радиус 6378 км., а масса 5.973e+24
Период обращения планеты вокруг Солнца 365 дней.Далее я написал 5 функций, каждая из которых возвращает строку отформатированную одним из способом, а после запустил каждую функцию много раз. Пример всех функций и тестового скрипта можете скачать тут.
После недолгого тестирования я получил следующие результаты:

На простых примерах f-строки показывают наилучшие результаты.
На 25% быстрее %-форматирования и метода format().
На сложных шаблонах f-строки ведут себя так же как %-форматирование
(разница в пользу %-форматирования не превышает величину погрешности).
А вот относительно метода format() f-строки быстрее на 27%.Заключение
Если вы используете Python 3.6 и старше, то самое время использовать f-строки — они гибкие и быстрые.
