Ядром pandas являются две структуры данных, в которых происходят все операции:
- Series
- Dataframes
Series — это структура, используемая для работы с последовательностью одномерных данных, а Dataframe — более сложная и подходит для нескольких измерений.
Пусть они и не являются универсальными для решения всех проблем, предоставляют отличный инструмент для большинства приложений. При этом их легко использовать, а множество более сложных структур можно упросить до одной из этих двух.
Однако особенности этих структур основаны на одной черте — интеграции в их структуру объектов index и labels (метки). С их помощью структурами становится очень легко манипулировать.
Series (серии)
Series — это объект библиотеки pandas, спроектированный для представления одномерных структур данных, похожих на массивы, но с дополнительными возможностями. Его структура проста, ведь он состоит из двух связанных между собой массивов. Основной содержит данные (данные любого типа NumPy), а в дополнительном, index, хранятся метки.
Создание объекта Series
Для создания объекта Series с предыдущего изображения необходимо вызвать конструктор Series() и передать в качестве аргумента массив, содержащий значения, которые необходимо включить.
>>> s = pd.Series([12,-4,7,9])
>>> s
0 12
1 -4
2 7
3 9
dtype: int64
Как можно увидеть по выводу, слева отображаются значения индексов, а справа — сами значения (данные).
Если не определить индекс при объявлении объекта, метки будут соответствовать индексам (положению в массиве) элементов объекта Series.
Однако лучше создавать Series, используя метки с неким смыслом, чтобы в будущем отделять и идентифицировать данные вне зависимости от того, в каком порядке они хранятся.
В таком случае необходимо будет при вызове конструктора включить параметр index и присвоить ему массив строк с метками.
>>> s = pd.Series([12,-4,7,9], index=['a','b','c','d'])
>>> s
a 12
b -4
c 7
d 9
dtype: int64
Если необходимо увидеть оба массива, из которых состоит структура, можно вызвать два атрибута: index и values.
>>> s.values
array([12, -4, 7, 9], dtype=int64)
>>> s.index
Index(['a', 'b', 'c', 'd'], dtype='object')
Выбор элементов по индексу или метке
Выбирать отдельные элементы можно по принципу обычных массивов numpy, используя для этого индекс.
>>> s[2]
7
Или же можно выбрать метку, соответствующую положению индекса.
>>> s['b']
-4
Таким же образом можно выбрать несколько элементов массива numpy с помощью следующей команды:
>>> s[0:2]
a 12
b -4
dtype: int64
В этом случае можно использовать соответствующие метки, но указать их список в массиве.
>>> s[['b','c']]
b -4
c 7
dtype: int64
Присваивание значений элементам
Понимая как выбирать отдельные элементы, важно знать и то, как присваивать им новые значения. Можно делать это по индексу или по метке.
>>> s[1] = 0
>>> s
a 12
b 0
c 7
d 9
dtype: int64
>>> s['b'] = 1
>>> s
a 12
b 1
c 7
d 9
dtype: int64
Создание Series из массивов NumPy
Новый объект Series можно создать из массивов NumPy и уже существующих Series.
>>> arr = np.array([1,2,3,4])
>>> s3 = pd.Series(arr)
>>> s3
0 1
1 2
2 3
3 4
dtype: int32
>>> s4 = pd.Series(s)
>>> s4
a 12
b 1
c 7
d 9
dtype: int64
Важно запомнить, что значения в массиве NumPy или оригинальном объекте Series не копируются, а передаются по ссылке. Это значит, что элементы объекта вставляются динамически в новый Series. Если меняется оригинальный объект, то меняются и его значения в новом.
>>> s3
0 1
1 2
2 3
3 4
dtype: int32
>>> arr[2] = -2
>>> s3
0 1
1 2
2 -2
3 4
dtype: int32
На этом примере можно увидеть, что при изменении третьего элемента массива arr, меняется соответствующий элемент и в s3.
Фильтрация значений
Благодаря тому что основной библиотекой в pandas является NumPy, многие операции, применяемые к массивам NumPy, могут быть использованы и в случае с Series. Одна из таких — фильтрация значений в структуре данных с помощью условий.
Например, если нужно узнать, какие элементы в Series больше 8, то можно написать следующее:
>>> s[s > 8]
a 12
d 9
dtype: int64
Операции и математические функции
Другие операции, такие как операторы (+, -, * и /), а также математические функции, работающие с массивами NumPy, могут использоваться и для Series.
Для операторов можно написать простое арифметическое уравнение.
>>> s / 2
a 6.0
b 0.5
c 3.5
d 4.5
dtype: float64
Но в случае с математическими функциями NumPy необходимо указать функцию через np, а Series передать в качестве аргумента.
>>> np.log(s)
a 2.484907
b 0.000000
c 1.945910
d 2.197225
dtype: float64
Количество значений
В Series часто встречаются повторения значений. Поэтому важно иметь информацию, которая бы указывала на то, есть ли дубликаты или конкретное значение в объекте.
Так, можно объявить Series, в котором будут повторяющиеся значения.
>>> serd = pd.Series([1,0,2,1,2,3], index=['white','white','blue','green',' green','yellow'])
>>> serd
white 1
white 0
blue 2
green 1
green 2
yellow 3
dtype: int64
Чтобы узнать обо всех значениях в Series, не включая дубли, можно использовать функцию unique(). Возвращаемое значение — массив с уникальными значениями, необязательно в том же порядке.
>>> serd.unique()
array([1, 0, 2, 3], dtype=int64)
На unique() похожа функция value_counts(), которая возвращает не только уникальное значение, но и показывает, как часто элементы встречаются в Series.
>>> serd.value_counts()
2 2
1 2
3 1
0 1
dtype: int64
Наконец, isin() показывает, есть ли элементы на основе списка значений. Она возвращает булевые значения, которые очень полезны при фильтрации данных в Series или в колонке Dataframe.
>>> serd.isin([0,3])
white False
white True
blue False
green False
green False
yellow True
dtype: bool
>>> serd[serd.isin([0,3])]
white 0
yellow 3
dtype: int64
Значения NaN
В предыдущем примере мы попробовали получить логарифм отрицательного числа и результатом стало значение NaN. Это значение (Not a Number) используется в структурах данных pandas для обозначения наличия пустого поля или чего-то, что невозможно обозначить в числовой форме.
Как правило, NaN — это проблема, для которой нужно найти определенное решение, особенно при работе с анализом данных. Эти данные часто появляются при извлечении информации из непроверенных источников или когда в самом источнике недостает данных. Также значения NaN могут генерироваться в специальных случаях, например, при вычислении логарифмов для отрицательных значений, в случае исключений при вычислениях или при использовании функций. Есть разные стратегии работы со значениями NaN.
Несмотря на свою «проблемность» pandas позволяет явно определять NaN и добавлять это значение в структуры, например, в Series. Для этого внутри массива достаточно ввести np.NaN в том месте, где требуется определить недостающее значение.
>>> s2 = pd.Series([5,-3,np.NaN,14])
>>> s2
0 5.0
1 -3.0
2 NaN
3 14.0
dtype: float64
Функции isnull() и notnull() очень полезны для определения индексов без значения.
>>> s2.isnull()
0 False
1 False
2 True
3 False
dtype: bool
>>> s2.notnull()
0 True
1 True
2 False
3 True
dtype: bool
Они возвращают два объекта Series с булевыми значениями, где True указывает на наличие значение, а NaN — на его отсутствие. Функция isnull() возвращает True для значений NaN в Series, а notnull() — True в тех местах, где значение не равно NaN. Эти функции часто используются в фильтрах для создания условий.
>>> s2[s2.notnull()]
0 5.0
1 -3.0
3 14.0
dtype: float64
s2[s2.isnull()]
2 NaN
dtype: float64
Series из словарей
Series можно воспринимать как объект dict (словарь). Эта схожесть может быть использована на этапе объявления объекта. Даже создавать Series можно на основе существующего dict.
>>> mydict = {'red': 2000, 'blue': 1000, 'yellow': 500,
'orange': 1000}
>>> myseries = pd.Series(mydict)
>>> myseries
blue 1000
orange 1000
red 2000
yellow 500
dtype: int64
На этом примере можно увидеть, что массив индексов заполнен ключами, а данные — соответствующими значениями. В таком случае соотношение будет установлено между ключами dict и метками массива индексов. Если есть несоответствие, pandas заменит его на NaN.
>>> colors = ['red','yellow','orange','blue','green']
>>> myseries = pd.Series(mydict, index=colors)
>>> myseries
red 2000.0
yellow 500.0
orange 1000.0
blue 1000.0
green NaN
dtype: float64
Операции с сериями
Вы уже видели, как выполнить арифметические операции на объектах Series и скалярных величинах. То же возможно и для двух объектов Series, но в таком случае в дело вступают и метки.
Одно из главных достоинств этого типа структур данных в том, что он может выравнивать данные, определяя соответствующие метки.
В следующем примере добавляются два объекта Series, у которых только некоторые метки совпадают.
>>> mydict2 = {'red':400,'yellow':1000,'black':700}
>>> myseries2 = pd.Series(mydict2)
>>> myseries + myseries2
black NaN
blue NaN
green NaN
orange NaN
red 2400.0
yellow 1500.0
dtype: float64
Новый объект получает только те элементы, где метки совпали. Все остальные тоже присутствуют, но со значением NaN.
DataFrame (датафрейм)
Dataframe — это табличная структура данных, напоминающая таблицы из Microsoft Excel. Ее главная задача — позволить использовать многомерные Series. Dataframe состоит из упорядоченной коллекции колонок, каждая из которых содержит значение разных типов (числовое, строковое, булевое и так далее).
В отличие от Series у которого есть массив индексов с метками, ассоциированных с каждым из элементов, Dataframe имеет сразу два таких. Первый ассоциирован со строками (рядами) и напоминает таковой из Series. Каждая метка ассоциирована со всеми значениями в ряду. Второй содержит метки для каждой из колонок.
Dataframe можно воспринимать как dict, состоящий из Series, где ключи — названия колонок, а значения — объекты Series, которые формируют колонки самого объекта Dataframe. Наконец, все элементы в каждом объекте Series связаны в соответствии с массивом меток, называемым index.
Создание Dataframe
Простейший способ создания Dataframe — передать объект dict в конструктор DataFrame(). Объект dict содержит ключ для каждой колонки, которую требуется определить, а также массив значений для них.
Если объект dict содержит больше данных, чем требуется, можно сделать выборку. Для этого в конструкторе Dataframe нужно определить последовательность колонок с помощью параметра column. Колонки будут созданы в заданном порядке вне зависимости от того, как они расположены в объекте dict.
>> data = {'color' : ['blue', 'green', 'yellow', 'red', 'white'],
'object' : ['ball', 'pen', 'pencil', 'paper', 'mug'],
'price' : [1.2, 1.0, 0.6, 0.9, 1.7]}
>>> frame = pd.DataFrame(data)
>>> frame
| color | object | price | |
|---|---|---|---|
| 0 | blue | ball | 1.2 |
| 1 | green | pen | 1.0 |
| 2 | yellow | pencil | 0.6 |
| 3 | red | paper | 0.9 |
| 4 | white | mug | 1.7 |
Даже для объектов Dataframe если метки явно не заданы в массиве index, pandas автоматически присваивает числовую последовательность, начиная с нуля. Если же индексам Dataframe нужно присвоить метки, необходимо использовать параметр index и присвоить ему массив с метками.
>>> frame2 = pd.DataFrame(data, columns=['object', 'price'])
>>> frame2
| object | price | |
|---|---|---|
| 0 | ball | 1.2 |
| 1 | pen | 1.0 |
| 2 | pencil | 0.6 |
| 3 | paper | 0.9 |
| 4 | mug | 1.7 |
Теперь, зная о параметрах index и columns, проще использовать другой способ определения Dataframe. Вместо использования объекта dict можно определить три аргумента в конструкторе в следующем порядке: матрицу данных, массив значений для параметра index и массив с названиями колонок для параметра columns.
В большинстве случаев простейший способ создать матрицу значений — использовать np.arrange(16).reshape((4,4)). Это формирует матрицу размером 4х4 из чисел от 0 до 15.
>>> frame3 = pd.DataFrame(np.arange(16).reshape((4,4)),
... index=['red', 'blue', 'yellow', 'white'],
... columns=['ball', 'pen', 'pencil', 'paper'])
>>> frame3
Выбор элементов
Если нужно узнать названия всех колонок Dataframe, можно вызвать атрибут columns для экземпляра объекта.
>>> frame.columns
Index(['color', 'object', 'price'], dtype='object')
То же можно проделать и для получения списка индексов.
>>> frame.index
RangeIndex(start=0, stop=5, step=1)
Весь же набор данных можно получить с помощью атрибута values.
>>> frame.values
array([['blue', 'ball', 1.2],
['green', 'pen', 1.0],
['yellow', 'pencil', 0.6],
['red', 'paper', 0.9],
['white', 'mug', 1.7]], dtype=object)
Указав в квадратных скобках название колонки, можно получить значений в ней.
>>> frame['price']
0 1.2
1 1.0
2 0.6
3 0.9
4 1.7
Name: price, dtype: float64
Возвращаемое значение — объект Series. Название колонки можно использовать и в качестве атрибута.
>>> frame.price
0 1.2
1 1.0
2 0.6
3 0.9
4 1.7
Name: price, dtype: float64
Для строк внутри Dataframe используется атрибут loc со значением индекса нужной строки.
>>> frame.loc[2]
color yellow
object pencil
price 0.6
Name: 2, dtype: object
Возвращаемый объект — это снова Series, где названия колонок — это уже метки массива индексов, а значения — данные Series.
Для выбора нескольких строк можно указать массив с их последовательностью.
>>> frame.loc[[2,4]]
| color | object | price | |
|---|---|---|---|
| 2 | yellow | pencil | 0.6 |
| 4 | white | mug | 1.7 |
Если необходимо извлечь часть Dataframe с конкретными строками, для этого можно использовать номера индексов. Она выведет данные из соответствующей строки и названия колонок.
>>> frame[0:1]
| color | object | price | |
|---|---|---|---|
| 2 | yellow | pencil | 0.6 |
| 4 | white | mug | 1.7 |
Возвращаемое значение — объект Dataframe с одной строкой. Если нужно больше одной строки, необходимо просто указать диапазон.
>>> frame[1:3]
| color | object | price | |
|---|---|---|---|
| 0 | blue | ball | 1.2 |
Наконец, если необходимо получить одно значение из объекта, сперва нужно указать название колонки, а потом — индекс или метку строки.
>>> frame['object'][3]
'paper'
Присваивание и замена значений
Разобравшись с логикой получения доступа к разным элементам Dataframe, можно следовать ей же для добавления новых или изменения уже существующих значений.
Например, в структуре Dataframe массив индексов определен атрибутом index, а строка с названиями колонок — columns. Можно присвоить метку с помощью атрибута name для этих двух подструктур, чтобы идентифицировать их.
>>> frame.index.name = 'id'
>>> frame.columns.name = 'item'
>>> frame
| item | color | object | price |
|---|---|---|---|
| id | |||
| 0 | blue | ball | 1.2 |
| 1 | green | pen | 1.0 |
| 2 | yellow | pencil | 0.6 |
| 3 | red | paper | 0.9 |
| 4 | white | mug | 1.7 |
Одна из главных особенностей структур данных pandas — их гибкость. Можно вмешаться на любом уровне для изменения внутренней структуры данных. Например, добавление новой колонки — крайне распространенная операция.
Ее можно выполнить, присвоив значение экземпляру Dataframe и определив новое имя колонки.
>>> frame['new'] = 12
>>> frame
| item | color | object | price | new |
|---|---|---|---|---|
| id | ||||
| 0 | blue | ball | 1.2 | 12 |
| 1 | green | pen | 1.0 | 12 |
| 2 | yellow | pencil | 0.6 | 12 |
| 3 | red | paper | 0.9 | 12 |
| 4 | white | mug | 1.7 | 12 |
Здесь видно, что появилась новая колонка new со значениями 12 для каждого элемента.
Для обновления значений можно использовать массив.
frame['new'] = [3.0, 1.3, 2.2, 0.8, 1.1]
frame
| item | color | object | price | new |
|---|---|---|---|---|
| id | ||||
| 0 | blue | ball | 1.2 | 3.0 |
| 1 | green | pen | 1.0 | 1.3 |
| 2 | yellow | pencil | 0.6 | 2.2 |
| 3 | red | paper | 0.9 | 0.8 |
| 4 | white | mug | 1.7 | 1.1 |
Тот же подход используется для обновления целой колонки. Например, можно применить функцию np.arrange() для обновления значений колонки с помощью заранее заданной последовательности.
Колонки Dataframe также могут быть созданы с помощью присваивания объекта Series одной из них, например, определив объект Series, содержащий набор увеличивающихся значений с помощью np.arrange().
>>> ser = pd.Series(np.arange(5))
>>> ser
0 0
1 1
2 2
3 3
4 4
dtype: int32
frame['new'] = ser
frame
| item | color | object | price | new |
|---|---|---|---|---|
| id | ||||
| 0 | blue | ball | 1.2 | 0 |
| 1 | green | pen | 1.0 | 1 |
| 2 | yellow | pencil | 0.6 | 2 |
| 3 | red | paper | 0.9 | 3 |
| 4 | white | mug | 1.7 | 4 |
Наконец, для изменения одного значения нужно лишь выбрать элемент и присвоить ему новое значение.
>>> frame['price'][2] = 3.3
Вхождение значений
Функция isin() используется с объектами Series для определения вхождения значений в колонку. Она же подходит и для объектов Dataframe.
>>> frame.isin([1.0,'pen'])
| item | color | object | price | new |
|---|---|---|---|---|
| id | ||||
| 0 | False | False | False | False |
| 1 | False | True | True | True |
| 2 | False | False | False | False |
| 3 | False | False | False | False |
| 4 | False | False | False | False |
Возвращается Dataframe с булевыми значениями, где True указывает на те значения, где членство подтверждено. Если передать это значение в виде условия, тогда вернется Dataframe, где будут только значения, удовлетворяющие условию.
>>> frame[frame.isin([1.0,'pen'])]
| item | color | object | price | new |
|---|---|---|---|---|
| id | ||||
| 0 | NaN | NaN | NaN | NaN |
| 1 | NaN | pen | 1.0 | 1.0 |
| 2 | NaN | NaN | NaN | NaN |
| 3 | NaN | NaN | NaN | NaN |
| 4 | NaN | NaN | NaN | NaN |
Удаление колонки
Для удаления целой колонки и всего ее содержимого используется команда del.
>>> del frame['new']
>>> frame
| item | color | object | price |
|---|---|---|---|
| id | |||
| 0 | blue | ball | 1.2 |
| 1 | green | pen | 1.0 |
| 2 | yellow | pencil | 3.3 |
| 3 | red | paper | 0.9 |
| 4 | white | mug | 1.7 |
Фильтрация
Даже для Dataframe можно применять фильтры, используя определенные условия. Например, вам нужно получить все значения меньше определенного числа (допустим, 1,2).
>>> frame[frame < 1.2]
| item | color | object | price |
|---|---|---|---|
| id | |||
| 0 | blue | ball | NaN |
| 1 | green | pen | 1.0 |
| 2 | yellow | pencil | NaN |
| 3 | red | paper | 0.9 |
| 4 | white | mug | NaN |
Результатом будет Dataframe со значениями меньше 1,2 на своих местах. На месте остальных будет NaN.
Dataframe из вложенного словаря
В Python часто используется вложенный dict:
>>> nestdict = {'red': { 2012: 22, 2013: 33},
... 'white': { 2011: 13, 2012: 22, 2013: 16},
... 'blue': { 2011: 17, 2012: 27, 2013: 18}}
Эта структура данных, будучи переданной в качестве аргумента в DataFrame(), интерпретируется pandas так, что внешние ключи становятся названиями колонок, а внутренние — метками индексов.
При интерпретации вложенный структуры возможно такое, что не все поля будут совпадать. pandas компенсирует это несоответствие, добавляя NaN на место недостающих значений.
>>> nestdict = {'red': { 2012: 22, 2013: 33},
... 'white': { 2011: 13, 2012: 22, 2013: 16},
... 'blue': { 2011: 17, 2012: 27, 2013: 18}}
>>> frame2 = pd.DataFrame(nestdict)
>>> frame2
| blue | red | white | |
|---|---|---|---|
| 2011 | 17 | NaN | 13 |
| 2012 | 27 | 22.0 | 22 |
| 2013 | 18 | 33.0 | 16 |
Транспонирование Dataframe
При работе с табличным структурами данных иногда появляется необходимость выполнить операцию перестановки (сделать так, чтобы колонки стали рядами и наоборот). pandas позволяет добиться этого очень просто. Достаточно добавить атрибут T.
>>> frame2.T
| 2011 | 2012 | 2013 | |
|---|---|---|---|
| blue | 17.0 | 27.0 | 18.0 |
| red | NaN | 22.0 | 33.0 |
| white | 13.0 | 22.0 | 16.0 |
Объекты Index
Зная, что такое Series и Dataframes, и понимая как они устроены, проще разобраться со всеми их достоинствами. Главная особенность этих структур — наличие объекта Index, который в них интегрирован.
Объекты Index являются метками осей и содержат другие метаданные. Вы уже знаете, как массив с метками превращается в объект Index, и что для него нужно определить параметр index в конструкторе.
>>> ser = pd.Series([5,0,3,8,4], index=['red','blue','yellow','white','green'])
>>> ser.index
Index(['red', 'blue', 'yellow', 'white', 'green'], dtype='object')
В отличие от других элементов в структурах данных pandas (Series и Dataframe) объекты index — неизменяемые. Это обеспечивает безопасность, когда нужно передавать данные между разными структурами.
У каждого объекта Index есть методы и свойства, которые нужны, чтобы узнавать значения.
Методы Index
Есть методы для получения информации об индексах из структуры данных. Например, idmin() и idmax() — структуры, возвращающие индексы с самым маленьким и большим значениями.
>>> ser.idxmin()
'blue'
>>> ser.idxmax()
'white'
Индекс с повторяющимися метками
Пока что были только те случаи, когда у индексов одной структуры лишь одна, уникальная метка. Для большинства функций это обязательное условие, но не для структур данных pandas.
Определим, например, Series с повторяющимися метками.
>>> serd = pd.Series(range(6), index=['white','white','blue','green', 'green','yellow'])
>>> serd
white 0
white 1
blue 2
green 3
green 4
yellow 5
dtype: int64
Если метке соответствует несколько значений, то она вернет не один элемент, а объект Series.
>>> serd['white']
white 0
white 1
dtype: int64
То же применимо и к Dataframe. При повторяющихся индексах он возвращает Dataframe.
В случае с маленькими структурами легко определять любые повторяющиеся индексы, но если структура большая, то растет и сложность этой операции. Для этого в pandas у объектов Index есть атрибут is_unique. Он сообщает, есть ли индексы с повторяющимися метками в структуре (Series или Dataframe).
>>> serd.index.is_unique
False
>>> frame.index.is_unique
True
Операции между структурами данных
Теперь когда вы знакомы со структурами данных, Series и Dataframe, а также базовыми операциями для работы с ними, стоит рассмотреть операции, включающие две или более структур.
Гибкие арифметические методы
Уже рассмотренные операции можно выполнять с помощью гибких арифметических методов:
add()sub()div()mul()
Для их вызова нужно использовать другую спецификацию. Например, вместо того чтобы выполнять операцию для двух объектов Dataframe по примеру frame1 + frame2, потребуется следующий формат:
>>> frame1.add(frame2)
| ball | mug | paper | pen | pencil | |
|---|---|---|---|---|---|
| blue | 6.0 | NaN | NaN | 6.0 | NaN |
| green | NaN | NaN | NaN | NaN | NaN |
| red | NaN | NaN | NaN | NaN | NaN |
| white | 20.0 | NaN | NaN | 20.0 | NaN |
| yellow | 19.0 | NaN | NaN | 19.0 | NaN |
Результат такой же, как при использовании оператора сложения +. Также стоит обратить внимание, что если названия индексов и колонок сильно отличаются, то результатом станет новый объект Dataframe, состоящий только из значений NaN.
Операции между Dataframe и Series
Pandas позволяет выполнять переносы между разными структурами, например, между Dataframe и Series. Определить две структуры можно следующим образом.
>>> frame = pd.DataFrame(np.arange(16).reshape((4,4)),
... index=['red', 'blue', 'yellow', 'white'],
... columns=['ball','pen','pencil','paper'])
>>> frame
| ball | pen | pencil | paper | |
|---|---|---|---|---|
| red | 0 | 1 | 2 | 3 |
| blue | 4 | 5 | 6 | 7 |
| yellow | 8 | 9 | 10 | 11 |
| white | 12 | 13 | 14 | 15 |
>>> ser = pd.Series(np.arange(4), index=['ball','pen','pencil','paper'])
>>> ser
ball 0
pen 1
pencil 2
paper 3
dtype: int32
Они были специально созданы так, чтобы индексы в Series совпадали с названиями колонок в Dataframe. В таком случае можно выполнить прямую операцию.
>>> frame - ser
| ball | pen | pencil | paper | |
|---|---|---|---|---|
| red | 0 | 0 | 0 | 0 |
| blue | 4 | 4 | 4 | 4 |
| yellow | 8 | 8 | 8 | 8 |
| white | 12 | 12 | 12 | 12 |
По результату видно, что элементы Series были вычтены из соответствующих тому же индексу в колонках значений Dataframe.
Если индекс не представлен ни в одной из структур, то появится новая колонка с этим индексом и значениями NaN.
>>> ser['mug'] = 9
>>> ser
ball 0
pen 1
pencil 2
paper 3
mug 9
dtype: int64
>>> frame - ser
| ball | mug | paper | pen | pencil | |
|---|---|---|---|---|---|
| red | 0 | NaN | 0 | 0 | 0 |
| blue | 4 | NaN | 4 | 4 | 4 |
| yellow | 8 | NaN | 8 | 8 | 8 |
| white | 12 | NaN | 12 | 12 | 12 |







