Введение в машинное обучение.
В дополнение к первой заметке рассматривются такие понятия как собственные функции, классы и иные библиотек относящихся к анализу данных.
Это предварительная версия! Любые замечания приветсвуются.
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as models
Напомню:
import csv
data = []
with open('MTLR_180101_190110.txt') as f:
data_rows = csv.reader( f, delimiter=';' )
for row in data_rows:
for i in range(2, len(row)):
row[i] = float( row[i] )
data.append( row )
close = [ day[-2] for day in data ] # -2 это цена закрытия.
plt.plot( close )
plt.ylabel( 'Цена рубли')
plt.xlabel( 'День начиная с 2018 г')
Как выполнить данное считывания и для других эмитентов, т.е. для других файлов? Можно создать функцию, которая обособит код.
Функции
def mysum( a, b): # Теперь у функции два аргумента
return a + b * 2; # Возвращаем значение выражения.
mysum( 3, 2) # 3 + 2 * 2
mysum( b = 3, a = 2) # 2 + 3 * 2
mysum( 3, a = 2) # При таком вызове система запутается. Точнее будет повторное присвоение первому аргументу.
mysum( b = 3, 2) # А так нельзя потомучто после присвоения переменной значения по имени позиции не учитываются.
mysum( 5 )
Упр. Напиши функцию вычисляющую корень квадратного уравнения. Например, а) больший корень. б) оба корня ввиде набора.
# Можно сделать значения по умолчанию
def mysum2( a, b = 5):
return a + b * 2;
mysum2( 3 ) # 3 + 5 * 2
mysum2( 3, 2) # 3 + 2 * 2
# После переменных с значением по умолчанию обычные переменные не могут следовать
def mysum3( a, b = 5, c):
return a + b + c
Упр. Напиши функцию вычисляющую логарифм. По умолчанию основание пусть будет натуральным. Иначе, оно должно быть указано.
# Тело функции ествественно может быть сложным
def doPow( a, c ): # Вычисляем возведение в степень. a возводится в степен c.
d = 1
for i in range(c):
d = d * a
return d
doPow( 2, 3)
doPow( 3, 4)
Упр. Напиши функцию вычисляющую среднее и среднеквадратичное отклонение массива. Написать нужно через цикл самостоятельно, а не черз фкнции из numpy.
# Функция может иметь несколько точек воврата
def myAbs( a ):
if a < 0:
return -a # else опустили для краткости.
return a
myAbs( -11 )
doPow( 3, -5) # Для отрицательной степени не сработали.
Упр. Напиши функцию которая возвращает знак числа, т.е. -1 для отрицательных, 1 для положительных и 0 для 0.
# Можем вызвать сами себя:
def doPow( a, c ):
if c < 0: #Учитываем отрицательость степени
return doPow( 1/a, -c )
d = 1
for i in range(c):
d = d * a
return d
doPow( 3, -5)
(1/doPow( 3, -5))/3/3/3/3/3
# Можем и более сложные алгортмы делать. Например вычисление факториала.
def fact( n ):
if n <= 1:
return 1
return n * fact( n - 1 )
fact( 3 )
Упр. Напиши фукнцию вычисляющую наибольший общий делитель. Рекурсивным способом: через вычитания или остаток.
Обратно к эмитентам
def txt2data( name ): # Функция принимает на вход название файла.
data = []
with open( name ) as f:
data_rows = csv.reader( f, delimiter=';' )
for row in data_rows:
for i in range(2, len(row)):
row[i] = float( row[i] )
data.append( row )
return data
mechel = txt2data( 'MTLR_180101_190110.txt' )
mtl_cl = np.array( [ day[-2] for day in mechel ] ) # -2 это цена закрытия.
vtb = txt2data( 'VTBR_180101_190110.txt' )
vtb_cl = np.array( [ day[-2] for day in vtb ] )
plt.plot( mtl_cl )
plt.plot( vtb_cl )
plt.ylabel( 'Цена рубли')
plt.xlabel( 'День начиная с 2018 г')
plt.plot( mtl_cl/mtl_cl[0] )
plt.plot( vtb_cl/vtb_cl[0] )
plt.ylabel( 'Процентое изменение')
plt.xlabel( 'День начиная с 2018 г')
plt.legend( ["Мечел", "ВТБ"] )
gaz = txt2data( 'GAZP_180101_190110.txt' )
gaz_cl = np.array( [ day[-2] for day in gaz ] )
Как во всех этих элементах не запутаться? Есть такая вещь как словарь.
country = dict()
country['Россия'] = 'Москва'
country['Франция'] = 'Париж'
country['Италия'] = 'Рим'
country['Франция']
country['Германия']
по аналогии с этим...
ticket = dict()
ticket['MTLR'] = mtl_cl
ticket['VTBR'] = vtb_cl
ticket['GAZP'] = gaz_cl
ticket.keys() # Можно узнать какие ключи есть.
lab = []
for k, t in ticket.items():#Итерация tuple ами.
plt.plot( t/t[0] )
lab.append( k )
plt.ylabel( 'Процентое изменение')
plt.xlabel( 'День начиная с 2018 г')
plt.legend( lab )
Упражнение. Как сделать так чтобы подписи в легенде были не сокращенные названия, а полноценные имена (как в предыдущем графике).
Сложный ключ
Наборы могут выступать в качестве ключа/индекса у словаря.
works = dict()
....
#plt.bar( [1,3,5],[10,5,8])
import pandas as pd
# import seaborn
%config InlineBackend.figure_format = 'svg'
flat_df = pd.read_csv('berkeley_case.csv', sep = ';') # Считываем данные из файла.
flat_df.values
flat_df # Выводим считанную таблицу. Она выглядит достаточно опрятно и эффектно.
flat_df.columns # Выводим название колонок.
# Переименовываем на русский лад.
flat_df.columns = ['Факультет', 'Пол', 'Параметр', 'Количество']
flat_df
# Выполним быструю агрегацию по полу.
total_stats = pd.pivot_table(flat_df, aggfunc = sum, index = 'Пол', columns = 'Параметр', values = 'Количество')
total_stats
#total_stats[:]['men']
total_stats.accepted/total_stats.applied # В процентах.
total_stats['Процент поступ'] = total_stats.accepted/total_stats.applied
total_stats
100*total_stats.accepted/total_stats.applied
#total_stats['perc_admitted'] = [round_2digits( it ) for it in 100*total_stats.accepted/total_stats.applied ]
total_stats['Процент поступ'] = [ round( it, 2) for it in 100*total_stats.accepted/total_stats.applied ]
total_stats
df = pd.pivot_table(flat_df, index = 'Факультет', values = 'Количество', columns = ['Пол', 'Параметр'])
df
#df['A']
df['women']
#df['applied']
df['women', 'applied']
df[:,'accepted'] # так нельзя
idx = pd.IndexSlice
idx[:, 'accepted']
#df[idx[:, 'accepted']]
idx[:]
df.loc[idx[:]] # Никаких изменений.
#df
#df_AA=df.reorder_levels(['Пол', 'Параметр'])
#df_AA
df_A=df.loc[idx['A']]
df_A
df_A[ idx['women'] ]
df_A[ idx[:, 'accepted'] ]
#df.loc[idx[:], idx[:, 'accepted']]
df.loc[idx['A'], idx[:, 'accepted']]
df['men']
df_total = df['men'] + df['women']
df_total
df_totalT = df_total.T # Транпонируем таблицу.
df_totalT
df_totalT['пол'] = 'всего'
df_totalT
df_totalT.set_index('пол', append = True, inplace = True)
df_totalT
df_totalT = df_totalT.reorder_levels(['пол', 'Параметр'])
df_totalT
df_total = df_totalT.T
df_total
df = pd.concat([df, df_total], axis = 1)
df
df_inv = df.reorder_levels(['Параметр', 'Пол'] )
df_inv = df.reorder_levels(['Параметр', 'Пол'], axis = 1)
df_inv
df_inv = df_inv.sort_index(level = 0, axis = 1)
df_inv
100*df_inv.accepted/df_inv.applied # Вычисляем итоговые проценты на факультетах в зависимости от пола.
# Итоговые проценту получили, но их нужно округлить. Как раньше не получится. Объект сложный. Итерация не годится.
# Можно ввести округление.
# Для этого понядобятся функции
def round_2digits( x ): # Данная функция от одного аргумента. Как синус, квадратный корень и тому подобное.
return round(x, 2) # Вызываем функцию из самого Python, число 2 указывает на то что округляем две цифры после запятой.
round_2digits( 2.123456 )
round_2digits( 2.1 )
round_2digits( 2.12567 ) # Это именно округление, а не отрезание чисел после второго разряда после запятой.
admitted_perc = 100*df_inv.accepted/df_inv.applied
admitted_perc = round( admitted_perc, 2)#round_2digits( admitted_perc )
admitted_perc
admitted_perc[['всего', 'men', 'women']].plot(kind = 'bar', title = 'Процент посупивших в Беркли')
df_applied = flat_df[ flat_df.Параметр == 'applied' ]
df_applied
gndr_fclt_appl = pd.pivot_table( df_applied, index = 'Факультет', values = 'Количество', columns = 'Пол')
gndr_fclt_appl
gndr_fclt_appl.sum()
gndr_fclt_appl = 100 * gndr_fclt_appl / gndr_fclt_appl.sum()
gndr_fclt_appl
gndr_fclt_appl = round_2digits( gndr_fclt_appl )
gndr_fclt_appl
faculty_stats = admitted_perc[['всего']].join( gndr_fclt_appl )
faculty_stats
faculty_stats.columns = ['Процент посупивших', 'доля мужчин', 'доля женщин']
faculty_stats.plot(kind = 'bar', title = 'Статистика факультетов Беркли')