Что такое векторизованные операции в NumPy и Pandas?

Что такое векторизация и зачем она нужна?

Векторизация – это способ выполнения операций над целыми массивами данных одновременно, а не поэлементно через циклы. В контексте NumPy и Pandas это означает, что вместо написания циклов for для обработки каждого элемента массива или столбца DataFrame, вы используете оптимизированные функции, которые применяются ко всему массиву сразу. Это позволяет значительно ускорить вычисления, особенно при работе с большими объемами данных, что критически важно в анализе данных, машинном обучении, и других областях.

Преимущества векторизованных операций: скорость и эффективность

Главное преимущество векторизации – скорость. NumPy и Pandas используют низкоуровневые оптимизированные библиотеки (например, BLAS и LAPACK для NumPy), которые выполняют операции над массивами на уровне машинного кода. Это в разы быстрее, чем итерирование по элементам в Python. Кроме скорости, векторизация упрощает код, делая его более читаемым и менее подверженным ошибкам. Меньше циклов – меньше потенциальных багов.

Векторизация в сравнении с циклами: примеры и бенчмарки

Представьте, что вам нужно увеличить каждый элемент массива на 1. С циклом for это выглядит так:

import numpy as np

def add_one_loop(arr: np.ndarray) -> np.ndarray:
    """Добавляет 1 к каждому элементу массива NumPy, используя цикл.

    Args:
        arr: Входной массив NumPy.

    Returns:
        Новый массив, где каждый элемент увеличен на 1.
    """
    result = np.empty_like(arr)
    for i in range(len(arr)):
        result[i] = arr[i] + 1
    return result


my_array = np.arange(1000)
result_loop = add_one_loop(my_array)

А с векторизацией NumPy:

def add_one_vectorized(arr: np.ndarray) -> np.ndarray:
    """Добавляет 1 к каждому элементу массива NumPy, используя векторизацию.

    Args:
        arr: Входной массив NumPy.

    Returns:
        Новый массив, где каждый элемент увеличен на 1.
    """
    return arr + 1

result_vectorized = add_one_vectorized(my_array)

Второй вариант не только короче, но и значительно быстрее. Бенчмарки покажут разницу на больших массивах.

Векторизованные операции в NumPy

Основные арифметические операции (сложение, вычитание, умножение, деление)

NumPy позволяет выполнять арифметические операции (+, -, *, /) между массивами поэлементно. Если размеры массивов совпадают, операция применяется к соответствующим элементам. Если размеры не совпадают, применяется broadcasting (см. ниже).

import numpy as np

arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])

sum_arr = arr1 + arr2  # [5 7 9]
diff_arr = arr2 - arr1 # [3 3 3]
prod_arr = arr1 * arr2 # [ 4 10 18]
div_arr = arr2 / arr1  # [4.  2.5 2. ]

Универсальные функции (ufunc): применение математических функций к массивам

ufunc (universal functions) – это функции, которые работают поэлементно над массивами NumPy. Они включают в себя математические функции (sin, cos, exp, log), тригонометрические, битовые и другие операции. Например:

import numpy as np

arr = np.array([0, 1, 2, 3])
sin_arr = np.sin(arr) # Вычисление синуса для каждого элемента
log_arr = np.log(arr + 1) # Вычисление натурального логарифма, избегая log(0)

Логические и сравнительные операции: создание булевых масок

Операции сравнения (>, =, <=) создают булевые массивы, где True означает, что условие выполнено для соответствующего элемента, а False – нет. Эти булевые массивы можно использовать для фильтрации данных.

Реклама
import numpy as np

arr = np.array([1, 2, 3, 4, 5])

bool_arr = arr > 2  # [False False  True  True  True]
filtered_arr = arr[bool_arr]  # [3 4 5] - элементы, больше 2

Примеры векторизованных операций NumPy для обработки изображений и сигналов

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

import numpy as np
from PIL import Image # pip install Pillow

def adjust_brightness(image_path: str, factor: float) -> np.ndarray:
    """Изменяет яркость изображения, умножая значения пикселей на фактор.

    Args:
        image_path: Путь к файлу изображения.
        factor: Фактор изменения яркости (1.0 - без изменений).

    Returns:
        NumPy массив, представляющий изображение с измененной яркостью.
    """
    img = Image.open(image_path).convert('L') # Открываем в оттенках серого
    img_array = np.array(img) / 255.0 # Нормализуем значения пикселей к диапазону [0, 1]
    brightened_array = np.clip(img_array * factor, 0, 1) # Изменяем яркость и обрезаем значения
    return brightened_array

Векторизованные операции в Pandas

Векторизация операций над Series и DataFrame

Pandas Series и DataFrame поддерживают все те же векторизованные операции, что и NumPy массивы. Можно выполнять арифметические операции, сравнивать значения, применять универсальные функции NumPy к столбцам DataFrame.

import pandas as pd

df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})

df['C'] = df['A'] + df['B']  # Создание нового столбца, суммирующего A и B
df['A_squared'] = df['A'] ** 2 # Возведение в квадрат столбца A

Применение функций к столбцам DataFrame с помощью .apply() и векторизации

Метод .apply() позволяет применять функцию к каждой строке или столбцу DataFrame. Если возможно, Pandas автоматически векторизует операцию. Однако, если функция сложная и не поддается векторизации, .apply() может быть медленнее, чем другие методы.

import pandas as pd

def custom_function(x: int) -> int:
    """Пример пользовательской функции для применения к Series.

    Args:
        x: Значение элемента Series.

    Returns:
        Преобразованное значение.
    """
    return x * 2 + 1

df = pd.DataFrame({'A': [1, 2, 3]}) 
df['A_modified'] = df['A'].apply(custom_function) # Применение функции к столбцу A

Использование векторизованных строковых методов Pandas

Pandas предоставляет специальные строковые методы, доступные через .str, которые работают векторизованно. Это позволяет быстро выполнять операции над текстовыми данными.

import pandas as pd

df = pd.DataFrame({'Name': ['Alice', 'Bob', 'Charlie']})

df['Name_upper'] = df['Name'].str.upper() # Приведение к верхнему регистру
df['Name_length'] = df['Name'].str.len() # Вычисление длины строки

Векторизация при работе с датами и временем в Pandas

Pandas поддерживает векторизованные операции с датами и временем. Можно вычислять разницу между датами, извлекать компоненты даты (год, месяц, день) и т.д.

import pandas as pd

df = pd.DataFrame({'Date': ['2023-01-01', '2023-01-05', '2023-01-10']})
df['Date'] = pd.to_datetime(df['Date'])

df['Year'] = df['Date'].dt.year
df['Days_since_start'] = (df['Date'] - df['Date'].min()).dt.days

Продвинутые техники векторизации

Broadcasting: векторизованные операции с массивами разной формы

Broadcasting – это механизм, позволяющий NumPy выполнять операции над массивами разной формы. NumPy автоматически «растягивает» меньший массив до размера большего, чтобы соответствовать форме. Это позволяет, например, добавить скаляр к каждому элементу массива.

«`python
import numpy as np

arr = np.array([1, 2, 3])
scalar = 2

result = arr + scalar # scalar


Добавить комментарий