AEGIS Algorithms Android Angular API API Canvas AppSec Architecture Artificial Intelligence Astro Authentication AutoGPT AWS AWS Aurora AWS Boto3 AWS EC2 AWS Lambda Azure Backend bash Beautiful Soup Big Data Binary Tree Browser API Bun Charts ChatGPT Chrome Extension Clean Code CLI ClickHouse Coding Combine Compose Computer Context Fusion Cosmo Route CProgramming cron Cryptography CSS CTF Data science dbt dbt Cloud deno Detekt Development Distributed Systems Django Docker Docker Hub Drizzle DRY DuckDB FastAPI Flask Flutter For Beginners Front End Development Game Development GCN Geospatial GitHub Actions GitHub Pages Gitlab GMS Golang Google Google Sheets Google Wire GPT-3 GPT3 Gradle Grafana GraphQL gRPC Guidance HMS Huawei HuggingFace InfoSec Interview iOS Jackknife Java JavaScript Jetpack Compose JSON Kafka Kotlin Kubernetes LangChain Laravel Linux LLM Logging Machine Learning Magento Math Mermaid Micro Frontends Mobile mondayDB MongoDB Naming NestJS NET NetMock Networks NextJS NLP Node.js Nodejs OOP OpenAI Pandas PDF PHP Playwright Plotly Polars PostgreSQL Prefect Productivity Programming Prometheus Puppeteer Pushover Python Pytorch Rabbitmq Ramda Raspberry Pi React React Native Reactor Redis REST API Revolut RProgramming Ruby Rust Scalene ScyllaDB Selenium Sklearn SLO SnowFlake Snowkase Software Architecture Software Development Solara Solid Spring Boot SQL SQLite Streamlit SudoLang Swift SwiftUI Tailwind CSS Terraform Testing Transformers TypeScript Ubuntu UI Design Unix UX Vim VSCode Vue Web Components Web Development Web Frameworks Web Scraping Web-разработка Webassembly Websocket Whisper Widgets WordPress YAML YouTube Наука о данных Разное Тренды

Глубокое погружение в режим Copy-on-Write в pandas. Часть 3

Первая и вторая части статьи.

Введение

В настоящее время включенный по умолчанию режим CoW планируется внедрить в релиз pandas 3.0, запланированный на апрель 2024 года. В первой части данной серии мы рассказывали о поведении Copy-on-Write, а во второй  —  об оптимизациях производительности, связанных с Copy-on-Write.

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

Цепочечное присваивание

Цепочечное присваивание  —  это техника, при которой один объект обновляется посредством двух последовательных операций.

import pandas as pd
df = pd.DataFrame({"x": [1, 2, 3]})
df["x"][df["x"] > 1] = 100

Первая операция выбирает столбец "x", а вторая ограничивает количество строк. Существует множество различных комбинаций этих операций (например, в сочетании с loc и iloc). Впрочем, ни одна из этих комбинаций не будет работать при активированном CoW. Вместо того чтобы бездействовать, система просто выдаст предупреждение ChainedAssignmentError для удаления данных шаблонов.

В качестве замены можно использовать loc:

df.loc[df["x"] > 1, "x"] = 100

Первое измерение loc всегда соответствует row-indexer. Это означает, что можно выбрать подмножество строк. Второе измерение соответствует column-indexer, что позволяет выбрать подмножество столбцов.

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

Это случай, когда эффект от CoW очевиден. Способ также работает для оказания воздействия на цепочечные операции в памяти:

df["x"].replace(1, 100)

Шаблон такой же, как указано выше. Первой операцией является выбор столбца. Метод replace пытается оперировать с временным объектом, что не приведет к обновлению исходного объекта. Устранить эти шаблоны можно также достаточно просто, указав столбцы, с которыми необходимо проводить операции.

df = df.replace({"x": 1}, {"x": 100})

Шаблоны, которых следует избегать

В предыдущей части я рассказывал, как работает механизм CoW и каким образом DataFrame совместно располагают базовыми данными. Защитное копирование будет выполнено, если у двух объектов есть одни и те же данные при модификации одного объекта в памяти:

df2 = df.reset_index()
df2.iloc[0, 0] = 100

Операция reset_index создает представление базовых данных. Результат присваивается новой переменной df2. Таким образом, два объекта будут располагать общими данными. Это положение вещей сохраняется до тех пор, пока df не будет собран в мусор. Таким образом, операция setitem вызовет копирование. Это совершенно излишне, если исходный объект df вам больше не нужен. Простое переназначение той же переменной приведет к инвалидации ссылки, хранящейся в объекте.

df = df.reset_index()
df.iloc[0, 0] = 100

Резюмируя, можно сказать, что создание нескольких ссылок в одном и том же методе сохраняет ненужные ссылки.

Временные ссылки, образующиеся при объединении различных методов в цепочку, вполне допустимы.

df = df.reset_index().drop(...)

При этом сохраняется только одна ссылка.

Доступ к базовому массиву NumPy

В настоящее время pandas предоставляет доступ к базовому массиву NumPy через to_numpy или .values. Возвращаемый массив является копией, если DataFrame состоит из различных типов данных, например:

df = pd.DataFrame({"a": [1, 2], "b": [1.5, 2.5]})
df.to_numpy()
[[1. 1.5]
[2. 2.5]]

DataFrame поддерживается двумя массивами, которые необходимо объединить в один. Это запускает копирование.

Другой случай  —  DataFrame, который поддерживается только одним массивом NumPy. Например:

df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
df.to_numpy()
[[1 3]
[2 4]]

Мы можем напрямую обратиться к массиву и получить представление вместо копии. Это гораздо быстрее, чем копирование всех данных. Теперь мы имеем возможность оперировать с массивом NumPy и потенциально изменять его в памяти, что также приведет к обновлению DataFrame и, возможно, всех других DataFrame, имеющих общие данные. В режиме Copy-on-Write процедура становится гораздо сложнее, поскольку мы удалили множество защитных копий. Теперь куда большее число DataFrame будут совместно использовать память.

Поэтому to_numpy и .values вернут массив, доступный только для чтения. Таким образом, результирующий массив нельзя будет записать.

df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
arr = df.to_numpy()
arr[0, 0] = 1

Это запускает ValueError:

ValueError: assignment destination is read-only

Такой ситуации можно избежать двумя способами.

  • Запустите копирование вручную, если не хотите, чтобы обновлялись DataFrame, которые имеют общую память с массивом.
  • Сделайте массив доступным для записи. Это более производительное решение, но оно обходит правила Copy-on-Write, поэтому его следует использовать с осторожностью.
arr.flags.writeable = True

Бывают случаи, когда это невозможно. Чаще всего такое происходит, если вы обращаетесь к одному столбцу, который поддерживался PyArrow:

ser = pd.Series([1, 2], dtype="int64[pyarrow]")
arr = ser.to_numpy()
arr.flags.writeable = True

Возвращается ValueError:

ValueError: cannot set WRITEABLE flag to True of this array

Массивы Arrow неизменяемы, поэтому сделать массив NumPy доступным для записи не представляется возможным. В таком случае преобразование из Arrow в NumPy выполняется с нулевым копированием.

Заключение

Мы рассмотрели наиболее серьезные изменения, связанные с Copy-on-Write. Они станут поведением по умолчанию в pandas 3.0. Мы также рассказали, как можно адаптировать код, чтобы не допустить его поломки при включении режима Copy-on-Write. Если избегать указанных шаблонов, процесс обновления пройдет достаточно гладко.

Читайте также:

Читайте нас в Telegram, VK и Дзен

Перевод статьи Patrick Hoefler: Deep Dive into Pandas Copy-on-Write Mode — Part III

Сообщение Глубокое погружение в режим Copy-on-Write в pandas. Часть 3 появились сначала на NOP::Nuances of programming.

Похожие записи

AEGIS Algorithms Android Angular API API Canvas AppSec Architecture Artificial Intelligence Astro Authentication AutoGPT AWS AWS Aurora AWS Boto3 AWS EC2 AWS Lambda Azure Backend bash Beautiful Soup Big Data Binary Tree Browser API Bun Charts ChatGPT Chrome Extension Clean Code CLI ClickHouse Coding Combine Compose Computer Context Fusion Cosmo Route CProgramming cron Cryptography CSS CTF Data science dbt dbt Cloud deno Design Detekt Development Distributed Systems Django Docker Docker Hub Drizzle DRY DuckDB FastAPI Flask Flutter For Beginners Front End Development Game Development GCN Geospatial GitHub Actions GitHub Pages Gitlab GMS Golang Google Google Sheets Google Wire GPT-3 GPT3 Gradio Gradle Grafana GraphQL gRPC Guidance HMS HTML Huawei HuggingFace InfoSec Interview iOS Jackknife Java JavaScript Jetpack Compose JSON Kafka Kotlin Kubernetes LangChain Laravel Linux LlaMA LLM Logging Machine Learning Magento Math Mermaid Micro Frontends Mobile mondayDB MongoDB Naming NestJS NET NetMock Networks NextJS NLP Node.js Nodejs OOP OpenAI Pandas PDF PHP Playwright Plotly Polars PostgreSQL Prefect Productivity Programming Prometheus Puppeteer Pushover Python Pytorch Rabbitmq Ramda Raspberry Pi React React Native Reactor Redis REST API Revolut RProgramming Ruby Rust Scalene ScyllaDB Selenium Sklearn SLO SnowFlake Snowkase Software Architecture Software Development Solara Solid Spring Boot SQL SQLite Streamlit SudoLang Supabase Swift SwiftUI Tailwind CSS Terraform Testing Transformers TypeScript Ubuntu UI Design Unix UX Vim VSCode Vue Web Components Web Development Web Frameworks Web Scraping Web-разработка Webassembly Websocket Whisper Widgets WordPress YAML YouTube Наука о данных Разное Тренды

Сложные вопросы на собеседовании для тех, кто 7 лет работал с Java. Часть 1

Вы пропустили

AEGIS Algorithms Android Angular API API Canvas AppSec Architecture Artificial Intelligence Astro Authentication AutoGPT AWS AWS Aurora AWS Boto3 AWS EC2 AWS Lambda Azure Backend bash Beautiful Soup Big Data Binary Tree Browser API Bun Charts ChatGPT Chrome Extension Clean Code CLI ClickHouse Coding Combine Compose Computer Context Fusion Cosmo Route CProgramming cron Cryptography CSS CTF Data science dbt dbt Cloud deno Design Detekt Development Distributed Systems Django Docker Docker Hub Drizzle DRY DuckDB FastAPI Flask Flutter For Beginners Front End Development Game Development GCN Geospatial GitHub Actions GitHub Pages Gitlab GMS Golang Google Google Sheets Google Wire GPT-3 GPT3 Gradio Gradle Grafana GraphQL gRPC Guidance HMS HTML Huawei HuggingFace InfoSec Interview iOS Jackknife Java JavaScript Jetpack Compose JSON Kafka Kotlin Kubernetes LangChain Laravel Linux LlaMA LLM Logging Machine Learning Magento Math Mermaid Micro Frontends Mobile mondayDB MongoDB Naming NestJS NET NetMock Networks NextJS NLP Node.js Nodejs OOP OpenAI Pandas PDF PHP Playwright Plotly Polars PostgreSQL Prefect Productivity Programming Prometheus Puppeteer Pushover Python Pytorch Rabbitmq Ramda Raspberry Pi React React Native Reactor Redis REST API Revolut RProgramming Ruby Rust Scalene ScyllaDB Selenium Sklearn SLO SnowFlake Snowkase Software Architecture Software Development Solara Solid Spring Boot SQL SQLite Streamlit SudoLang Supabase Swift SwiftUI Tailwind CSS Terraform Testing Transformers TypeScript Ubuntu UI Design Unix UX Vim VSCode Vue Web Components Web Development Web Frameworks Web Scraping Web-разработка Webassembly Websocket Whisper Widgets WordPress YAML YouTube Наука о данных Разное Тренды

Сложные вопросы на собеседовании для тех, кто 7 лет работал с Java. Часть 1