Вместе с факультетом Data Science GeekUniversity собрали для вас задачи для практики по самым популярным Python-библиотекам в Data Science: pandas, NumPy и DataTable. Решать задачи можно в любом порядке.
Обратите внимание, что у любой задачи может быть несколько способов решения. Чтобы посмотреть добавленный нами вариант решения, кликните по соответствующей кнопке. Все приведённые варианты написаны на Python 3.
Задачи по pandas
Задача 1
Как найти евклидово расстояние между двумя Series
(точками) a
и b
, не используя встроенную формулу?
Ввод:
a = pd.Series([2, 4, 6, 8])
b = pd.Series([1, 3, 5, 7])
Ожидаемый вывод:
2.0
# Ввод
a = pd.Series([2, 4, 6, 8]
b = pd.Series([1, 3, 5, 7])
# Решение
sum((a - b)**2)**.5
# Решение (с использованием функции из NumPy)
np.linalg.norm(a-b)
Задача 2
Как найти максимально возможное абсолютное значение корреляции каждого столбца с другими столбцами в df
?
Ввод:
df = pd.DataFrame(np.random.randint(1, 100, 16).reshape(4, 4), columns=list('efgh'), index=list('abcd'))
# Ввод
df = pd.DataFrame(np.random.randint(1, 100, 16).reshape(4, 4), columns=list('efgh'), index=list('abcd'))
# Решение
abs_corr = np.abs(df.corr())
max_corr = abs_corr.apply(lambda x: sorted(x)[-2])
print('Максимальное значение корреляции для каждого столбца: ', np.round(max_corr.tolist(), 2))
Вывод:
Максимальное значение корреляции для каждого столбца: [0.58 0.58 0.76 0.76]
Задача 3
Как нормализовать все столбцы в DataFrame
?
- Нормализуйте все столбцы
df
путём вычитания среднего значения столбца и деления на стандартное отклонение. - Сделайте так, чтобы все значения в
df
находились в диапазоне от 0 до 1.
Ввод:
df = pd.DataFrame(np.random.randint(1, 100, 16).reshape(4, 4))
# Ввод
df = pd.DataFrame(np.random.randint(1, 100, 16).reshape(4, 4))
# Первая часть решения
part1 = df.apply(lambda x: ((x - x.mean()) / x.std()).round(2))
print('Первая часть\n', part1)
# Вторая часть решения
part2 = df.apply(lambda x: ((x.max() - x) / (x.max() - x.min())).round(2))
print('Вторая часть\n', part2)
Вывод:
Первая часть
0 1 2 3
0 -1.11 -0.87 0.43 0.61
1 -0.57 0.83 -0.50 -0.38
2 0.72 0.91 -1.09 -1.23
3 0.96 -0.87 1.17 0.99
Вторая часть
0 1 2 3
0 1.00 1.00 0.33 0.17
1 0.74 0.05 0.74 0.62
2 0.12 0.00 1.00 1.00
3 0.00 1.00 0.00 0.00
Задача 4
Как объединить два DataFrame
по двум столбцам так, чтобы остались только общие строки?
Объедините df1
и df2
по столбцам fruit-frukt и weight-ves.
Ввод:
df1 = pd.DataFrame({'fruit': ['apple', 'banana', 'orange'] * 3,
'weight': ['low', 'medium', 'high'] * 3,
'price': np.random.randint(0, 100, 9)})
df2 = pd.DataFrame({'frukt': ['apple', 'banana', 'melon'] * 2,
'ves': ['low', 'high'] * 3,
'price': np.random.randint(0, 100, 6)})
# Ввод
df1 = pd.DataFrame({'fruit': ['apple', 'banana', 'orange'] * 3,
'weight': ['low', 'medium', 'high'] * 3,
'price': np.random.randint(0, 100, 9)})
df2 = pd.DataFrame({'frukt': ['apple', 'banana', 'melon'] * 2,
'ves': ['low', 'high'] * 3,
'price': np.random.randint(0, 100, 6)})
# Решение
pd.merge(df1, df2, how='inner', left_on=['fruit', 'weight'], right_on=['frukt', 'ves'], suffixes=['_left', '_right'])
Задача 5
Как узнать частоту уникальных значений во всём DataFrame
?
Ввод:
df = pd.DataFrame(np.random.randint(1, 10, 16).reshape(4, 4), columns=list('abcd'))
# Ввод
df = pd.DataFrame(np.random.randint(1, 10, 16).reshape(4, 4), columns=list('abcd'))
# Решение
pd.value_counts(df.values.ravel())
Вывод:
2 5
8 4
9 2
6 2
5 1
3 1
1 1
dtype: int64
Задача 6
Как создать новый столбец, который содержит номера ближайших по евклидовому расстоянию столбцов?
Ввод:
df = pd.DataFrame(np.random.randint(1, 100, 16).reshape(4, 4), columns=list('efgh'), index=list('abcd'))
df
# e f g h
# a 51 57 11 15
# b 63 5 81 48
# c 7 63 98 88
# d 6 31 29 37
Ожидаемый вывод:
df
# e f g h nearest_row dist
# a 51 57 11 15 c 122.0
# b 63 5 81 48 a 94.0
# c 7 63 98 88 a 122.0
# d 6 31 29 37 c 92.0
# Ввод
df = pd.DataFrame(np.random.randint(1, 100, 16).reshape(4, 4), columns=list('efgh'), index=list('abcd'))
import numpy as np
# Инициализация выводов
nearest_rows = []
nearest_distance = []
# Проход по строкам
for i, row in df.iterrows():
curr = row
rest = df.drop(i)
dists = {} # инициализируем словарь для евклидовых расстояния для текущей строки
# проходим по оставшимся строкам текущей строки
for j, contestant in rest.iterrows():
# вычисляем евклидово расстояние и обновляем dists
dists.update({j: round(np.linalg.norm(curr.values - contestant.values))})
# приравниваем текущую строку к ближайшей и записываем значение расстояния=
nearest_rows.append(max(dists, key=dists.get))
nearest_distance.append(max(dists.values()))
df['nearest_row'] = nearest_rows
df['dist'] = nearest_distance
Задачи по NumPy
Задача 7
Как поменять местами две строки в двумерном массиве NumPy? Поменяйте местами строки 1 и 3 массива a
.
Ввод:
a = np.arange(9).reshape(3,3)
# Ввод
a = np.arange(9).reshape(3,3)
# Решение
a[[2, 1, 0], :]
Вывод:
array([[6, 7, 8],
[3, 4, 5],
[0, 1, 2]])
Задача 8
Как найти количество уникальных значений в массиве NumPy? Найдите уникальные значения и их количество в столбце species
таблицы iris
.
Ввод:
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
iris = np.genfromtxt(url, delimiter=',', dtype='object')
# Ввод
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
iris = np.genfromtxt(url, delimiter=',', dtype='object')
# Решение
# Извлекаем столбец species как массив
species = np.array([row.tolist()[4] for row in iris])
# Получаем уникальные значения и их количество
np.unique(species, return_counts=True)
Вывод:
(array([b'Iris-setosa', b'Iris-versicolor', b'Iris-virginica'],
dtype='|S15'), array([50, 50, 50]))
Задача 9
Как найти второе максимальное значение в массиве, который сгруппирован по другому массиву? Найдите значение второго самого длинного petallength
вида setosa
в таблице iris
.
Ввод:
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
iris = np.genfromtxt(url, delimiter=',', dtype='object')
Решение:
# Ввод
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
iris = np.genfromtxt(url, delimiter=',', dtype='object')
# Решение
# Извлекаем столбцы вида и длины лепестков
setosa_petal_len = iris[iris[:, 4] == b'Iris-setosa', [2]].astype('float')
# Получаем второе значение с конца
np.unique(np.sort(setosa_petal_len))[-2]
Вывод:
1.7
Задача 10
Как отранжировать элементы массива NumPy?
Ввод:
a = np.random.randint(100, size=10)
print(a)
# [9 15 64 28 89 93 29 8 73 0]
Ожидаемый вывод:
[2 3 6 4 8 9 5 1 7 0]
# Ввод
a = np.random.randint(100, size=10)
# Решение
print(a.argsort().argsort())
Задача 11
Как найти результат деления минимального значения на максимальное в каждой строке двумерного массива?
Ввод:
np.random.seed(10)
a = np.random.randint(1, 10, [3, 3])
a
# array([[5, 1, 2],
# [1, 2, 9],
# [1, 9, 7]])
# Ввод
np.random.seed(10)
a = np.random.randint(1, 10, [3, 3])
# Решение
np.apply_along_axis(lambda x: np.min(x) / np.max(x), arr=a, axis=1)
Вывод:
array([0.2, 0.11111111, 0.11111111])
Задача 12
Как найти повторяющиеся значения в массиве NumPy? Найдите повторяющиеся значения (начиная со второго вхождения) в заданном массиве и отметьте их как True
. Первое вхождение отмечайте как False
.
Ввод:
np.random.seed(10)
a = np.random.randint(0, 7, 10)
print(a)
# [1 5 4 0 1 3 4 1 5 0]
Ожидаемый вывод:
[False False False False True False True True True True]
# Ввод
np.random.seed(10)
a = np.random.randint(0, 7, 10)
# Решение
# Создаём массив с True
out = np.full(a.shape[0], True)
# Находим индексы уникальных элементов
pos = np.unique(a, return_index=True)[1]
# Помечаем их как False
out[pos] = False
print(out)
Задача 13
Как удалить из массива NumPy строки, которые содержат nan
?
Ввод:
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
iris = np.genfromtxt(url, delimiter=',', dtype='float', usecols=[0, 1, 2, 3])
iris[np.random.randint(150, size=20), np.random.randint(4, size=20)] = np.nan
Решение:
# Ввод
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
iris = np.genfromtxt(url, delimiter=',', dtype='float', usecols=[0, 1, 2, 3])
iris[np.random.randint(150, size=20), np.random.randint(4, size=20)] = np.nan
# Решение
# Способ 1:
nan_in_row = np.array([~np.any(np.isnan(row)) for row in iris])
iris[nan_in_row][:5]
# Способ 2:
iris[np.sum(np.isnan(iris), axis = 1) == 0][:5]
Вывод:
array([[ 4.9, 3. , 1.4, 0.2],
[ 4.7, 3.2, 1.3, 0.2],
[ 4.6, 3.1, 1.5, 0.2],
[ 5. , 3.6, 1.4, 0.2],
[ 5.4, 3.9, 1.7, 0.4]])
Задачи по DataTable
Задача 14
Как сделать left join двух объектов datatable.Frame
? Объедините заданные объекты по ключу А
.
Ввод:
import datatable as dt
df1 = dt.Frame(A=[1, 2, 3, 4], B=['a', 'b', 'c', 'd'])
df2 = dt.Frame(A=[1, 2, 3, 4, 5], C=['a2', 'b2', 'c2', 'd2', 'e2'])
# Ввод
import datatable as dt
df1 = dt.Frame(A=[1, 2, 3, 4], B=['a', 'b', 'c', 'd'])
df2 = dt.Frame(A=[1, 2, 3, 4, 5], C=['a2', 'b2', 'c2', 'd2', 'e2'])
# Решение
df2.key = 'A'
output = df1[:, :, dt.join(df2)]
Задача 15
Как преобразовать datatable.Frame
в формат Pandas, NumPy, словаря, списка, кортежа, CSV-файла? Датасет из примера.
Решение:
import datatable as dt
df = dt.fread('https://raw.githubusercontent.com/selva86/datasets/master/BostonHousing.csv')
# в DataFrame Pandas
pd_df = df.to_pandas()
# в массив NumPy
arr = df.to_numpy()
# в словарь
dict_ = df.to_dict()
# в список
list_ = df[:, 'medv'].to_list()
# в кортеж
tuples_ = df[:, 'medv'].to_tuples()
# в CSV
df.to_csv('BostonHousing.csv')
Задача 16
Как узнать типы данных всех столбцов в datatable.Frame
? Датасет из примера.
Ожидаемый вывод:
crim : stype.float64
zn : stype.float64
indus : stype.float64
chas : stype.bool8
nox : stype.float64
rm : stype.float64
age : stype.float64
dis : stype.float64
rad : stype.int32
tax : stype.int32
ptratio : stype.float64
b : stype.float64
lstat : stype.float64
medv : stype.float64
Решение:
import datatable as dt
df = dt.fread('https://raw.githubusercontent.com/selva86/datasets/master/BostonHousing.csv')
for i in range(len(df.names)):
print(df.names[i], ':', df.stypes[i])