Введение в Python, настройка среды программирования

Шестаков А.В. Майнор по анализу данных - 12/01/2016

Этот IPython Notebook содержит вспомогательные указания для выполнения семинарских и домашних заданий. В течение курса мы будем преимущественно работать в подобных "тетрадках", но может быть иногда будем переключаться на другие среды\средства.

(Мы используем Python версии 2.x.x, а не 3.x.x)

Как установить IPython Notebook у себя дома?!

Самый простой и надежный способ - воспользоваться готовым дистрибутивом Anaconda, включающий в себе практически все необходимые модули и утилиты, которые нам понадобятся - IPython, NumPy, SciPy, Matplotlib и Scikit-Learn. Просто следуйте указаниям установщика для вашей ОС.

Быстрое введение в Python

Калькулятор

In [ ]:
2*7
In [ ]:
6+4**2-1
In [ ]:
4^4
# О боже, госпади, что это было? 

Знак "#" символизирует начало комментариев в коде - всё что идет после этого знака до конца строки игнорируется Питоном.

Поехали дальше - что у нас с делением?

In [ ]:
16/4
In [ ]:
25/7
# Угадайте, что получится?

Для питона, в результате целочисленного деления должно тоже получится целое число. Т.е. остаток отбрасывается. Как же намекнуть питону, что мы хотим получить точный ответ?

In [ ]:
25./7
25/7.
float(25)/7

Ну окей, пока всё это можно было посчитать в столбик.

Есть что посерьезнее? КАААНЕЧНО!

In [ ]:
sqrt(4)

... Но не так сразу. Питон начал ругаться. По-умолчанию, он не знает, что такое извлечение квадратного корня. Однако можно показать ему, где искать.

В стандартном модуле math есть такая функция. Давайте импортируем её в нашу программу

In [ ]:
import math
math.sqrt(4)

А чтобы каждый раз не писать math. перед вызовом конкретных фукнций можно поступить так:

In [ ]:
from math import sin
sin(3.14)

Ну хорошо, что мы всё приближенно, давайте точно посчитаем, чему равено $sin(\pi)$. В модуле math можно найти это самое $\pi$

In [ ]:
from math import pi
sin(pi)

Возникают вопросы:

  • ЭТО ВООБЩЕ ЧИСЛО?
  • почему так получилось?

Переменные

В Python не надо как-то спецально объявлять переменную. Присвоил значение и поехали!

In [ ]:
x = 4
x
In [ ]:
# Инкрементация
x = x + 2
x+=2 # тоже самое
x
In [ ]:
# Логические операции
In [ ]:
x != 7
In [ ]:
x > 7
In [ ]:
x < 10

Задание

Числа Фибоначчи или последовательность Фибоначчи — последовательность чисел, начинающаяся с двух единиц, и такая, что очередное число в этой последовательности равно сумме двух предыдущих. Формально можно определить её следующим образом:

$a_1=1$;

$a_2=1$;

$a_{n+1}=a_n+a_{n-1}$ для всех $n>2$.

Например, $a_3=1+1=2$, $a_4=2+1=3$.

Задача: посчитать 15-е число Фибоначчи

In [ ]:
a = 1 # первое число
b = 1 # второе число
i = 2 # номер того числа, которое находится в переменной b (сейчас это a_2)
In [ ]:
c = a + b #нашли следующее число
i = i + 1 #увеличили i на 1
a = b
b = c
# или можно сделать в одну строчку
# a,b = b,c

print i, b 
# команда print выводит на экран значение переменных 
# и всякие другие штуки

Питон выполняет команды последовательно, строчку за строчкой, поэтому порядок следоавния команд очень важен. Выполняя эту ячейку несколько раз, вы будете получать каждый раз очередное число Фибоначчи.

Типы данных

До сих пор мы имели дело только с числами, но уже поняли, что вещественные числа отличаются от целых. Вообще в Python есть много разных типов данных, предназначенных для хранения информации разной природы. Каждый тип данных имеет название в Python, например, целые числа — это int, вещественные (числа с плавающей запятой или правильнее сказать плавающей точкой) — float.

Строки

Строки выглядят так:

In [ ]:
print 'Hello, World!'

Вот эта штука в кавычках — это и есть строка (тип данных str). Строки тоже можно сохранять в переменных и делать с ними разные операции (но совсем не такие, как с числами).

In [ ]:
type('Blah-Blah')
In [ ]:
a = "Hello"
b = "World"
print a + b
In [ ]:
# Форматирование строк

x = 123
# Хочу:
# x is equal to 123
print 'x is equal to %i' % x

Здесь символ процента означает, что нужно взять переменную, которая написана справа, и подставить в строчку, написанную слева, вместо символов %i. Буква i здесь означает integer, то есть что ожидается целое число.

In [ ]:
'ABC' == 'abc'
In [ ]:
'ABC' < 'DEF'

Списки

До сих пор мы работали с числовыми переменными — в каждой переменной лежало одно число. На практике нам зачастую приходится работать с большими массивами данных. Чтобы их хранить, нужно познакомиться со списками. Список — это такая переменная, которая содержит в себе сразу много элементов.

In [ ]:
x = [2, 5, 1, 2, 3, 2, 4, 6]
# вот эта штука в квадратных скобках — это и есть список

Можно обращаться к отдельным элементам списка и работать с ними как с обычными переменными. Чтобы выбрать элемент, нужно указать его номер.

Нумерация начинается с нуля! По старой программистская традиции, чтобы запутать непосвященных.

In [ ]:
x[0]
In [ ]:
x[1] = 10
x

Список можно расширять!

In [ ]:
x.append(2)
x
In [ ]:
type(x)

Слово append — это метод класса list. У x, как у любого списка, есть много методов. Можно набрать x., нажать табуляцию, и получить список доступных методов. Например:

In [ ]:
x.count(2) # считаем количество "2"
In [ ]:
x.reverse()
# пустые скобки означают, что мы вызываем функцию, 
# но параметров ей не передаем
x
In [ ]:
# Cписок можно попробовать отсортировать
x.sort(reverse=True)
print x

Слайсы

Иногда нам нужен не весь список, а его кусочек.

In [ ]:
print x
print x[2:5]
print x[2:]
print x[:5]

Присвоение и копирование списков

Списки могут быть коварными.

In [ ]:
y = x
y[0] = 15
# Что же лежит в первом элементе списка x?
# 10 ил 15?
x

ШТАА?! Когда мы изменили список y, то изменился и список x! Почему так произошло? Дело в том, что списки живут в своём собственном мире платоновских идей.

Когда мы присваиваем список переменной, то есть пишем что-нибудь вроде x = [1, 2, 3]

мы говорим, что теперь переменная x будет указывать на этот список. Можно сказать, что мы создали список и дали ему имя x. После этого в x хранится не сам список, а указатель (ссылка) на него. Когда мы присваиваем значение x новой переменной y, мы не производим копирование списка, мы копируем только указатель. То есть y просто стала другим именем для того же самого списка, что и y. Поэтому изменение элементов x приведет к изменению y, и наоборот.

Если мы хотим создать новый список, скопировав существующий, нужно использовать вот такой синтаксис:

In [ ]:
y = x[:]
y[1] = 10
print x
print y

Преобразование типов

In [ ]:
a = 10.8
b = int(a)
print b
In [ ]:
a = '213'
x = a + a
print int(x)

Картинки

Немного картинок, чтобы было повеселее. Для рисования графиков в основном используют модуль matplotlib. Однако, он далеко не единственный, и кроме того, далеко не самый "изящный". Посмотрите, например, seaborn!

In [ ]:
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
In [ ]:
plt.plot([1,2,3,4],[4,2,3,1])
In [ ]:
plt.bar([1,2,3,4,6],[1,2,3,4,10])
In [ ]:
x = np.arange(-10, 10, 0.5)
y = x**2
plt.plot(x, y)

В "сыром" виде выглядит не так чтобы очень. Но всегда можно заморочиться. И себе приятно, и семенаристу (который будет смотреть твои домашнки)!

In [ ]:
# Особый стриль графиков
plt.style.use('ggplot')

# Это надо, чтобы писать русскими буквами
font = {'family': 'Verdana',
        'weight': 'normal'}
plt.rc('font', **font)
In [ ]:
x = np.arange(0, 6*np.pi, 0.3)
y = np.sin(x)
z = np.cos(x)

plt.figure(figsize=(8, 6))
plt.plot(x, y)
plt.plot(x, z, 'b')
plt.xlabel('x')
plt.title(u'Тригонометрия!')
plt.legend(['sin', 'cos'])

Веселье закончилось. Идем дальше.

Условные операторы

Часто в программе возникают "развилки" - когда в зависимости от выполнения какого-то условия, программа должна пойти по тому или иному пути.

В Python, как и во многих языках программирования, такие развилки задаются словом if:

In [ ]:
x = 3
if x == 2:
    print 'Okay'
    print 'This is good number'
else:
    print 'Oh, noooo!'
    if x > 2:
        print 'x is greater than 2'
    else:
        print 'x is lesser than 2'

Можно задавать несколько условий, объединяя их логическими операторами И,ИЛИ НЕ

In [ ]:
x = 1.5
if x > 2 and x < 3:
    print 'Okay'
In [ ]:
if x < 2 or x < 3:
    print 'Okay'
In [ ]:
if 1 < x < 5:
    print 'Ok'

Цикл for

Часто нужно сделать какое-то действие со всеми элементами списка. Для этого есть цикл for.

In [ ]:
x = [1, 4, 9, 1]
i = 1234
for i in x:
    print i
    print "One more"
#     print i + 1
print "And finally"
print i

break и continue

Говоря о циклах, нужно упомянуть два специальных способа прекратить обработку очередного элемента. Ключевое слово continue означает, что нужно вернуться в начало цикла и взять следующй элемент.

In [ ]:
for i in xrange(1, 10):
    if i**2>10:
        print 'Next'
        continue
    else:
        print i
    print 'Ok'
In [ ]:
for i in xrange(1,10):
    if i**2>50:
        print "Stop"
        break
    else:
        print i
    print "Okay"
print "Stopped"

Цикл while

Иногда нужно выполнять какие-то команды до тех пор, пока что-то не произойдёт. Например, мы выводим на экран числа Фибоначчи, но только те из них, которые меньше 1000. Это делается с помощью цикла while.

In [ ]:
a = 1
b = 1
while b < 1000:
    c = a + b
    a = b
    b = c
    print a

Если условие не выполняется до входа в цикл, то тело цикла не выполнится ни разу. Если вы хотите цикл с постусловием (то есть условием, проверяющимся в конце), то мне придётся вас расстроить: в Python его нет. Есть только вот такая конструкция, его заменяющая.

In [ ]:
x=10
while True:
    print "Hello"
    x=x+2
    if not (x<5):
        break

Простые задачки

Задача 1. Ввести числа a, d и N. Найти сумму первых N членов арифметической прогрессии с первым членом a и разностью d, не пользуясь «школьной» формулой.

Задача 2. Ввести число N с клавиатуры. Найти сумму первых N членов гармонического ряда.

Задача 3. Ввести натуральное число N с клавиатуры. Проверить, является ли оно простым.

Задача 4. Вывести N первых простых чисел.

Задача 5. Даны три числа: a, b, c. Не пользуясь функциями min, max и какими-либо библиотечными функциями, вывести на экран максимальное из них.

Продолжаем любить Питон

Пользовательские функции. Примочки функциональных языков

In [ ]:
func = lambda x: x**2
In [ ]:
# Это тоже самое, что и сверху
def func(x):
    return x**2
In [ ]:
func(4)
In [ ]:
l = range(10)
l2 = map(func, l)
l2
In [ ]:
reduce(lambda x, y: x+y, l)
In [ ]:
filter(lambda x: x>=5, l)
In [ ]:
string = 'lala. alala, dada'
no_punct = filter(lambda x: x not in ['.', ','], string)
no_punct

Работа с файлами

В общем случае, работа с файлами осуществляется через команду open. Давайте попробуем создать файл с каким-то текстом:

In [ ]:
fout = open('temp.txt', 'w')
In [ ]:
string = 'this is very interesting text\n'
fout.write(string)
fout.close()

Попробуем записать несколько строк:

In [ ]:
string_arr = ['Indeed, this text is very interesting,\n', 
              'You should read it again', 
              ' and again']
with open('temp.txt', 'w') as fout:
    fout.writelines(string_arr)

Теперь, загрузим содержание файла:

In [ ]:
with open('temp.txt', 'r') as fin:
    data = fin.readlines()
data = map(lambda (x): x.strip(), data)

Как правило, в зависимости от области применимости модуля Python, в нем есть свои функции загрузки из различных форматов файлов в нужный тип данных. В следующий раз мы поработаем с прекрасным модулем Pandas, созданный для работы с таблицами всевозможных сортов. А сейчас - посмотрим что есть в NumPy.

Загрузите файл 1 и файл 2 в папку с тетрадкой. С помощью функции loadtxt в модуле NumPy загрузите табличные данные одного из файлов. Присвойте y = D[:,0] а X = D[:, 1:].

Оцените коэффициенты линейной регрессии $\hat{y} = X\hat{\beta}$, где

$$ \hat{\beta} = (X^T X)^{-1} X^T y $$

Остатки модели рассчитываются как $$ \text{res} = y - \hat{y} $$

Итак, еще раз:

1. Загрузите данные
2. Обучите модель
3. Постройте два графика: 
    3.1. Выберите какой-нибудь признак (кроме x0) и на одном графике изобразите зависимость y~x и линию регрессии
    3.2. Постройте график остатки~y
In [ ]:
# Write your code here
#
#
#

# load data
D = np.loadtxt('tutorial_dataset.csv', 
               skiprows=1, 
               delimiter=',')