diff --git a/solutions/sem02/lesson03/task1.py b/solutions/sem02/lesson03/task1.py index 2c3fc0b58..a44df2051 100644 --- a/solutions/sem02/lesson03/task1.py +++ b/solutions/sem02/lesson03/task1.py @@ -8,13 +8,23 @@ class ShapeMismatchError(Exception): def sum_arrays_vectorized( lhs: np.ndarray, rhs: np.ndarray, -) -> np.ndarray: ... +) -> np.ndarray: + + if lhs.shape != rhs.shape: + raise ShapeMismatchError + return lhs + rhs -def compute_poly_vectorized(abscissa: np.ndarray) -> np.ndarray: ... +def compute_poly_vectorized(abscissa: np.ndarray) -> np.ndarray: + return 3 * (abscissa ** 2) + 2 * abscissa + 1 def get_mutual_l2_distances_vectorized( lhs: np.ndarray, rhs: np.ndarray, -) -> np.ndarray: ... +) -> np.ndarray: + + if lhs.shape[1] != rhs.shape[1]: + raise ShapeMismatchError + + return np.sqrt(((lhs[:, None, :] - rhs[None, :, :]) ** 2).sum(axis=2)) diff --git a/solutions/sem02/lesson03/task2.py b/solutions/sem02/lesson03/task2.py index fc823c1d6..5ac56687a 100644 --- a/solutions/sem02/lesson03/task2.py +++ b/solutions/sem02/lesson03/task2.py @@ -9,11 +9,33 @@ def convert_from_sphere( distances: np.ndarray, azimuth: np.ndarray, inclination: np.ndarray, -) -> tuple[np.ndarray, np.ndarray, np.ndarray]: ... +) -> tuple[np.ndarray, np.ndarray, np.ndarray]: + + if not (distances.shape == azimuth.shape == inclination.shape): + raise ShapeMismatchError + + abscissa = distances * np.sin(inclination) * np.cos(azimuth) + ordinates = distances * np.sin(inclination) * np.sin(azimuth) + applicates = distances * np.cos(inclination) + + return abscissa, ordinates, applicates def convert_to_sphere( abscissa: np.ndarray, ordinates: np.ndarray, applicates: np.ndarray, -) -> tuple[np.ndarray, np.ndarray, np.ndarray]: ... +) -> tuple[np.ndarray, np.ndarray, np.ndarray]: + + if not (abscissa.shape == ordinates.shape == applicates.shape): + raise ShapeMismatchError + + r = np.sqrt(abscissa**2 + ordinates**2 + applicates**2) + azimuth = np.arctan2(ordinates, abscissa) + + inclination = np.zeros_like(r) + + mask = r != 0 + inclination[mask] = np.arccos(applicates[mask] / r[mask]) + + return r, azimuth, inclination diff --git a/solutions/sem02/lesson03/task3.py b/solutions/sem02/lesson03/task3.py index 477acd0ce..06886ce09 100644 --- a/solutions/sem02/lesson03/task3.py +++ b/solutions/sem02/lesson03/task3.py @@ -3,4 +3,19 @@ def get_extremum_indices( ordinates: np.ndarray, -) -> tuple[np.ndarray, np.ndarray]: ... +) -> tuple[np.ndarray, np.ndarray]: + + if len(ordinates) < 3: + raise ValueError + + left_compare = ordinates[1:-1] > ordinates[:-2] + right_compare = ordinates[1:-1] > ordinates[2:] + + max = left_compare & right_compare + + min = (~left_compare) & (~right_compare) + + max_indices = np.where(max)[0] + 1 + min_indices = np.where(min)[0] + 1 + + return min_indices, max_indices diff --git a/solutions/sem02/lesson04/task1.py b/solutions/sem02/lesson04/task1.py index 1b5526c1f..994cdf1d2 100644 --- a/solutions/sem02/lesson04/task1.py +++ b/solutions/sem02/lesson04/task1.py @@ -2,16 +2,62 @@ def pad_image(image: np.ndarray, pad_size: int) -> np.ndarray: - # ваш код - return image + + if pad_size < 1: + raise ValueError + + if image.ndim == 2: + + h, w = image.shape + + padded = np.zeros((h + 2*pad_size, w + 2*pad_size), dtype=image.dtype) + padded[pad_size:pad_size+h, pad_size:pad_size+w] = image + + elif image.ndim == 3: + + h, w, c = image.shape + + padded = np.zeros((h + 2*pad_size, w + 2*pad_size, c), dtype=image.dtype) + padded[pad_size:pad_size+h, pad_size:pad_size+w, :] = image + + else: + raise ValueError + + return padded def blur_image( image: np.ndarray, kernel_size: int, ) -> np.ndarray: - # ваш код - return image + + if kernel_size < 1 or kernel_size % 2 == 0: + raise ValueError + + pad = kernel_size // 2 + k = kernel_size + + padded = pad_image(image.astype(np.float64), pad) + integral = np.cumsum(np.cumsum(padded, axis=0), axis=1) + + if image.ndim == 2: + h, w = image.shape + + sums = (integral[k:, k:] - integral[:-k, k:] - + integral[k:, :-k] + integral[:-k, :-k]) + + result = sums[:h, :w] / (k * k) + + else: + h, w, c = image.shape + result = np.zeros((h, w, c), dtype=np.float64) + + for ch in range(c): + sums = (integral[k:, k:, ch] - integral[:-k, k:, ch] - + integral[k:, :-k, ch] + integral[:-k, :-k, ch]) + result[:, :, ch] = sums[:h, :w] / (k * k) + + return np.clip(result, 0, 255).astype(np.uint8) if __name__ == "__main__": diff --git a/solutions/sem02/lesson04/task2.py b/solutions/sem02/lesson04/task2.py index be9a2288f..2b1f2277a 100644 --- a/solutions/sem02/lesson04/task2.py +++ b/solutions/sem02/lesson04/task2.py @@ -5,6 +5,33 @@ def get_dominant_color_info( image: np.ndarray[np.uint8], threshold: int = 5, ) -> tuple[np.uint8, float]: - # ваш код + + if threshold < 1: + raise ValueError + + pixels = image.flatten() + pixels.sort() - return 0, 0 + current_group_start = 0 + current_group_size = 1 + best_group_start = 0 + best_group_size = 1 + + for i in range(1, len(pixels)): + if pixels[i] - pixels[current_group_start] < threshold: + current_group_size += 1 + else: + if current_group_size > best_group_size: + best_group_size = current_group_size + best_group_start = current_group_start + current_group_start = i + current_group_size = 1 + + if current_group_size > best_group_size: + best_group_size = current_group_size + best_group_start = current_group_start + + total_pixels = len(pixels) + percentage = (best_group_size / total_pixels) * 100 + + return (pixels[best_group_start], percentage) \ No newline at end of file diff --git a/solutions/sem02/lesson05/task1.py b/solutions/sem02/lesson05/task1.py index e9c7c3c56..f96a11160 100644 --- a/solutions/sem02/lesson05/task1.py +++ b/solutions/sem02/lesson05/task1.py @@ -9,4 +9,10 @@ def can_satisfy_demand( costs: np.ndarray, resource_amounts: np.ndarray, demand_expected: np.ndarray, -) -> bool: ... +) -> bool: + M, N = costs.shape + + if len(resource_amounts) != M or len(demand_expected) != N: + raise ShapeMismatchError + + return bool(np.all(costs @ demand_expected <= resource_amounts)) \ No newline at end of file diff --git a/solutions/sem02/lesson05/task2.py b/solutions/sem02/lesson05/task2.py index be1fb9d2b..8dfd859de 100644 --- a/solutions/sem02/lesson05/task2.py +++ b/solutions/sem02/lesson05/task2.py @@ -8,4 +8,22 @@ class ShapeMismatchError(Exception): def get_projections_components( matrix: np.ndarray, vector: np.ndarray, -) -> tuple[np.ndarray | None, np.ndarray | None]: ... +) -> tuple[np.ndarray | None, np.ndarray | None]: + if matrix.shape[0] != matrix.shape[1]: + raise ShapeMismatchError + + n = matrix.shape[0] + if len(vector) != n: + raise ShapeMismatchError + + if abs(np.linalg.det(matrix)) < 1e-10: + return None, None + + coeffs = np.linalg.solve(matrix.T, vector) + + projections = np.array([coeffs[i] * matrix[i] for i in range(n)]) + + total_projection = np.sum(projections, axis=0) + components = vector - total_projection + + return projections, components diff --git a/solutions/sem02/lesson05/task3.py b/solutions/sem02/lesson05/task3.py index 0c66906cb..48062f307 100644 --- a/solutions/sem02/lesson05/task3.py +++ b/solutions/sem02/lesson05/task3.py @@ -9,4 +9,25 @@ def adaptive_filter( Vs: np.ndarray, Vj: np.ndarray, diag_A: np.ndarray, -) -> np.ndarray: ... +) -> np.ndarray: + M, N = Vs.shape + M2, K = Vj.shape + + if M != M2 or len(diag_A) != K: + raise ShapeMismatchError + + Vj_H = Vj.conj().T + + A = np.diag(diag_A.astype(complex)) + + I_K = np.eye(K, dtype=complex) + matrix_to_invert = I_K + Vj_H @ Vj @ A + + inv_matrix = np.linalg.inv(matrix_to_invert) + + I_M = np.eye(M, dtype=complex) + R_inv = I_M - Vj @ inv_matrix @ Vj_H + + y = R_inv @ Vs + + return y \ No newline at end of file diff --git a/solutions/sem02/lesson07/task1.py b/solutions/sem02/lesson07/task1.py index 3a505d89b..ae54a13ce 100644 --- a/solutions/sem02/lesson07/task1.py +++ b/solutions/sem02/lesson07/task1.py @@ -13,8 +13,87 @@ def visualize_diagrams( ordinates: np.ndarray, diagram_type: Any, ) -> None: - # ваш код - pass + + if len(abscissa) != len(ordinates): + raise ShapeMismatchError( + f"Длины массивов должны совпадать: abscissa={len(abscissa)}, ordinates={len(ordinates)}" + ) + + # проверка допустимости diagram_type + valid_types = ["hist", "violin", "box"] + if diagram_type not in valid_types: + raise ValueError( + f"diagram_type должен быть одним из: {valid_types}, получено '{diagram_type}'" + ) + + # Создаем фигуру с сеткой 2x2 + plt.figure(figsize=(10, 10)) + + # Основная диаграмма рассеяния (нижний левый) + scatter_ax = plt.subplot(2, 2, 3) + scatter_ax.scatter( + abscissa, ordinates, alpha=0.6, s=20, c="steelblue", edgecolors="white", linewidth=0.5 + ) + scatter_ax.set_xlabel("X") + scatter_ax.set_ylabel("Y") + scatter_ax.set_title("Диаграмма рассеяния") + scatter_ax.grid(True, alpha=0.3) + + # Распределение по оси X (верхний левый) + x_ax = plt.subplot(2, 2, 1) + + if diagram_type == "hist": + x_ax.hist(abscissa, bins=30, color="steelblue", alpha=0.7, edgecolor="white") + x_ax.set_title("Распределение по X (гистограмма)") + + elif diagram_type == "violin": + x_ax.violinplot(abscissa, positions=[0], showmeans=True, showmedians=True) + x_ax.set_title("Распределение по X (скрипичная диаграмма)") + + elif diagram_type == "box": + x_ax.boxplot(abscissa, vert=True, positions=[0]) + x_ax.set_title("Распределение по X (ящик с усами)") + + x_ax.set_xlabel("X") + x_ax.set_ylabel("Плотность") + x_ax.grid(True, alpha=0.3) + + # Распределение по оси Y (нижний правый) + y_ax = plt.subplot(2, 2, 4) + + if diagram_type == "hist": + y_ax.hist( + ordinates, + bins=30, + color="lightcoral", + alpha=0.7, + edgecolor="white", + orientation="horizontal", + ) + y_ax.set_title("Распределение по Y (гистограмма)") + + elif diagram_type == "violin": + y_ax.violinplot(ordinates, positions=[0], vert=False, showmeans=True, showmedians=True) + y_ax.set_title("Распределение по Y (скрипичная диаграмма)") + + elif diagram_type == "box": + y_ax.boxplot(ordinates, vert=False, positions=[0]) + y_ax.set_title("Распределение по Y (ящик с усами)") + + y_ax.set_xlabel("Плотность") + y_ax.set_ylabel("Y") + y_ax.grid(True, alpha=0.3) + + # Убираем пустой угол (верхний правый) + plt.subplot(2, 2, 2).axis("off") + + # Общий заголовок + plt.suptitle( + f"Визуализация данных\nТип распределения: {diagram_type}", fontsize=14, fontweight="bold" + ) + + # Автоматическая подгонка + plt.tight_layout() if __name__ == "__main__": diff --git a/solutions/sem02/lesson07/task2.py b/solutions/sem02/lesson07/task2.py index decd607ef..c293220ff 100644 --- a/solutions/sem02/lesson07/task2.py +++ b/solutions/sem02/lesson07/task2.py @@ -1 +1,105 @@ -# ваш код (используйте функции или классы для решения данной задачи) +import json + +import matplotlib.pyplot as plt +import numpy as np + + +def visualize_diagrams(filepath: str) -> None: + with open(filepath, "r", encoding="utf-8") as f: + data = json.load(f) + + roman_to_number = {"I": 1, "II": 2, "III": 3, "IV": 4} + + before_numbers = [roman_to_number[x] for x in data["before"]] + after_numbers = [roman_to_number[x] for x in data["after"]] + + before_counts = [before_numbers.count(i) for i in range(1, 5)] + after_counts = [after_numbers.count(i) for i in range(1, 5)] + + fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5)) + + x = np.arange(4) + categories = ["I", "II", "III", "IV"] + + ax1.bar(x, before_counts, color="steelblue", edgecolor="white", linewidth=2) + ax1.set_title("До установки импланта", fontsize=14, fontweight="bold") + ax1.set_xlabel("Степень митральной недостаточности", fontsize=11) + ax1.set_ylabel("Количество пациентов", fontsize=11) + ax1.set_xticks(x) + ax1.set_xticklabels(categories, fontsize=10) + ax1.grid(axis="y", alpha=0.3, linestyle="--") + + for bar, count in zip(ax1.bar(x, before_counts, color="steelblue"), before_counts): + ax1.text( + bar.get_x() + bar.get_width() / 2.0, + count + 0.5, + str(count), + ha="center", + va="bottom", + fontweight="bold", + ) + + ax2.bar(x, after_counts, color="lightcoral", edgecolor="white", linewidth=2) + ax2.set_title("После установки импланта", fontsize=14, fontweight="bold") + ax2.set_xlabel("Степень митральной недостаточности", fontsize=11) + ax2.set_ylabel("Количество пациентов", fontsize=11) + ax2.set_xticks(x) + ax2.set_xticklabels(categories, fontsize=10) + ax2.grid(axis="y", alpha=0.3, linestyle="--") + + for bar, count in zip(ax2.bar(x, after_counts, color="lightcoral"), after_counts): + ax2.text( + bar.get_x() + bar.get_width() / 2.0, + count + 0.5, + str(count), + ha="center", + va="bottom", + fontweight="bold", + ) + + plt.suptitle( + "Распределение пациентов по степени митральной недостаточности\n" \ + "до и после установки кардио-импланта", + fontsize=16, + fontweight="bold", + ) + + plt.tight_layout() + plt.savefig("mitral_insufficiency_distribution.png", dpi=150, bbox_inches="tight") + plt.show() + + total_before = sum(before_counts) + total_after = sum(after_counts) + + print("\n" + "=" * 60) + print("АНАЛИЗ ЭФФЕКТИВНОСТИ ИМПЛАНТА") + print("=" * 60) + + for i, grade in enumerate(categories): + before_pct = (before_counts[i] / total_before) * 100 + after_pct = (after_counts[i] / total_after) * 100 + change = after_pct - before_pct + arrow = "↑" if change > 0 else "↓" if change < 0 else "→" + print( + f"{grade} степень: {before_pct:5.1f}% → {after_pct:5.1f}% ({arrow} {abs(change):.1f}%)" + ) + + severe_before = before_counts[2] + before_counts[3] + severe_after = after_counts[2] + after_counts[3] + + print("\n" + "=" * 60) + print("ВЫВОД:") + print("=" * 60) + + if severe_before > 0: + reduction = ((severe_before - severe_after) / severe_before) * 100 + if reduction > 30: + print(f"✅ Имплант эффективен! Снижение тяжелых форм на {reduction:.1f}%") + elif reduction > 10: + print(f"⚠️ Имплант умеренно эффективен (снижение на {reduction:.1f}%)") + else: + print(f"❌ Имплант малоэффективен (снижение на {reduction:.1f}%)") + + +if __name__ == "__main__": + visualize_diagrams("medic_data.json") diff --git a/solutions/sem02/lesson08/modulated_signal.gif b/solutions/sem02/lesson08/modulated_signal.gif new file mode 100644 index 000000000..17c74776f Binary files /dev/null and b/solutions/sem02/lesson08/modulated_signal.gif differ diff --git a/solutions/sem02/lesson08/task1.py b/solutions/sem02/lesson08/task1.py index 89f88572f..a68a6e09f 100644 --- a/solutions/sem02/lesson08/task1.py +++ b/solutions/sem02/lesson08/task1.py @@ -1,8 +1,6 @@ -from functools import partial import matplotlib.pyplot as plt import numpy as np - from IPython.display import HTML from matplotlib.animation import FuncAnimation @@ -16,8 +14,49 @@ def create_modulation_animation( animation_step=0.01, save_path="" ) -> FuncAnimation: - # ваш код - return FuncAnimation() + def signal(t): + carrier = np.sin(2 * np.pi * fc * t) + return carrier if modulation is None else modulation(t) * carrier + + fig, ax = plt.subplots(figsize=(12, 6)) + num_points = int(plot_duration / time_step) + 1 + time_segment = np.linspace(0, plot_duration, num_points) + + line, = ax.plot(time_segment, signal(time_segment), 'b-', lw=2) + + if modulation is not None: + envelope, = ax.plot(time_segment, modulation(time_segment), 'r--', alpha=0.7) + + total_duration = (num_frames - 1) * animation_step + plot_duration + total_points = int(total_duration / time_step) + 1 + total_time = np.linspace(0, total_duration, total_points) + total_signal = signal(total_time) + + ax.set_xlim(0, plot_duration) + ax.set_ylim(-1.2 * np.max(np.abs(total_signal)), 1.2 * np.max(np.abs(total_signal))) + ax.grid(True, alpha=0.3) + ax.set_xlabel('Time (s)') + ax.set_ylabel('Amplitude') + ax.set_title('Modulated Signal') + + def update(frame): + start = frame * animation_step + idx = int(start / time_step) + line.set_data(total_time[idx:idx+num_points], total_signal[idx:idx+num_points]) + ax.set_xlim(start, start + plot_duration) + if modulation is not None: + envelope.set_data( + total_time[idx:idx+num_points], + modulation(total_time[idx:idx+num_points]) + ) + return (line,) + + anim = FuncAnimation(fig, update, frames=num_frames, interval=50) + + if save_path: + anim.save(save_path, writer='pillow') + + return anim if __name__ == "__main__": diff --git a/solutions/sem02/lesson08/task2.py b/solutions/sem02/lesson08/task2.py index b677c0702..e6032ebcf 100644 --- a/solutions/sem02/lesson08/task2.py +++ b/solutions/sem02/lesson08/task2.py @@ -1,25 +1,136 @@ -from functools import partial - import matplotlib.pyplot as plt import numpy as np - from IPython.display import HTML from matplotlib.animation import FuncAnimation +def animate_wave_algorithm( + maze: np.ndarray, + start: tuple[int, int], + end: tuple[int, int], + save_path: str = "", +) -> FuncAnimation: + + def solution_wave(maze, start, end): + height, width = maze.shape + distances = np.full(maze.shape, fill_value=-1, dtype=int) + distances[start] = 0 + history = [distances.copy()] + cur_wave = [start] + moves = [(-1, 0), (1, 0), (0, -1), (0, 1)] + + while cur_wave: + next_wave = [] + for y, x in cur_wave: + cur_value = distances[y, x] + for move_y, move_x in moves: + new_y = y + move_y + new_x = x + move_x + if not (0 <= new_y < height and 0 <= new_x < width): + continue + if maze[new_y, new_x] != 1: + continue + if distances[new_y, new_x] != -1: + continue + distances[new_y, new_x] = cur_value + 1 + next_wave.append((new_y, new_x)) + history.append(distances.copy()) + if distances[end] != -1: + break + cur_wave = next_wave + return distances, history + def path_recovery(distances, start, end): + height, width = distances.shape + moves = [(-1, 0), (1, 0), (0, -1), (0, 1)] + path = [end] + cur_cell = end + while cur_cell != start: + cur_value = distances[cur_cell] + for move_y, move_x in moves: + new_y = cur_cell[0] + move_y + new_x = cur_cell[1] + move_x + if not (0 <= new_y < height and 0 <= new_x < width): + continue + if distances[new_y, new_x] == cur_value - 1: + cur_cell = (new_y, new_x) + path.append(cur_cell) + break + path.reverse() + return path + + def build_frames(history, path, path_marker): + frames = list(history) + if path: + state = history[-1].copy() + for cell in path: + state[cell] = path_marker + frames.append(state.copy()) + return frames + + # алгос + distances, history = solution_wave(maze, start, end) + path_found = distances[end] != -1 + + if path_found: + path = path_recovery(distances, start, end) + else: + path = [] + print("Путь не найден") + + path_marker = distances.max() + 2 if path_found else 999 + frames = build_frames(history, path, path_marker) + + # графика + figure, axis = plt.subplots(figsize=(8, 8)) + height, width = maze.shape + + axis.imshow(maze, cmap="gray", alpha=0.1) + + + axis.set_xticks(np.arange(width + 1) - 0.5, minor=True) + axis.set_yticks(np.arange(height + 1) - 0.5, minor=True) + axis.grid(which="minor", color="black", linestyle="-", linewidth=0.5) + axis.set_xticks([]) + axis.set_yticks([]) + + texts = [ + [axis.text(x, y, "", ha="center", va="center") for x in range(width)] + for y in range(height) + ] + + # обновление кадра + def update(frame_id): + curr_frame = frames[frame_id] + for y in range(height): + for x in range(width): + val = curr_frame[y, x] + if val == -1: + texts[y][x].set_text("") + elif val == path_marker: + texts[y][x].set_text("*") + texts[y][x].set_color("red") + else: + texts[y][x].set_text(str(val)) + texts[y][x].set_color("black") + return [t for row in texts for t in row] + + # анимация + animation = FuncAnimation( + figure, + update, + frames=len(frames), + interval=200, + blit=True, + ) + + if save_path: + animation.save(save_path, writer="pillow", fps=5) + + return animation -def animate_wave_algorithm( - maze: np.ndarray, - start: tuple[int, int], - end: tuple[int, int], - save_path: str = "" -) -> FuncAnimation: - # ваш код - return FuncAnimation() if __name__ == "__main__": - # Пример 1 maze = np.array([ [0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 0], @@ -29,25 +140,10 @@ def animate_wave_algorithm( [1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0], ]) - - start = (2, 0) - end = (5, 0) - save_path = "labyrinth.gif" # Укажите путь для сохранения анимации - - animation = animate_wave_algorithm(maze, start, end, save_path) - HTML(animation.to_jshtml()) - - # Пример 2 - maze_path = "./data/maze.npy" - loaded_maze = np.load(maze_path) - - # можете поменять, если захотите запустить из других точек start = (2, 0) end = (5, 0) - loaded_save_path = "loaded_labyrinth.gif" - - loaded_animation = animate_wave_algorithm(loaded_maze, start, end, loaded_save_path) - HTML(loaded_animation.to_jshtml()) + save_path = "labyrinth.gif" - \ No newline at end of file + animation = animate_wave_algorithm(maze, start, end, save_path) + HTML(animation.to_jshtml()) \ No newline at end of file diff --git a/solutions/sem02/lesson10/task1.ipynb b/solutions/sem02/lesson10/task1.ipynb index 4b4e9e335..d20d4c164 100644 --- a/solutions/sem02/lesson10/task1.ipynb +++ b/solutions/sem02/lesson10/task1.ipynb @@ -34,12 +34,168 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "d7b00711", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
survivedpclasssexagesibspparchfareembarkedclasswhoadult_maledeckembark_townalivealone
48102maleNaN000.0000SSecondmanTrueNaNSouthamptonnoTrue
32813female31.01120.5250SThirdwomanFalseNaNSouthamptonyesFalse
213female26.0007.9250SThirdwomanFalseNaNSouthamptonyesTrue
79611female49.00025.9292SFirstwomanFalseDSouthamptonyesTrue
40203female21.0109.8250SThirdwomanFalseNaNSouthamptonnoFalse
\n", + "
" + ], + "text/plain": [ + " survived pclass sex age sibsp parch fare embarked class \\\n", + "481 0 2 male NaN 0 0 0.0000 S Second \n", + "328 1 3 female 31.0 1 1 20.5250 S Third \n", + "2 1 3 female 26.0 0 0 7.9250 S Third \n", + "796 1 1 female 49.0 0 0 25.9292 S First \n", + "402 0 3 female 21.0 1 0 9.8250 S Third \n", + "\n", + " who adult_male deck embark_town alive alone \n", + "481 man True NaN Southampton no True \n", + "328 woman False NaN Southampton yes False \n", + "2 woman False NaN Southampton yes True \n", + "796 woman False D Southampton yes True \n", + "402 woman False NaN Southampton no False " + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "import seaborn as sns\n", + "import pandas as pd\n", + "import numpy as np\n", "\n", "\n", "titanic_data = sns.load_dataset(\"titanic\")\n", @@ -66,12 +222,36 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "cd2f1773", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "survived 0\n", + "pclass 0\n", + "sex 0\n", + "age 177\n", + "sibsp 0\n", + "parch 0\n", + "fare 0\n", + "embarked 2\n", + "class 0\n", + "who 0\n", + "adult_male 0\n", + "deck 688\n", + "embark_town 2\n", + "alive 0\n", + "alone 0\n", + "dtype: int64\n" + ] + } + ], "source": [ - "# ваш код" + "null_counts = titanic_data.isnull().sum()\n", + "print(null_counts)" ] }, { @@ -88,12 +268,35 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "7e458447", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Удалено столбцов: 1\n", + "Удалено строк: 0\n", + "Оставшийся размер: (891, 14)\n" + ] + } + ], "source": [ - "# ваш код" + "rows, cols = titanic_data.shape\n", + "\n", + "max_missing_cols = rows / 2\n", + "cols_to_drop = titanic_data.columns[titanic_data.isnull().sum() > max_missing_cols]\n", + "titanic_clean = titanic_data.drop(columns=cols_to_drop)\n", + "\n", + "new_cols = titanic_clean.shape[1]\n", + "max_missing_rows = new_cols / 2\n", + "rows_to_drop = titanic_clean[titanic_clean.isnull().sum(axis=1) > max_missing_rows].index\n", + "titanic_clean = titanic_clean.drop(index=rows_to_drop)\n", + "\n", + "print(f\"Удалено столбцов: {len(cols_to_drop)}\")\n", + "print(f\"Удалено строк: {len(rows_to_drop)}\")\n", + "print(f\"Оставшийся размер: {titanic_clean.shape}\")" ] }, { @@ -111,12 +314,34 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "f7db5e99", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Пропусков в age после заполнения: 0\n" + ] + } + ], "source": [ - "# ваш код" + "titanic_filled = titanic_clean.copy()\n", + "\n", + "median_man = titanic_filled[titanic_filled['who'] == 'man']['age'].median()\n", + "median_woman = titanic_filled[titanic_filled['who'] == 'woman']['age'].median()\n", + "median_child = titanic_filled[titanic_filled['who'] == 'child']['age'].median()\n", + "\n", + "median_man = int(round(median_man))\n", + "median_woman = int(round(median_woman))\n", + "median_child = int(round(median_child))\n", + "\n", + "titanic_filled.loc[(titanic_filled['age'].isnull()) & (titanic_filled['who'] == 'man'), 'age'] = median_man\n", + "titanic_filled.loc[(titanic_filled['age'].isnull()) & (titanic_filled['who'] == 'woman'), 'age'] = median_woman\n", + "titanic_filled.loc[(titanic_filled['age'].isnull()) & (titanic_filled['who'] == 'child'), 'age'] = median_child\n", + "\n", + "print(f\"Пропусков в age после заполнения: {titanic_filled['age'].isnull().sum()}\")" ] }, { @@ -131,12 +356,24 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "id": "67a0c6bc", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Всего пропусков в таблице: 0\n", + "Размер итоговой таблицы: (889, 14)\n" + ] + } + ], "source": [ - "# ваш код" + "titanic_final = titanic_filled[titanic_filled.isnull().sum(axis=1) <= 1]\n", + "\n", + "print(f\"Всего пропусков в таблице: {titanic_final.isnull().sum().sum()}\")\n", + "print(f\"Размер итоговой таблицы: {titanic_final.shape}\")" ] }, { @@ -151,12 +388,29 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "id": "6a2d0ae9", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Город с max пассажиров: Southampton\n", + "embark_town\n", + "Southampton 644\n", + "Cherbourg 168\n", + "Queenstown 77\n", + "Name: count, dtype: int64\n" + ] + } + ], "source": [ - "# ваш код" + "city_counts = titanic_final['embark_town'].value_counts()\n", + "most_common_city = city_counts.idxmax()\n", + "\n", + "print(f\"Город с max пассажиров: {most_common_city}\")\n", + "print(city_counts)" ] }, { @@ -171,12 +425,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "id": "11acb4b4", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Процент выживших: 38.25%\n" + ] + } + ], "source": [ - "# ваш код" + "survived_pct = (titanic_final['survived'].sum() / len(titanic_final)) * 100\n", + "survived_pct = round(survived_pct, 2)\n", + "\n", + "print(f\"Процент выживших: {survived_pct}%\")" ] }, { @@ -191,12 +456,26 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "id": "59ec7295", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "embark_town\n", + "Cherbourg 93\n", + "Queenstown 30\n", + "Southampton 217\n", + "Name: survived, dtype: int64\n" + ] + } + ], "source": [ - "# ваш код" + "survived_by_embark = titanic_final.groupby('embark_town')['survived'].sum()\n", + "\n", + "print(survived_by_embark)" ] }, { @@ -211,12 +490,27 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "id": "34daca28", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "class\n", + "First 62.62\n", + "Second 47.28\n", + "Third 24.24\n", + "Name: survived, dtype: float64\n" + ] + } + ], "source": [ - "# ваш код" + "survival_by_class = titanic_final.groupby('class')['survived'].mean() * 100\n", + "survival_by_class = survival_by_class.round(2)\n", + "\n", + "print(survival_by_class)" ] }, { @@ -231,12 +525,29 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "id": "1fc0d667", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Богатых пассажиров: 53\n", + "Процент выживших среди них: 73.58%\n" + ] + } + ], "source": [ - "# ваш код" + "rich = titanic_final[titanic_final['fare'] >= 100]\n", + "if len(rich) > 0:\n", + " rich_survived_pct = (rich['survived'].sum() / len(rich)) * 100\n", + "else:\n", + " rich_survived_pct = 0\n", + "rich_survived_pct = round(rich_survived_pct, 2)\n", + "\n", + "print(f\"Богатых пассажиров: {len(rich)}\")\n", + "print(f\"Процент выживших среди них: {rich_survived_pct}%\")" ] }, { @@ -251,12 +562,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "id": "480352b6", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Детей в одиночку: 6\n" + ] + } + ], "source": [ - "# ваш код" + "children_alone = titanic_final[(titanic_final['who'] == 'child') & (titanic_final['alone'] == True)]\n", + "count_children_alone = len(children_alone)\n", + "\n", + "print(f\"Детей в одиночку: {count_children_alone}\")" ] }, { @@ -266,11 +588,19 @@ "source": [ "Какие выводы вы можете сделать о выживших пассажирах Титаника? " ] + }, + { + "cell_type": "markdown", + "id": "ce6aecc3", + "metadata": {}, + "source": [ + "им сильно повезло, рад что они выжили. а вообще печально так все, столько грусти тут, столько утрат(" + ] } ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "venv", "language": "python", "name": "python3" }, @@ -284,7 +614,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.9" + "version": "3.12.3" } }, "nbformat": 4,