Сообщить об ошибке.

Модуль pandas, анализ данных в Python

Инструменты анализа данных в Python

Библиотека pandas предоставляет быстрые, гибкие и выразительные структуры данных, которые делают работу с "реляционными" или "помеченными" данными простой и интуитивно понятной. Pandas призван стать фундаментальным строительным блоком высокого уровня для практического анализа реальных данных в Python.

Pandas хорошо подходит для разных типов данных:

  • Табличные данные со столбцами с разными типами, например, таблица SQL или электронная таблица Excel.
  • Упорядоченные и неупорядоченные (не обязательно с фиксированной частотой) данные временных рядов.
  • Произвольные матричные данные (однородно типизированные или неоднородные) с метками строк и столбцов.
  • Любая другая форма наборов наблюдательных/статистических данных. Данные вообще не нужно маркировать, чтобы поместить их в структуру данных pandas.

Две основные структуры данных, pandas.Series (1-мерная) и pandas.DataFrame (2-мерная), обрабатывают подавляющее большинство типичных случаев использования в финансах, статистике, социальных науках и многих областях техники. Библиотека pandas построена на базе NumPy и предназначена для хорошей интеграции в среду научных вычислений со многими другими сторонними библиотеками.

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

Установка pandas в виртуальное окружение:

Pandas можно установить через pip из PyPI.

# создаем виртуальное окружение, если нет
$ python3 -m venv .venv --prompt VirtualEnv
# активируем виртуальное окружение 
$ source .venv/bin/activate
# ставим модуль `pandas`
(VirtualEnv) Idea@Centre:~$ python3 -m pip install -U pandas

В Windows, рекомендуемый способ установки pandas с помощью Miniconda. Miniconda позволяет создать минимальную автономную установку Python и использовать менеджер пакетов Conda для установки дополнительных пакетов и создания виртуальной среды. Среда conda похожа на виртуальную среду, которая позволяет указать конкретную версию Python и набор библиотек.

# установка `pandas`
> conda create -c conda-forge -n name_env python pandas
# активация среды `conda`
> activate name_env

Для пользователей, которые не знакомы с Python, самый простой способ установить Python, pandas и пакеты, составляющие стек PyData (SciPy, NumPy, Matplotlib и другие), - это использовать кроссплатформенный дистрибутив Anaconda:

Содержание:

Основные структуры данных pandas

Так как многие "будущие" пользователи pandas в некоторой степени знакомы с программами для работы с электронными таблицами, такими как Excel (LibreOffice Calc), то по возможности здесь будут примеры того, как различные операции с электронными таблицами можно было бы выполнять с помощью pandas.

Перевод общей терминологии:

  • pandas.DataFrame - можно сравнить с рабочим листом электронных таблиц.
  • pandas.Series - можно сравнить со столбцом на рабочем листе электронных таблиц.
  • pandas.Index - можно сравнить с заголовками строк (числа строк в электронных таблицах).
  • значение NaN - можно сравнить с пустой ячейкой в электронных таблицах.

Объект pandas.DataFrame

Объект pandas.DataFrame представляет собой двумерную помеченную структуру данных со столбцами потенциально разных типов. Об этом объекте можно думать как об электронной таблице, таблице SQL или наборе объектов pandas.Series. Как правило, это наиболее часто используемый объект библиотеки pandas.

Объект pandas.Series

Объект pandas.Series - это одномерный помеченный массив, способный хранить данные любого типа (целые числа, строки, числа с плавающей запятой, объекты Python и т. д.). Метки осей в совокупности называются индексом. Другими словами, Series представляет один столбец DataFrame. Работа с серией аналогична ссылке на столбец электронной таблицы.

>>> import pandas as pd
>>> import numpy as np
>>> d = {"A": ['one', 'two', 'three'], 
         "B": [1, 2, 3]}
>>> df = pd.DataFrame(d)
>>> df
#        A  B
# 0    one  1
# 1    two  2
# 2  three  3

# извлечем столбец `A` и посмотрим его тип
>>> type(df['A'])
# <class 'pandas.core.series.Series'>

Объект pandas.Index

Каждый pandas.DataFrame и pandas.Series имеют индекс pandas.Index, который представляет собой метки строк данных. В pandas, если индекс не указан, то по умолчанию используется RangeIndex (первая строка = 0, вторая строка = 1 и т.д.), аналогично числам строк в электронных таблицах.

В pandas индексам можно задать одно (или несколько) уникальных значений, что похоже на использование столбца в качестве идентификатора строки на листе. В отличие от большинства электронных таблиц, эти значения индекса фактически можно использовать для ссылки на строки. Например, в электронных таблицах, ссылаться на первую строку можно как A1:Z1, а в pandas можно использовать DataFrame.loc[number_row].

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

>>> import pandas as pd
>>> import numpy as np
>>> df = pd.DataFrame({"col1": [1, 3, 5], "col2": [2, 4, 6]})
>>> df
#    col1  col2
# 0     1     2
# 1     3     4
# 2     5     6

Смотрим как можно взять набор данных из строки и из колонки:

# набор данных из второй строки
>>> df.loc[1]
# col1    3
# col2    4
# Name: 1, dtype: int64

# набор данных из второго столбца
>>> df['col2']
# 0    2
# 1    4
# 2    6
# Name: col2, dtype: int64

Значения индекса являются постоянными, следовательно, если изменить порядок строк в DataFrame, то метка конкретной строки не изменится.

Например, отсортируем значения первой колонки по убыванию и убедимся, что индексы в строках не поменялись:

# возможна сортировка данных по нескольким колонкам
>>> df.sort_values(by=['col1'], ascending=False)
#    col1  col2
# 2     5     6
# 1     3     4
# 0     1     2

Базовые операции Pandas в сравнении с Excel

Фрейм данных pandas может быть создан множеством различных способов, но для небольшого числа значений удобно указывать его как словарь Python, где ключами являются имена столбцов, а значениями - данные.

>>> import pandas as pd
>>> import numpy as np
>>> d = {
           "A": ['one', 'two', 'three', 'four', 'five'], 
           "B": [1, 2, 3, 4, 5], 
           "C": [0.1, 0.2, 0.3, 0.4, 0.5]
        }
>>> df = pd.DataFrame(d)
>>> df
#        A  B    C
# 0    one  1  0.1
# 1    two  2  0.2
# 2  three  3  0.3
# 3   four  4  0.4
# 4   five  5  0.5

Свойства DataFrame.index или DataFrame.columns отображает все индексы и столбцы соответственно:

>>> df.index
# RangeIndex(start=0, stop=5, step=1)
>>> df.columns
# Index(['A', 'B', 'C'], dtype='object')

Загрузка внешних данных и сохранение результатов в pandas

И Excel, и pandas могут импортировать данные из разных источников в разных форматах. Для работы с примерами загрузим и отобразим набор данных советов из тестов pandas, который представляет собой файл CSV. В Excel сначала необходимо скачать файл, а затем открыть как CSV. В pandas можно просто передать URL-адрес или локальный путь к CSV-файлу в метод pandas.read_csv():

url = (
    "https://raw.githubusercontent.com/pandas-dev"
    "/pandas/main/pandas/tests/io/data/csv/tips.csv"
)
>>> tips = pd.read_csv(url)
>>> tips
#      total_bill   tip     sex smoker   day    time  size
# 0         16.99  1.01  Female     No   Sun  Dinner     2
# 1         10.34  1.66    Male     No   Sun  Dinner     3
# 2         21.01  3.50    Male     No   Sun  Dinner     3
# 3         23.68  3.31    Male     No   Sun  Dinner     2
# 4         24.59  3.61  Female     No   Sun  Dinner     4
# ..          ...   ...     ...    ...   ...     ...   ...
# 239       29.03  5.92    Male     No   Sat  Dinner     3
# 240       27.18  2.00  Female    Yes   Sat  Dinner     2
# 241       22.67  2.00    Male    Yes   Sat  Dinner     2
# 242       17.82  1.75    Male     No   Sat  Dinner     2
# 243       18.78  3.00  Female     No  Thur  Dinner     2
# 
# [244 rows x 7 columns]

Как и мастер импорта данных Excel, метод pandas.read_csv() может принимать ряд аргументов, определяющих способ анализа данных. Например, если бы данные были разделены табуляцией и не имели имен столбцов, то команда pandas была бы такой:

# например данные разделены табуляцией
tips = pd.read_csv("tips.csv", sep="\t", header=None)

# метод `pandas.read_table` - это псевдоним для 
# `pandas.read_csv()` с разделителем табуляцией
tips = pd.read_table("tips.csv", header=None)

Excel открывает различные форматы файлов электронных таблиц, дважды щелкнув по нем или используя меню "Открыть". В pandas можно использовать специальные методы для чтения и записи в файлы Excel.

Например сохраним считанные данные в формате Excel

>>> tips.to_excel("./tips.xlsx", sheet_name="Лист1")

Файлы с расширением .xlsx будут записаны с использованием xlsxwriter (если доступно) или openpyxl. Если необходимо получить доступ к данным в файле Tips.xlsx, то можно считать их:

>>> pd.read_excel("./tips.xlsx", sheet_name="Лист1", index_col=0)

Отображение данных pandas

Программы для работы с электронными таблицами будут отображать данные только на экране и нет необходимости ограничивать вывод. В pandas дела обстоят немного по другому. По умолчанию pandas обрезает вывод больших фреймов данных и показывает несколько первых и последних строк. Такое поведение можно переопределить, используя метод DataFrame.head(n) для вывода на экран n первых строк или DataFrame.tail(n) последних строк. Для отрицательных значений n эти методы покажут строки, кроме первых/последних n строк в зависимости от метода.

# Отобразим первые 7 строк данных
>>> tips.head(7)
#    total_bill   tip     sex smoker  day    time  size
# 0       16.99  1.01  Female     No  Sun  Dinner     2
# 1       10.34  1.66    Male     No  Sun  Dinner     3
# 2       21.01  3.50    Male     No  Sun  Dinner     3
# 3       23.68  3.31    Male     No  Sun  Dinner     2
# 4       24.59  3.61  Female     No  Sun  Dinner     4
# 5       25.29  4.71    Male     No  Sun  Dinner     4
# 6        8.77  2.00    Male     No  Sun  Dinner     2

Метод DataFrame.info() даст представление о том, что содержит набор данных (название столбцов, количество строк, тип данных в строках и т.д.):

>>> tips.info()
# <class 'pandas.core.frame.DataFrame'>
# RangeIndex: 244 entries, 0 to 243
# Data columns (total 8 columns):
#  #   Column      Non-Null Count  Dtype  
# ---  ------      --------------  -----  
#  0   Unnamed: 0  244 non-null    int64  
#  1   total_bill  244 non-null    float64
#  2   tip         244 non-null    float64
#  3   sex         244 non-null    object 
#  4   smoker      244 non-null    object 
#  5   day         244 non-null    object 
#  6   time        244 non-null    object 
#  7   size        244 non-null    int64  
# dtypes: float64(2), int64(2), object(4)
# memory usage: 15.4+ KB

Метод DataFrame.describe() показывает краткую статистическую сводку данных:

>>> tips.describe()
#        total_bill         tip        size
# count  244.000000  244.000000  244.000000
# mean    19.785943    2.998279    2.569672
# std      8.902412    1.383638    0.951100
# min      3.070000    1.000000    1.000000
# 25%     13.347500    2.000000    2.000000
# 50%     17.795000    2.900000    2.000000
# 75%     24.127500    3.562500    3.000000
# max     50.810000   10.000000    6.000000

Метод DataFrame.mean() рассчитает среднее значение для столбца с числовым значением:

>>> tips[['total_bill', 'tip']].mean()
# total_bill    19.785943
# tip            2.998279
# dtype: float64

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

>>> tips[['total_bill', 'tip']].sum()
# total_bill    4339.77
# tip            731.58
# dtype: float64

Доступ и изменение данных в pandas

Информация об индексных метках осей в объектах pandas служит многим целям:

  • Идентифицирует данные (т. е. предоставляет метаданные) с использованием известных индикаторов, важных для анализа, визуализации и отображения на интерактивной консоли.
  • Обеспечивает автоматическое и явное выравнивание данных.
  • Позволяет интуитивно получать и настраивать подмножества набора данных.

Получение доступа к конкретному значению в DataFrame

Используемые понятия:

  • Индексная метка - это название столбца и название строки. Названия строк создаются при создании DataFrame при помощи аргумента index и могут быть, например, датами или строками. Если при создании DataFrame аргумент index не задан, то pandas автоматически создает метки строк, которые будут совпадать с их позицией.
  • Позиция - это индекс элемента в списке строк или столбцов.

Будем извлекать данные 2 строки столбца 'total_bill':

# медленный способ, но наиболее интуитивно понятный 
# использует индексные метки столбца и стоки соответственно
>>> tips['total_bill'][1]
# 10.34

# медленный способ использует индексную метку столбца 
# и метод `dict.values`, который принимает позицию строки
# (обратите внимание на скобки `.values[]`)
>>> tips['total_bill'].values[1]
# 10.34

# быстрый способ - использует индексные метки 
# строки и столбца соответственно
>>> tips.loc[1, 'total_bill']
# 10.34

# быстрый способ - использует позиции 
# строки и столбца соответственно
>>> tips.iloc[1, 0]
# 10.34

# самый быстрый способ использует индексные 
# метки строки и столбца соответственно
>>> tips.at[1, 'total_bill']
# 10.34

# самый быстрый способ - использует позиции 
# строки и столбца соответственно
>>> tips.iat[1, 0]
# 10.34

Описание методов:

  • Получение значение из ячейки DataFrame с помощью метода dict.values() - это встроенный метод словаря Python, который возвращает объект словаря view. Объект view содержит значения словаря в виде списка.
  • Метод DataFrame.loc[] обеспечивает доступ к группе строк и столбцов по индексным меткам строки и столбца в данном DataFrame.
  • Метод Dataframe.iloc[] обеспечивает доступ к группе строк и столбцов по позиции строки и столбца в DataFrame. Например, когда индексная метка фрейма данных отличается от числовой серии 0, 1, 2, 3….n или в случае, если пользователь не знает индексную метку.
  • Метод DataFrame.at[] обеспечивает доступ к конкретному значению ячейки по индексным меткам строки и столбца в данном DataFrame. Похож на Dataframe.loc[], только DataFrame.at[] возвращает одно значение и поэтому выполняется быстрее. Является предпочтительным при изменении данных в конкретной ячейке.
  • Метод DataFrame.iat[] обеспечивает доступ к конкретному значению ячейки по позиции строки и столбца в DataFrame. Похож на Dataframe.iloc[], только DataFrame.iat[] возвращает одно значение и поэтому выполняется быстрее. Является предпочтительным при изменении данных в конкретной ячейке.

Изменение данных конкретной ячейки DataFrame

Изменение данных конкретной ячейки DataFrame происходит простым присвоением:

# изменяем данные методом `DataFrame.at[]`
>>> tips.at[5, 'total_bill']
# 25.29
>>> tips.at[5, 'total_bill'] = tips.at[5, 'total_bill'] + 10
>>> tips.at[5, 'total_bill']
# 35.29

# изменяем данные методом `DataFrame.iat[]`
>>> tips.iat[6, 1]
# 2.0
>>> tips.iat[6, 0]
# 8.77
>>> tips.iat[6, 1] = tips.iat[6, 0] * tips.iat[6, 1]
>>> tips.iat[6, 1]
# 17.54

Получение доступа к набору/срезу данных DataFrame.

Основы индексации данных в pandas заключаются в следующем:

ОперацияСинтаксисРезультат
Выбор столбцовdf[`col`]Series
Выбор строк по индексным меткамdf.loc[label]Series
Выбор строки по позицииdf.iloc[loc]Series
Срез строк по позицииdf[5:10]DataFrame
Выбор строк по логическому векторуdf[bool_vec]DataFrame

Получение доступа к серии данных столбца по его индексной метке в DataFrame.

# набор данных 'total_bill' 
>>> tips['total_bill'].head()
# 0    16.99
# 1    10.34
# 2    21.01
# 3    23.68
# 4    24.59
# Name: total_bill, dtype: float64

Получение доступа к данным нескольких столбцов по их индексным меткам в DataFrame.

# данные столбцов 'total_bill' и  'size'
>>> tips[['total_bill','size']].head()
   total_bill  size
0       16.99     2
1       10.34     3
2       21.01     3
3       23.68     2
4       24.59     4

Получить доступ к данным нескольких строк в DataFrame можно указав срез строк внутри []:

>>> tips[5:11]
#     total_bill   tip   sex smoker  day    time  size
# 5        25.29  4.71  Male     No  Sun  Dinner     4
# 6         8.77  2.00  Male     No  Sun  Dinner     2
# 7        26.88  3.12  Male     No  Sun  Dinner     4
# 8        15.04  1.96  Male     No  Sun  Dinner     2
# 9        14.78  3.23  Male     No  Sun  Dinner     2
# 10       10.27  1.71  Male     No  Sun  Dinner     2

Здесь используется все преимущества срезов:

# выбираем каждую 5 строку
>>> tips[::5].head()
#     total_bill   tip     sex smoker  day    time  size
# 0        16.99  1.01  Female     No  Sun  Dinner     2
# 5        25.29  4.71    Male     No  Sun  Dinner     4
# 10       10.27  1.71    Male     No  Sun  Dinner     2
# 15       21.58  3.92    Male     No  Sun  Dinner     2
# 20       17.92  4.08    Male     No  Sat  Dinner     2

# разворачиваем строки
>>> tips[::-1].head()
#      total_bill   tip     sex smoker   day    time  size
# 243       18.78  3.00  Female     No  Thur  Dinner     2
# 242       17.82  1.75    Male     No   Sat  Dinner     2
# 241       22.67  2.00    Male    Yes   Sat  Dinner     2
# 240       27.18  2.00  Female    Yes   Sat  Dinner     2
# 239       29.03  5.92    Male     No   Sat  Dinner     3

Срез данных в pandas можно получить методами DataFrame.loc[] или DataFrame.iloc[].

Использование метода DataFrame.loc[]:

# получаем срез индексных меток строк с 5 по 10, 
# которые расположены в столбцах 'total_bill' и 'tip'
>>> tips.loc[5:10, ['total_bill', 'tip']]
#     total_bill    tip
# 5        35.29   4.71
# 6         8.77  17.54
# 7        26.88   3.12
# 8        15.04   1.96
# 9        14.78   3.23
# 10       10.27   1.71

# получаем срез индексных меток строк с 5 по 10, которые
# расположены в срезе индексных меток столбцов с 'tip' по 'smoker'
>>> tips.loc[5:10, 'tip':'smoker']
#       tip   sex smoker
# 5    4.71  Male     No
# 6   17.54  Male     No
# 7    3.12  Male     No
# 8    1.96  Male     No
# 9    3.23  Male     No
# 10   1.71  Male     No

Получаем тоже самое, только используя метод DataFrame.iloc[]:

# получаем срез данных по позиции строк и столбцов 
# в данном случае индексные метки строк совпадают с их позицией
>>> tips.iloc[5:11, 0:2]
#     total_bill    tip
# 5        35.29   4.71
# 6         8.77  17.54
# 7        26.88   3.12
# 8        15.04   1.96
# 9        14.78   3.23
# 10       10.27   1.71

# получаем срез индексных меток строк с 5 по 10, которые
# расположены в срезе индексных меток столбцов с 'tip' по 'smoker'
>>> tips.iloc[5:11, 1:4]
#       tip   sex smoker
# 5    4.71  Male     No
# 6   17.54  Male     No
# 7    3.12  Male     No
# 8    1.96  Male     No
# 9    3.23  Male     No
# 10   1.71  Male     No

Изменение серии данных, добавление новых столбцов

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

Библиотека pandas предоставляет векторизованные операции, указывая отдельные Series в DataFrame. Новые столбцы можно назначить таким же образом.

# изменяем данные столбца "total_bill"
>>> tips["total_bill"] = tips["total_bill"] - 2
# создаем новый столбец "new_bill" и вставляем 
# в него данные расчета `tips["total_bill"] / 2`
>>> tips["new_bill"] = tips["total_bill"] / 2
# смотрим изменения
>>> tips[['total_bill', 'new_bill']].head()
#      total_bill  new_bill
# 0         14.99     7.495
# 1          8.34     4.170
# 2         19.01     9.505
# 3         21.68    10.840
# 4         22.59    11.295

Обратите внимание, что НЕ НУЖНО указывать pandas выполнять вычитание по ячейкам, библиотека сделает это сама.

Изменение данных в pandas по условию

Метод .apply() предоставляется как объектом pandas.Series так и pandas.DataFrame.

Метод DataFrame.apply() применяет пользовательскую функцию вдоль оси axis (передается как аргумент) к каждой строке/столбцу DataFrame в зависимости от того что передается в axis (может принимать 0 или 'index', 1 или 'columns', по умолчанию 0).

Такой же метод есть у объекта Series.apply(), который не имеет аргумента axis в виду размерности 1d. Зато этот метод имеет общие (для обоих объектов) аргументы, которые в свою очередь принимают дополнительные аргументы для пользовательской функции: arg=() - позиционные в виде кортежа и **kwargs - ключевые аргументы в виде словаря.

Сама пользовательская функция по умолчанию принимает один аргумент значения столбца/строки, в зависимости от того что передается в axis. У объекта Series, функцией также может быть функция NumPy (например, numpy.sum()), которая применяется ко всей серии или функция Python, которая работает только с отдельными значениями.

Немного запутанно... Лучше посмотреть на примере. Изменять будем серию tips['total_bill'], значение умножаем на 10 если оно < 8:

# создадим серию, на основе которой потом проверим изменения
>>> s = tips[tips['total_bill'] < 8]['total_bill']
>>> s
# 67     3.07
# 92     5.75
# 111    7.25
# 149    7.51
# 172    7.25
# 195    7.56
# 218    7.74
# Name: total_bill, dtype: float64

# определим пользовательскую функцию, которая
# будет применяться к каждому элементу серии
def my_func(row):
    if row < 8:
        return row * 10
    return row

# изменяем `Series` простым присваиванием
>>> tips['total_bill'] = tips['total_bill'].apply(my_func)
# функцию можно записать как `lambda` - функцию
# tips['total_bill'] = tips['total_bill'].apply(lambda x: x*10 if x<8 else x)

# проверяем
>>> tips.loc[s.index, s.name]
# 67     30.7
# 92     57.5
# 111    72.5
# 149    75.1
# 172    72.5
# 195    75.6
# 218    77.4
# Name: total_bill, dtype: float64

Итерация по ячейкам среза DataFrame

Получаем срез необходимых данных (новый DataFrame), например, одним из вышеуказанных способов и сохраняем его в переменную:

>>> slice_tips = tips.iloc[100:106, 0:3]
>>> slice_tips
#      total_bill   tip     sex
# 100       11.35  2.50  Female
# 101       15.38  3.00  Female
# 102       44.30  2.50  Female
# 103       22.42  3.48  Female
# 104       20.92  4.08  Female
# 105       15.36  1.64    Male

Библиотека pandas индексирует как строки, так и столбцы DataFrame, а также и имеет атрибуты DataFrame.index и DataFrame.columns, которые содержат списки индексных меток строк и столбцов соответственно:

# смотрим индексные метки полученного `DataFrame`
>>> slice_tips.columns
# Index(['total_bill', 'tip', 'sex'], dtype='object')
>>> slice_tips.index
# RangeIndex(start=100, stop=106, step=1)

Располагая данной информацией можно легко пройтись по каждой ячейке полученного DataFrame:

# пройдемся построчно
for row in slice_tips.index:
    # извлекая данные из каждой колонки
    for col in slice_tips.columns:
        # получаем элемент среза данных и что-то
        # с ним делаем, например, можно изменить данные
        print(f'Строка: {row}, столбец {col}:', slice_tips.at[row, col])

# Строка: 100, столбец total_bill: 11.35
# Строка: 100, столбец tip: 2.5
# Строка: 100, столбец sex: Female
# Строка: 101, столбец total_bill: 15.38
# Строка: 101, столбец tip: 3.0
# Строка: 101, столбец sex: Female
# Строка: 102, столбец total_bill: 44.3
# Строка: 102, столбец tip: 2.5
# Строка: 102, столбец sex: Female
# Строка: 103, столбец total_bill: 22.42
# Строка: 103, столбец tip: 3.48
# Строка: 103, столбец sex: Female
# Строка: 104, столбец total_bill: 20.92
# Строка: 104, столбец tip: 4.08
# Строка: 104, столбец sex: Female
# Строка: 105, столбец total_bill: 15.36
# Строка: 105, столбец tip: 1.64
# Строка: 105, столбец sex: Male

Обратите внимание, что pandas.Series также имеет атрибуты Series.index, но не имеет атрибута .columns, т.к. серия содержит один столбец DataFrame.

>>> type(tips["total_bill"])
>>> tips["total_bill"].index
# RangeIndex(start=0, stop=244, step=1)

Отображение, удаление и переименования столбцов/строк в pandas

В электронных таблицах можно выбирать нужные столбцы следующим образом:

  • Скрытие столбцов
  • Удаление столбцов
  • Ссылка на диапазон с одного листа на другой

Так как названия столбцов электронной таблицы располагаются в первой строке, то переименование столбца - это просто изменение текста в первой ячейке столбца.

Те же операции представлены ниже для библиотеки pandes.

Отображение нескольких столбцов в pandas

Отображаем, а при необходимости можно сохранить определенные столбцы в новый DataFrame, а затем записать в результирующий файл.

# например, отобразим определенные столбцы
>>> tips[["sex", "total_bill", "tip"]].head()
#       sex  total_bill   tip
# 0  Female       14.99  1.01
# 1    Male        8.34  1.66
# 2    Male       19.01  3.50
# 3    Male       21.68  3.31
# 4  Female       22.59  3.61

# Отобразим столбцы срезом позиции
>>> tips[tips.columns[0:5]].head()
#    total_bill   tip     sex smoker  day
# 0       16.99  1.01  Female     No  Sun
# 1       10.34  1.66    Male     No  Sun
# 2       21.01  3.50    Male     No  Sun
# 3       23.68  3.31    Male     No  Sun
# 4       24.59  3.61  Female     No  Sun

Удаление одного или нескольких столбцов в pandas

# удаление одного столбца по индексной метке
>>> tips = tips.drop(columns="months_between")

# удаление нескольких столбцов по индексным меткам
>>> tips = tips.drop(columns=["date1_next", "date2_month", "date1_year", "bucket"])

# удаление нескольких столбцов по срезу позиции
# получим названия колонок в заданных позициях 
>>> tips.columns[5:7]
# Index(['time', 'size'], dtype='object')

# подставляем данные в метод `DataFrame.drop`
# tips.drop(columns=tips.columns[5:7])

Обратите внимание, что для сохранения результата необходимо пересохранить DataFrame в переменную tips или создать новую.

Переименование столбца в pandas

# переименование одного столбца
>>> tips = tips.rename(columns={"new_bill": "total_bill_2"})
# переименование нескольких столбцов
>>> tips = tips.rename(columns={"date1": "dt1", "date2": "dt2"})
>>> tips.head()
#      total_bill   tip     sex smoker   day    time  size  total_bill_2        dt1        dt2
# 0         14.99  1.01  Female     No   Sun  Dinner     2         7.495 2023-01-15 2024-02-15
# 1          8.34  1.66    Male     No   Sun  Dinner     3         4.170 2023-01-15 2024-02-15
# 2         19.01  3.50    Male     No   Sun  Dinner     3         9.505 2023-01-15 2024-02-15
# 3         21.68  3.31    Male     No   Sun  Dinner     2        10.840 2023-01-15 2024-02-15
# 4         22.59  3.61  Female     No   Sun  Dinner     4        11.295 2023-01-15 2024-02-15

Обратите внимание, что для сохранения результата необходимо пересохранить DataFrame в переменную tips или создать новую.

Удаление строк в pandas

Удаление строк по индексным меткам:

# удаление конкретной строки по индексной метке
>>> tips = tips.drop(index=15)
# можно видеть, что 15 строки нет
>>> tips.loc[14:16, 'tip']
# 14    3.02
# 16    1.67
# Name: tip, dtype: float64

# удаление нескольких строк по меткам
>>> tips = tips.drop(index=[16, 20, 21])
>>> tips.loc[14:22, 'tip']
# 14    3.02
# 17    3.71
# 18    3.50
# 19    3.35
# 22    2.23
# Name: tip, dtype: float64

Удаление строк срезом позиций (не индексных меток):

>>> tips = tips.drop(tips.index[15:20])
>>> tips.iloc[14:17, 0:2]
#     total_bill   tip
# 14       14.83  3.02
# 24       19.82  3.18
# 25       17.81  2.34

Обратите внимание, что для сохранения результата необходимо пересохранить DataFrame в переменную tips или создать новую.

Добавление строк в конец pandas.DataFrame

Предполагая, что в качестве индекса используется RangeIndex (с номерами 0, 1 и т. д.), можно использовать функцию pandas.concat() для добавления строки в нижнюю часть DataFrame.

# создаем строку с данными
>>> new_row = pd.DataFrame([["E", 51, True]],
...                        columns=["class", "student_count", "all_pass"])

# добавляем
>>> pd.concat([df, new_row])
#   class  student_count all_pass
# 0     A             42      Yes
# 1     A             35      Yes
# 2     A             42      Yes
# 3     B             50       No
# 4     C             47       No
# 5     D             45      Yes
# 0     E             51     True

Обратите внимание, что для сохранения результата необходимо пересохранить DataFrame в переменную tips или создать новую.

Отбор и фильтрация данных в pandas

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

>>> tips[tips["total_bill"] > 10].head()
#    total_bill   tip     sex smoker  day    time  size  new_bill
# 0       14.99  1.01  Female     No  Sun  Dinner     2     7.495
# 2       19.01  3.50    Male     No  Sun  Dinner     3     9.505
# 3       21.68  3.31    Male     No  Sun  Dinner     2    10.840
# 4       22.59  3.61  Female     No  Sun  Dinner     4    11.295
# 5       23.29  4.71    Male     No  Sun  Dinner     4    11.645

Приведенный выше оператор просто передает DataFrame серию объектов True/False, отбирая и возвращая все строки с True.

Для комбинации нескольких условий pandas использует & (И), | (ИЛИ) и ~ (НЕ):

>>> tips[(tips["total_bill"] > 10) & (tips["sex"] == "Male")].head()
#    total_bill   tip   sex smoker  day    time  size
# 1       10.34  1.66  Male     No  Sun  Dinner     3
# 2       21.01  3.50  Male     No  Sun  Dinner     3
# 3       23.68  3.31  Male     No  Sun  Dinner     2
# 5       25.29  4.71  Male     No  Sun  Dinner     4
# 7       26.88  3.12  Male     No  Sun  Dinner     4

# для получения среза добавим в конец выражения необходимый метод 
>>> tips[(tips["total_bill"] > 10) & (tips["sex"] == "Male")].loc[100:106, ['total_bill', 'tip']]
#      total_bill   tip
# 105       15.36  1.64
# 106       20.49  4.06

Логические операции If/then над данными в pandas

Допустим, необходимо создать создать столбец сегмента со значениями low и high в зависимости от того, составляет ли total_bill меньше или больше 10.

В электронных таблицах логическое сравнение можно выполнять с помощью условных формул. То есть в Excel используют формулу =IF(A2 < 10, "low", "high"), которую необходимо перетащить на все ячейки в новом столбце bucket.

Ту же операцию в pandas можно выполнить, используя метод .where() из numpy.

>>> tips["bucket"] = np.where(tips["total_bill"] < 10, "low", "high")
# отображаем нужные столбцы
>>> tips[['total_bill', 'bucket']].head()
#    total_bill bucket
# 0       14.99   high
# 1        8.34    low
# 2       19.01   high
# 3       21.68   high
# 4       22.59   high

Работа с датами в pandas

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

Функциональность даты можно разделить на две части: синтаксический анализ и вывод. В электронных таблицах значения дат обычно анализируются автоматически, хотя, если необходимо, есть функция DATEVALUE. В pandas необходимо явно преобразовать обычный текст в объекты datetime либо при чтении из CSV, либо один раз в DataFrame.

После анализа, электронные таблицы отображают даты в формате по умолчанию, хотя формат можно изменить. В pandas, обычно нужно сохранять даты как объекты datetime, пока выполняются вычисления с ними. Вывод частей дат (например, года) в электронных таблицах осуществляется с помощью функций даты, а в pandas свойствами datetime.

# добавляем в `DataFrame` новые столбцы с датами
>>> tips["date1"] = pd.Timestamp("2023-01-15")
>>> tips["date2"] = pd.Timestamp("2024-02-15")
# добавляем столбец со значением года
>>> tips["date1_year"] = tips["date1"].dt.year
# добавляем столбец со значением месяца
>>> tips["date2_month"] = tips["date2"].dt.month
# добавляем столбец с датой начала следующего месяца
# (дата начала предыдущего месяца вычисляется знаком `-`)
>>> tips["date1_next"] = tips["date1"] + pd.offsets.MonthBegin()
# добавляем столбец с периодом
>>> tips["months_between"] = (tips["date2"].dt.to_period("M") - 
...                           tips["date1"].dt.to_period("M"))
# отображаем нужные столбцы
>>> tips[["date1", "date2", "date1_year", 
...      "date2_month", "date1_next", "months_between"]].head()
#        date1      date2  date1_year  date2_month date1_next    months_between
# 0 2023-01-15 2024-02-15        2023            2 2023-02-01  <13 * MonthEnds>
# 1 2023-01-15 2024-02-15        2023            2 2023-02-01  <13 * MonthEnds>
# 2 2023-01-15 2024-02-15        2023            2 2023-02-01  <13 * MonthEnds>
# 3 2023-01-15 2024-02-15        2023            2 2023-02-01  <13 * MonthEnds>
# 4 2023-01-15 2024-02-15        2023            2 2023-02-01  <13 * MonthEnds>

Дополнительные сведения смотрите в разделе "Доступ к методам datetime объектов Series/index в pandas".

Сортировка данных в pandas

Сортировка в электронных таблицах осуществляется через диалог сортировки. В pandas есть метод DataFrame.sort_values(), который принимает список столбцов для сортировки.

>>> tips = tips.sort_values(["sex", "total_bill"])
>>> tips[['total_bill', 'tip', 'sex']].head()
#      total_bill   tip     sex
# 67         1.07  1.00  Female
# 92         3.75  1.00  Female
# 111        5.25  1.00  Female
# 145        6.35  1.50  Female
# 135        6.51  1.25  Female

Обратите внимание, что отсортировать по убыванию можно передав ключевой аргумент ascending=False. Для сортировки данных по индексу (номерам строк) используйте метод DataFrame.sort_index().

Обработка строк в pandas

Находим длину строки в pandas

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

=LEN(TRIM(A2))

В pandas можно узнать длину строки символов с помощью Series.str.len(). В Python 3 все строки являются строками Unicode. Функция len() включает конечные пробелы. Чтобы исключить из подсчета пробелы, нужно дополнительно применить к строке функцию str.strip(). В итоге вызов получиться следующий Series.str.strip().str.len().

>>> tips["time"].str.strip().str.len().head()
# 67     6
# 92     6
# 111    6
# 145    5
# 135    5
# Name: time, dtype: int64

Поиск позиции подстроки в строке в pandas

Функция электронной таблицы FIND возвращает позицию подстроки, первый символ которой равен 1.

В pandas можно найти позицию символа в столбце строк с помощью метода Series.str.find(). Метод str.find() ищет первую позицию подстроки. Если подстрока найдена, то метод возвращает ее позицию. Если не найден, возвращается -1. Имейте в виду, что индексы Python начинаются с нуля.

>>> tips["sex"].str.find("ale")
>>> tips["sex"].str.find("ale")
# 67     3
# 92     3
# 111    3
# 145    3
# 135    3
#       ..
# 182    1
# 156    1
# 59     1
# 212    1
# 170    1
# Name: sex, Length: 244, dtype: int64

Извлечение подстроки по позиции в pandas

В электронных таблицах есть формула MID для извлечения подстроки из заданной позиции. Чтобы получить первый символ:

=MID(A2,1,1)

С помощью pandas можно использовать нотацию среза [] для извлечения подстроки из строки по местоположениям. Имейте в виду, что индексы Python начинаются с нуля.

>>> tips["sex"].str[0:1]
# 67     F
# 92     F
# 111    F
# 145    F
# 135    F
#       ..
# 182    M
# 156    M
# 59     M
# 212    M
# 170    M
# Name: sex, Length: 244, dtype: object

Извлечение N-го слова каждой строки для получения определенного столбца в pandas

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

Самый простой способ извлечь слова в pandas - разделить строки пробелами, а затем ссылаться на слово по индексу. Обратите внимание, что есть более мощные подходы.

# создадим `DataFrame`
>>> firstlast = pd.DataFrame({"String": ["John Smith", "Jane Cook"]})
>>> firstlast
#        String
# 0  John Smith
# 1   Jane Cook

# добавляем столбец "First_Name"
>>> firstlast["First_Name"] = firstlast["String"].str.split(" ", expand=True)[0]
# добавляем столбец "Last_Name"
>>> firstlast["Last_Name"] = firstlast["String"].str.rsplit(" ", expand=True)[1]
>>> firstlast
#        String First_Name Last_Name
# 0  John Smith       John     Smith
# 1   Jane Cook       Jane      Cook

Изменение регистра строки в pandas

В электронных таблицах предусмотрены функции UPPER, LOWER и PROPER для преобразования текста в верхний, нижний регистр и регистр заголовка соответственно.

Эквивалентными методами pandas являются Series.str.upper(), Series.str.lower() и Series.str.title().

>>> firstlast = pd.DataFrame({"string": ["John Smith", "Jane Cook"]})
>>> firstlast
#        string
# 0  John Smith
# 1   Jane Cook

# добавляем соответствующие столбцы с измененными данными
>>> firstlast["upper"] = firstlast["string"].str.upper()
>>> firstlast["lower"] = firstlast["string"].str.lower()
>>> firstlast["title"] = firstlast["string"].str.title()
>>> firstlast
#         string       upper       lower       title
# 0  John Smith  JOHN SMITH  john smith  John Smith
# 1   Jane Cook   JANE COOK   jane cook   Jane Cook

Слияние таблиц в pandas

В примерах слияния будут использоваться следующие таблицы:

>>> df1 = pd.DataFrame({"key": ["A", "B", "C", "D"], "value": np.random.randn(4)})
>>> df1
#   key     value
# 0   A  0.872520
# 1   B  0.659742
# 2   C  1.423087
# 3   D -1.676140
>>> df2 = pd.DataFrame({"key": ["B", "D", "D", "E"], "value": np.random.randn(4)})
>>> df2
#   key     value
# 0   B  0.255974
# 1   D -0.377506
# 2   D -0.164284
# 3   E  0.125792

В Excel объединение таблиц можно выполнить с помощью VLOOKUP.

Фреймы данных pandas имеют метод DataFrame.merge(), который обеспечивает аналогичную функциональность. Данные не нужно сортировать заранее, а различные типы соединений выполняются с помощью ключевого аргумента how.

>>> inner_join = df1.merge(df2, on=["key"], how="inner")
>>> inner_join
#   key   value_x   value_y
# 0   B  0.659742  0.255974
# 1   D -1.676140 -0.377506
# 2   D -1.676140 -0.164284
>>> left_join = df1.merge(df2, on=["key"], how="left")
>>> left_join
#   key   value_x   value_y
# 0   A  0.872520       NaN
# 1   B  0.659742  0.255974
# 2   C  1.423087       NaN
# 3   D -1.676140 -0.377506
# 4   D -1.676140 -0.164284
>>> right_join = df1.merge(df2, on=["key"], how="right")
>>> right_join
  key   value_x   value_y
# 0   B  0.659742  0.255974
# 1   D -1.676140 -0.377506
# 2   D -1.676140 -0.164284
# 3   E       NaN  0.125792
>>> outer_join = df1.merge(df2, on=["key"], how="outer")
>>> outer_join
#   key   value_x   value_y
# 0   A  0.872520       NaN
# 1   B  0.659742  0.255974
# 2   C  1.423087       NaN
# 3   D -1.676140 -0.377506
# 4   D -1.676140 -0.164284
# 5   E       NaN  0.125792

Слияние в pandas имеет ряд преимуществ перед VLOOKUP:

  • Искомое значение не обязательно должно быть первым столбцом таблицы поиска.
  • Если сопоставлено несколько строк, для каждого совпадения будет одна строка, а не только первая.
  • Итоговый DataFrame будет включать все столбцы из таблицы поиска, а не только один указанный столбец
  • DataFrame поддерживает более сложные операции объединения

Сводные таблицы в pandas

Сводные таблицы из электронных таблиц могут быть воспроизведены в pandas с помощью изменения формы и метода DataFrame.pivot_table(). Возьмем за основу ранее используемый фрейм данных tips и найдем среднее значение столбца tip в зависимости от размера size и пола sex.

>>> tips[['tip', 'sex', 'size']]
#        tip     sex  size
# 67    1.00  Female     1
# 92    1.00  Female     2
# 111   1.00  Female     1
# 145   1.50  Female     2
# 135   1.25  Female     2
# ..     ...     ...   ...
# 182   3.50    Male     3
# 156   5.00    Male     6
# 59    6.73    Male     4
# 212   9.00    Male     4
# 170  10.00    Male     3

# создаем сводную таблицу 
>>> table = pd.pivot_table(
...     tips, values="tip", index=["size"], columns=["sex"], aggfunc=np.average
... )
>>> table
# sex     Female      Male
# size                    
# 1     1.276667  1.920000
# 2     2.528448  2.614184
# 3     3.250000  3.476667
# 4     4.021111  4.172143
# 5     5.140000  3.750000
# 6     4.600000  5.850000

Для сохранения сводной таблицы, присвойте полученный вывод переменной Python.

Удаление повторяющихся значений в pandas

Excel имеет встроенную функцию удаления повторяющихся значений. В pandas это поддерживается через DataFrame.drop_duplicated().

>>> df = pd.DataFrame(
...     {
...         "class": ["A", "A", "A", "B", "C", "D"],
...         "student_count": [42, 35, 42, 50, 47, 45],
...         "all_pass": ["Yes", "Yes", "Yes", "No", "No", "Yes"],
...     }
... )

# удаление дубликатов строк
>>> df.drop_duplicates()
#   class  student_count all_pass
# 0     A             42      Yes
# 1     A             35      Yes
# 3     B             50       No
# 4     C             47       No
# 5     D             45      Yes

# удаление строк с дублирующими записями в определенных столбцах
>>> df.drop_duplicates(["class", "student_count"])
#   class  student_count all_pass
# 0     A             42      Yes
# 1     A             35      Yes
# 3     B             50       No
# 4     C             47       No
# 5     D             45      Yes

Поиск и замена данных в pandas

Диалоговое окно поиска в Excel приведет вас к соответствующим ячейкам, одну за другой. В pandas эта операция обычно выполняется сразу для всего столбца или DataFrame с помощью условных выражений.

>>> tips.head()
#      total_bill   tip     sex smoker   day    time  size  total_bill_2        dt1        dt2
# 67         1.07  1.00  Female    Yes   Sat  Dinner     1         0.535 2023-01-15 2024-02-15
# 92         3.75  1.00  Female    Yes   Fri  Dinner     2         1.875 2023-01-15 2024-02-15
# 111        5.25  1.00  Female     No   Sat  Dinner     1         2.625 2023-01-15 2024-02-15
# 145        6.35  1.50  Female     No  Thur   Lunch     2         3.175 2023-01-15 2024-02-15
# 135        6.51  1.25  Female     No  Thur   Lunch     2         3.255 2023-01-15 2024-02-15

# поиск во всем `DataFrame`
>>> (tips == "Sat").head()
#      total_bill    tip    sex  smoker    day   time   size  total_bill_2    dt1    dt2
# 67        False  False  False   False   True  False  False         False  False  False
# 92        False  False  False   False  False  False  False         False  False  False
# 111       False  False  False   False   True  False  False         False  False  False
# 145       False  False  False   False  False  False  False         False  False  False
# 135       False  False  False   False  False  False  False         False  False  False

# поиск в определенном столбце
>>> tips["day"].str.contains("S").head()
# 67      True
# 92     False
# 111     True
# 145    False
# 135    False

Замена данных в определенном столбце

>>> tips["smoker"] = tips["smoker"].str.replace("Yes", "---")
>>> tips.head()
#      total_bill   tip     sex smoker   day    time  size  total_bill_2        dt1        dt2
# 67         1.07  1.00  Female    ---   Sat  Dinner     1         0.535 2023-01-15 2024-02-15
# 92         3.75  1.00  Female    ---   Fri  Dinner     2         1.875 2023-01-15 2024-02-15
# 111        5.25  1.00  Female     No   Sat  Dinner     1         2.625 2023-01-15 2024-02-15
# 145        6.35  1.50  Female     No  Thur   Lunch     2         3.175 2023-01-15 2024-02-15
# 135        6.51  1.25  Female     No  Thur   Lunch     2         3.255 2023-01-15 2024-02-15

Метод DataFrame.replace() в pandas сравним с функцией Excel "Заменить все".

>>> tips.replace("Thur", "---").head()
#      total_bill   tip     sex smoker  day    time  size  total_bill_2        dt1        dt2
# 67         1.07  1.00  Female    Yes  Sat  Dinner     1         0.535 2023-01-15 2024-02-15
# 92         3.75  1.00  Female    Yes  Fri  Dinner     2         1.875 2023-01-15 2024-02-15
# 111        5.25  1.00  Female     No  Sat  Dinner     1         2.625 2023-01-15 2024-02-15
# 145        6.35  1.50  Female     No  ---   Lunch     2         3.175 2023-01-15 2024-02-15
# 135        6.51  1.25  Female     No  ---   Lunch     2         3.255 2023-01-15 2024-02-15

Числа по заданному шаблону в определенном наборе ячеек в pandas

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

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

# создадим `DataFrame`
>>> df = pd.DataFrame({"AAA": [1] * 8, "BBB": list(range(0, 8))})
>>> df
#    AAA  BBB
# 0    1    0
# 1    1    1
# 2    1    2
# 3    1    3
# 4    1    4
# 5    1    5
# 6    1    6
# 7    1    7

# создадим список 
>>> lst = list(range(1, 5))
>>> lst
# [1, 2, 3, 4]

# присвоим список срезу столбца "AAA"
>>> df.loc[2:5, "AAA"] = lst
>>> df
#    AAA  BBB
# 0    1    0
# 1    1    1
# 2    1    2
# 3    2    3
# 4    3    4
# 5    4    5
# 6    1    6
# 7    1    7

О важности индексации в pandas

Если создать индексированную серию pandas.Series, то при ее вставке pandas будет сверять индексы строк столбца DataFrame с индексами созданной серии, при этом данные с совпавшими индексами будут заменены на данные из серии, а данные с не совпавшими индексами будут потеряны. Другими словами произойдет выравнивание индексов. Смотрим на примере:

>>> df = pd.DataFrame({"AAA": [1] * 8, "BBB": list(range(0, 8))})
>>> df
#    AAA  BBB
# 0    1    0
# 1    1    1
# 2    1    2
# 3    1    3
# 4    1    4
# 5    1    5
# 6    1    6
# 7    1    7

# создадим индексированную Series 
# (обратите внимание на индексы серии)
>>> s = pd.Series(range(1, 5))
>>> s
# 0    1
# 1    2
# 2    3
# 3    4
# dtype: int64

# вставлять будем в срез столбца `DataFrame`
# (обратите внимание на индексы серии столбца)
>>> df.loc[2:5, "AAA"]
# 2    1
# 3    2
# 4    3
# 5    4
# Name: AAA, dtype: int64

# присвоим серию срезу столбца "AAA"
>>> df.loc[2:5, "AAA"] = s
>>> df
#    AAA  BBB
# 0  1.0  0.0
# 1  1.0  1.0
# 2  3.0  2.0
# 3  4.0  3.0
# 4  NaN  4.0
# 5  NaN  5.0
# 6  1.0  6.0
# 7  1.0  7.0

Что произошло? При изменении данных pandas проверил индексы серии столбца df.loc[2:5, "AAA"] и индексы созданной серии s, данные с совпавшими индексами (2 и 3) в DataFrame изменились, данные в индексах (4 и 5) считаются потерянными (таких индексов во вставляемой серии нет).

Что бы достичь первого результата (смотри выше) необходимо создать Series с одинаковыми индексами или вставить просто массив значений серии Series.values без индексов:

>>> df = pd.DataFrame({"AAA": [1] * 8, "BBB": list(range(0, 8))})

# создадим индексированную Series 
# (обратите внимание на индексы серии)
>>> s = pd.Series(range(1, 5), index=list(range(2, 6)))
>>> s
# 2    1
# 3    2
# 4    3
# 5    4
# dtype: int64

# присвоим серию срезу столбца "AAA"
>>> df.loc[2:5, "AAA"] = s
>>> df
#    AAA  BBB
# 0    1    0
# 1    1    1
# 2    1    2
# 3    2    3
# 4    3    4
# 5    4    5
# 6    1    6
# 7    1    7

# массив значений серии без индексов
>>> s.values
# array([1, 2, 3, 4])

Теперь индексы в обоих сериях совпали и потерь данных нет.