{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Программирование для всех (основы работы с Python)\n", "\n", "*Алла Тамбовцева*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Кортежи (tuples)\n", "\n", "Кортежи встречаются не только в программировании, но и в математике. В математике под кортежем обычно понимают упорядоченную совокупность элементов, то есть совокупность, порядок элементов которой фиксирован. В кортеже мы точно знаем, какой элемент является первым, какой – вторым, и так далее.\n", "\n", "Внешне кортежи несильно отличаются от списков. Единственное внешнее отличие – элементы кортежа заключаются в круглые, а не в квадратные скобки." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "t = (4, 0, 2) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "К элементам кортежа можно обращаться точно так же, как к элементам списка:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t[0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Но, несмотря на кажущееся сходство, кортежи и списки – принципиально разные объекты. Главное отличие кортежей от списков заключается в том, что кортежи – неизменяемые объекты. Другими словами, изменять элементы кортежа нельзя. Проверим:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "'tuple' object does not support item assignment", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mt\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m6\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: 'tuple' object does not support item assignment" ] } ], "source": [ "t[0] = 6" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Иногда это свойство бывает полезным (некоторая «защита» от изменений), иногда – не очень, но для нас пока важно познакомиться с разными объектами в Python, чтобы потом не удивляться. Ведь многие более продвинутые функции могут возвращать результат или, наоборот, принимать на вход только кортежи или только списки.\n", "\n", "При желании кортеж можно превратить в список:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[4, 0, 2]" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "list(t)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "И наоборот:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "L = [5, 8, 1, -2] " ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(5, 8, 1, -2)" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tuple(L)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Если посмотреть на методы, применяемые к кортежам (например, набрать `t.` и нажать *Tab*), то можно заметить, что методов для кортежей сильно меньше по сравнению с методами для списков. Во многом это связано с тем, что кортеж нельзя изменить. Но вот «склеивать» кортежи, создавая при этом новый, легко:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1, 3, 7, 8)" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(1, 3) + (7, 8)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Массивы NumPy" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Сегодня мы начнём знакомство с библиотекой NumPy (сокращение от *Numeric Python*), которая часто используется в задачах, связанных с анализом данных и машинным обучением. \n", "\n", "Чтобы мы смогли на конкретных примерах увидеть, зачем эта библиотека используется, давайте ее импортируем. Если вы уже устанавливали Anaconda, то библиотека NumPy также была установлена на ваш компьютер. Проверим: импортируем библиотеку с сокращённым названием, так часто делают, чтобы не «таскать» за собой в коде длинное название. Сокращение `np` для библиотеки `numpy` – общепринятое, его часто можно увидеть в документации или официальных тьюториалах." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "import numpy as np" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Основным объектом NumPy является *Ndarray* – это n-мерный массив (от *n-dimensional array*), структура данных, которая позволяет хранить набор элементов одного типа: либо целые числа, либо числа с плавающей точкой, либо строки, либо логические значения True и False. Мы пока рассмотрим одномерные массивы, которые внешне несильно отличаются от списков.\n", "\n", "Зачем вообще нужны массивы, почему обычных списков недостаточно? Списки не позволяют выполнять операции поэлементно эффективным образом – без использования циклов и подобных конструкций. Допустим, у нас есть список чисел `L`:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "L = [5, 8, 1 , -2] " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Если мы захотим получить новый список, состоящий из квадратов элементов списка `L`, нам придётся обращаться к циклу, применение операции ко всему списку вызовет ошибку:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "unsupported operand type(s) for ** or pow(): 'list' and 'int'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mL\u001b[0m \u001b[0;34m**\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: unsupported operand type(s) for ** or pow(): 'list' and 'int'" ] } ], "source": [ "L ** 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Такая особенность списков вполне логично вытекает из их структуры, которая подразумевает то, что внутри могут быть элементы разного типа. А раз так, то какой смысл позволять выполнять операции, которые имеют смысл только для одного типа данных?\n", "\n", "С массивами такой проблемы не возникает. Если в массиве хранятся числа, мы можем свободно применить какую-нибудь операцию, работающую на числах, к каждому элементу массива. Попробуем это сделать. Создадим массив `A`:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ 4 6 7 -1 0]\n" ] } ], "source": [ "A = np.array([4, 6, 7, -1, 0]) \n", "print(A)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Возведём каждый элемент массива в квадрат:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([16, 36, 49, 1, 0])" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A ** 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Получилось! Цикла не понадобилось, всё выглядит очень компактно, работает быстро!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Что удобно, похожим образом можно выполнять действия сразу с несколькими массивами одинаковой длины. Например, мы можем поэлементно сложить два массива: " ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ 9 14 8 1 10]\n" ] } ], "source": [ "A = np.array([4, 6, 7, -1, 0]) \n", "B = np.array([5, 8, 1, 2, 10]) \n", "C = A + B\n", "print(C)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Или вычесть:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ -1, -2, 6, -3, -10])" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A - B" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Или произвести сразу несколько действий:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ -11.11111111, -14.28571429, 75. , -300. ,\n", " -100. ])" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(A - B) / C * 100" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Так как в массиве элементы должны быть одного типа, целые числа в примере выше записались в дробном виде с нулевой дробной часть (например, `75.` вместо `75`).\n", "\n", "На этом закончим наше беглое знакомство с массивами, мы вернёмся к ним, когда будем обсуждать работу с реальными данными в табличном виде (Python будет обращаться со столбцами таблицы как с массивами с дополнительными свойствами)." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.4" } }, "nbformat": 4, "nbformat_minor": 2 }