Python для сбора и анализа данных

Курс повышения квалификации

И. В. Щуров, НИУ ВШЭ

Домашнее задание №3

За разные задачи можно получить разное число баллов. Если не указано обратное, задача весит 1 балл. Максимум за ДЗ можно набрать 17 баллов. Вы можете решить больше задач, чем требуется, чтобы потренироваться.

Для предварительной проверки задания нужно сделать следующее:

  1. Скачать данный ipynb-файл на свой компьютер, открыть его в IPython Notebook/Jupyter.
  2. Активировать тесты (см. ниже).
  3. Запустить ячейку, в которую вы вставили код с решением.
  4. Запустить следующую ячейку (в ней содержится тест). Если запуск ячейки с тестом не приводит к появлению ошибки (assertion), значит, всё в порядке, задача решена. Если приводит к появлению ошибки, значит, тест не пройден и нужно искать ошибку.

Внимание! Если в какой-то момент забыть ввести входные данные и перейти на следующую ячейку, есть риск, что Notebook перестанет откликаться. В этом случае надо перезапустить ядро: Kernel → Restart. При этом потеряются все значения переменных, но сам код останется.

Чтобы сдать ДЗ, его надо загрузить в nbgr-x в виде ipynb-файла. Получить ipynb-файл можно, выбрав в Jupyter пункт меню File → Download as... → IPython Notebook (.ipynb).

Активировать тесты

Запустите следующие ячейку, чтобы иметь возможность запускать тесты. Эту операцию нужно проделывать каждый раз, когда вы перезапускаете ядро. Если какой-то из тестов говорит NameError: name 'Tester' is not defined, нужно запустить эту ячейку ещё раз.

In [ ]:
# Фабрика тестов для проверки программ, принимающих данные через input()

from collections import deque

class Tester(object):
    def __init__(self, inp):
        self.outputs = []
        self.inputs = deque(inp)
    def print(self, *args, sep = " ", end = "\n"):
        text = sep.join(map(str, args)) + end
        newlines = text.splitlines(keepends=True)
        if self.outputs and self.outputs[-1] and self.outputs[-1][-1] != "\n" and newlines:
            self.outputs[-1] += newlines[0]
            self.outputs.extend(newlines[1:])
        else:
            self.outputs.extend(newlines)

    def input(self, *args):
        assert self.inputs, "Вы пытаетесь считать больше элементов, чем предусмотрено условием"
        return self.inputs.popleft()
    def __enter__(self):
        global print
        global input
        print = self.print
        input = self.input
        return self.outputs
    def __exit__(self, *args):
        global print
        global input
        del print
        del input

Задача 1 (1 балл).

Написать функцию times2(x), принимающую на вход число x и возвращающую это число, увеличенное в два раза.

Подсказка. Решение должно начинаться со строчки

def times2(x):

Подсказка. В этом ДЗ вам не придётся вводить данные с клавиатуры. Вместо этого вы будете передавать входные данные функции в виде аргументов. Если в условии сказано, что функция должна вернуть какое-то значение — это означает, что она должна его вернуть (return), а не напечатать.

In [ ]:
# YOUR CODE HERE
In [ ]:
assert(times2(1) == 2)
assert(times2(2) == 4)
assert(times2(-2) == -4)
assert(times2(0) == 0)
assert(times2(100) == 200)
with Tester([]) as t:
    times2(4)
    assert len(t) == 0, "функция ничего не должна печатать"

print("Окей! :)")

Задача 2 (1 балл).

Написать функцию is_odd(n), проверяющую, является ли данное число n нечётным. Она должна возвращать True, если число нечётное, и False, если чётное. Функция не должна ничего выводить на экран!

In [ ]:
# YOUR CODE HERE
In [ ]:
assert(is_odd(1))
assert(not is_odd(2))
assert(not is_odd(0))
assert(is_odd(101))
with Tester([]) as t:
    is_odd(1)
    assert len(t) == 0, "функция ничего не должна печатать"
print("Отлично! Едем дальше.")

Задача 3 (1 балл).

Написать функцию hello(n), выводящую на экран строчку Hello n раз подряд и ничего не возвращающую. Например, вызов hello(3) должен привести к выводу на экран

Hello
Hello
Hello
In [ ]:
# YOUR CODE HERE
In [ ]:
for n in range(100):
    with Tester([]) as t:
        x = hello(n)
        assert x is None, "функция ничего не должна возвращать"
        assert len(t) == n, "функция должна выводить ровно n строк"
        assert "".join(t).strip() == ("Hello\n" * n).strip(), "функция вывела что-то не то"

Задача 4 (2 балла)

Написать функцию num_div(n), вычисляющую, сколько у данного числа n делителей (включая 1 и само это число). Функция должна работать с целыми положительными числами.

In [ ]:
# YOUR CODE HERE
In [ ]:
assert(num_div(1) == 1)
assert(num_div(2) == 2)
assert(num_div(3) == 2)
assert(num_div(100) == 9)
assert(num_div(1000) == 16)
assert(num_div(139) == 2)
assert(num_div(1289237) == 2)
print("Похоже на правду!")

Задача 5 (1 балл).

Написать функцию is_prime(n), проверяющую, является ли данное число n простым. Она должна вернуть True, если является, и False, если не является.

Примечание. Можете использовать ранее написанную функцию num_div(n). (Вопрос: Является ли это самым эффективным способом решения данной задачи?)

In [ ]:
# YOUR CODE HERE
In [ ]:
assert(is_prime(2) and 
       is_prime(3) and 
       is_prime(139) and 
       is_prime(617) and 
       is_prime(293) and 
       not is_prime(12) and 
       not is_prime(13*7))
print("Отлично! Давайте сделаем что-нибудь посложнее.")

Задача 6 (2 балла).

Написать функцию med3(x,y,z), возвращающую медиану из чисел x, y, z (то есть то из этих чисел, которое будет стоять посередине, если их упорядочить). Пользоваться какими-либо библиотечными функциями нельзя! Сортировкой тоже пользоваться нельзя.

In [ ]:
# YOUR CODE HERE
In [ ]:
from itertools import permutations
def test_med3(x,y,z,m):
    for t in permutations([x,y,z]):
        assert(med3(*t) == m)
test_med3(1,1,1,1)
test_med3(1,1,2,1)
test_med3(1,2,2,2)
test_med3(1,2,3,2)
test_med3(0,1,2,1)
test_med3(100,200,300,200)
test_med3(100,101,1000,101)
print("Ура! Получилось!")

Задача 7 (2 балла)

Написать функцию is_increasing(lst, strict), проверяющую, является ли список lst возрастающим. Если параметр strict установлен в True, нужно проверять строгое возрастание, иначе нестрогое. Иными словами, функция должна возвращать True, если каждый элемент списка не меньше (если strict установлен в False) или строго больше (если strict установлен в True) предыдущего, и False в противном случае. Если strict не указан, функция должна считать, что strict установлен в True.

Это важная задача. Сделайте её!

In [ ]:
# YOUR CODE HERE
In [ ]:
assert is_increasing([1, 2, 3, 4, 5]) == True
assert is_increasing([1, 10, 15, 16, 17]) == True
assert is_increasing([5]) == True
assert is_increasing([5, 5]) == False
assert is_increasing([5, 6, 7, 7]) == False
assert is_increasing([5, 6, 7, 8, 7]) == False
assert is_increasing([2, 1, 5, 6]) == False

assert is_increasing([1, 1], strict=True) == False
assert is_increasing([1, 1], strict=False) == True

assert is_increasing([1, 2, 3, 3], strict=True) == False
assert is_increasing([1, 2, 3, 3], strict=False) == True
assert is_increasing([1, 2, 3, 2], strict=False) == False
assert is_increasing(list(range(10000))) == True

Задача 8

Написать функцию prod, которая принимает на вход список чисел и возвращает произведение этих чисел.

In [ ]:
# YOUR CODE HERE
In [ ]:
assert prod([5]) == 5
assert prod([1, 2, 3, 4, 5]) == 1 * 2 * 3 * 4 * 5
assert prod([-1, -2, -3, -5, -6]) == (-1) * (-2) * (-3) * (-5) * (-6)
assert prod([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0]) == 0

Задача 9

Написать функцию average(list_of_numbers), которая принимает на вход список чисел и возвращает его среднее арифметическое.

In [ ]:
# YOUR CODE HERE
In [ ]:
assert average([5]) == 5
assert average([0]) == 0
assert average([4, 6]) == 5
assert average([1, 2, 3, 4, 5, 6, 7, 8, 9]) == 5
assert average([1, 100, 200, 300]) == 150.25

Задача 10

Написать функцию average_of, которая принимает на вход несколько чисел и возвращает их среднее арифметическое. В отличие от предыдущей задачи, здесь функция должна принимать на вход не один список, а несколько чисел. Примеры см. в тесте.

Подсказка. Можно написать функцию, принимающую переменное число аргументов. Как это сделать написано тут.

In [ ]:
# YOUR CODE HERE
In [ ]:
assert average_of(5) == 5
assert average_of(0) == 0
assert average_of(4, 6) == 5
assert average_of(1, 2, 3, 4, 5, 6, 7, 8, 9) == 5
assert average_of(1, 100, 200, 300) == 150.25

Задача 11 (2 балла)

Написать функцию variance(numbers, unbiased), принимающую на вход список вещественных чисел numbers и булевскую переменную unbiased и возвращающую выборочную дисперсию для numbers. Если параметр unbiased установлен в True, должна возвращаться исправленная (несмещённая) выборочная дисперсия. Если параметр unbiased не указан, он считается установленным в True. Вы можете пользоваться ранее созданными функциями, но не можете пользоваться никакими библиотеками.

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

In [ ]:
# YOUR CODE HERE
In [ ]:
import numpy as np
np.random.seed(42)
for i in [3, 10, 100, 1000, 10000]:
    num = np.random.uniform(size=i)
    assert np.isclose(variance(num), np.var(num, ddof=1))
    assert np.isclose(variance(num, unbiased=False), np.var(num, ddof=0))

Задача 12 (2 балла)

Итоговая оценка вычисляется по формуле: $\text{накопленная} \times 0.75 + \text{экзамен} \times 0.25$ и округляется до целого числа. Если оценка имеет вид «целое + 1/2», то она округляется вверх (то есть до «целое + 1»), в остальном округлением происходит к ближайшему целому. Написать функцию final_grade(acc, exam), которая бы принимала на вход накопленную и экзаменационную оценки и возвращала итоговую оценку.

Подсказка. Есть функция round, но она округляет числа вида «целое + 1/2» к ближайшему чётному.

In [ ]:
# YOUR CODE HERE
In [ ]:
assert final_grade(1, 2) == 1
assert final_grade(acc=1, exam=2) == 1
assert final_grade(exam=2, acc=1) == 1
assert final_grade(1, 5) == 2
assert final_grade(0, 0) == 0
assert final_grade(0, 1) == 0
assert final_grade(0, 2) == 1
assert final_grade(0, 3) == 1
assert final_grade(0, 4) == 1
assert final_grade(0, 5) == 1
assert final_grade(0, 6) == 2
assert final_grade(0, 7) == 2
assert final_grade(0, 8) == 2
assert final_grade(0, 9) == 2
assert final_grade(1, 0) == 1
assert final_grade(1, 1) == 1
assert final_grade(1, 2) == 1
assert final_grade(1, 3) == 2
assert final_grade(1, 4) == 2
assert final_grade(1, 5) == 2
assert final_grade(1, 6) == 2
assert final_grade(1, 7) == 3
assert final_grade(1, 8) == 3
assert final_grade(1, 9) == 3
assert final_grade(2, 0) == 2
assert final_grade(2, 1) == 2
assert final_grade(2, 2) == 2
assert final_grade(2, 3) == 2
assert final_grade(2, 4) == 3
assert final_grade(2, 5) == 3
assert final_grade(2, 6) == 3
assert final_grade(2, 7) == 3
assert final_grade(2, 8) == 4
assert final_grade(2, 9) == 4
assert final_grade(3, 0) == 2
assert final_grade(3, 1) == 3
assert final_grade(3, 2) == 3
assert final_grade(3, 3) == 3
assert final_grade(3, 4) == 3
assert final_grade(3, 5) == 4
assert final_grade(3, 6) == 4
assert final_grade(3, 7) == 4
assert final_grade(3, 8) == 4
assert final_grade(3, 9) == 5
assert final_grade(4, 0) == 3
assert final_grade(4, 1) == 3
assert final_grade(4, 2) == 4
assert final_grade(4, 3) == 4
assert final_grade(4, 4) == 4
assert final_grade(4, 5) == 4
assert final_grade(4, 6) == 5
assert final_grade(4, 7) == 5
assert final_grade(4, 8) == 5
assert final_grade(4, 9) == 5
assert final_grade(5, 0) == 4
assert final_grade(5, 1) == 4
assert final_grade(5, 2) == 4
assert final_grade(5, 3) == 5
assert final_grade(5, 4) == 5
assert final_grade(5, 5) == 5
assert final_grade(5, 6) == 5
assert final_grade(5, 7) == 6
assert final_grade(5, 8) == 6
assert final_grade(5, 9) == 6
assert final_grade(6, 0) == 5
assert final_grade(6, 1) == 5
assert final_grade(6, 2) == 5
assert final_grade(6, 3) == 5
assert final_grade(6, 4) == 6
assert final_grade(6, 5) == 6
assert final_grade(6, 6) == 6
assert final_grade(6, 7) == 6
assert final_grade(6, 8) == 7
assert final_grade(6, 9) == 7
assert final_grade(7, 0) == 5
assert final_grade(7, 1) == 6
assert final_grade(7, 2) == 6
assert final_grade(7, 3) == 6
assert final_grade(7, 4) == 6
assert final_grade(7, 5) == 7
assert final_grade(7, 6) == 7
assert final_grade(7, 7) == 7
assert final_grade(7, 8) == 7
assert final_grade(7, 9) == 8
assert final_grade(8, 0) == 6
assert final_grade(8, 1) == 6
assert final_grade(8, 2) == 7
assert final_grade(8, 3) == 7
assert final_grade(8, 4) == 7
assert final_grade(8, 5) == 7
assert final_grade(8, 6) == 8
assert final_grade(8, 7) == 8
assert final_grade(8, 8) == 8
assert final_grade(8, 9) == 8
assert final_grade(9, 0) == 7
assert final_grade(9, 1) == 7
assert final_grade(9, 2) == 7
assert final_grade(9, 3) == 8
assert final_grade(9, 4) == 8
assert final_grade(9, 5) == 8
assert final_grade(9, 6) == 8
assert final_grade(9, 7) == 9
assert final_grade(9, 8) == 9
assert final_grade(9, 9) == 9

Задача 13 (4 балла)

Это необязательная задача. Её можно смело пропустить.

Рассмотрим некоторое арифметическое выражение, которое может содержать скобки — квадратные или круглые. Каждая скобка должна корректно закрываться скобкой такого же типа. Например, 5 * [1 + 2 + (3 + 4) + 5] — корректное выражение, а выражение 4 + (2 + некорректное, потому что скобка открылась и не закрылась. Также некорректным будет выражение [1 + (2 + 3] + 4), потому что, например, первая квадратная скобка должна была закрыться также квадратной, а закрылась круглой.

Написать функцию check_brackets(expr), принимающую на вход строку, содержащую выражение, и возвращающую True, если выражение корректное, и False в противном случае.

Подсказка. Вам нужно запоминать, в каком порядке какие скобки открывались. Когда скобка корректно закрылась, она вас больше не интересует.

In [ ]:
# YOUR CODE HERE
In [ ]:
assert check_brackets('5 * [1 + 2 + (3 + 4) + 5]')
assert not check_brackets('4 + (2 + ')
assert not check_brackets('[1 + (2 + 3] + 4)')
assert check_brackets('[]()[][[([(([]))])]]')
assert not check_brackets(']')
assert not check_brackets(')')
assert not check_brackets('[)]')
assert not check_brackets('[)()]')
assert not check_brackets('[)](')
assert not check_brackets("[[([(]))]]")
assert not check_brackets('[')
assert not check_brackets('(')
assert not check_brackets('(' * 100 + ')' * 99)
assert  check_brackets('(' * 1000 + ')' * 1000)
assert not check_brackets('([' + '(' * 998 + ')' * 909 + ']')