NumPy

numpy.org/doc/

Библеотека NumPy предоставляет следующие возможности:

  • работать с многомерными массивами (включая матрицы)
  • производить быстрое вычисление математических функций на многомерных массивах

Ядром пакета NumPy является объект ndarray

Важные отличия между NumPy arrays и Python sequences:

  • NumPy array имеет фиксированную длину, которая определяется в момент его создания (в отличие от Python lists, которые могут расти динамически)
  • Элементы в NumPy array должны быть одного типа
  • Можно выполнять операции непосредственно над NumPy arrays

Сильные стороны NumPy:

  • Vectorization
  • Broadcasting

Мотивирующий пример Imgur

import numpy as np

Способы создания Numpy arrays

  • Конвертация из Python structures
  • Генерация с помощью встроенных функций
  • Чтение с диска

Конвертация из Python structures

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

При конвертации можно задавать тип данных с помощью аргумента dtype:

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

Аналогичное преобразование:

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

Генерация Numpy arrays

  • arange — аналог range из Python, которому можно передать нецелочисленный шаг
  • linspace — способ равномерно разбить отрезок на n-1 интервал
  • logspace — способ разбить отрезок по логарифмической шкале
  • zeros — создаёт массив заполненный нулями заданной размерности
  • ones — создаёт массив заполненный единицами заданной размерности
  • empty — создаёт массив неинициализированный никаким значением заданной размерности
np.arange(0, 5, 0.5)
array([0. , 0.5, 1. , 1.5, 2. , 2.5, 3. , 3.5, 4. , 4.5])
np.linspace(0, 5, 11)
array([0. , 0.5, 1. , 1.5, 2. , 2.5, 3. , 3.5, 4. , 4.5, 5. ])
np.logspace(0, 9, 10, base=2)
array([  1.,   2.,   4.,   8.,  16.,  32.,  64., 128., 256., 512.])
np.zeros((2, 2))
array([[0., 0.],
       [0., 0.]])
np.ones((2, 2))
array([[1., 1.],
       [1., 1.]])
np.empty((2, 2))
array([[1., 1.],
       [1., 1.]])
np.diag([1,2,3])
array([[1, 0, 0],
       [0, 2, 0],
       [0, 0, 3]])

Pазмеры массива храниться в поле shape, а количество размерностей - в ndim

array = np.ones((2, 3,))
print('Размерность массива - %s, количество размерностей - %d'%(array.shape, array.ndim))
array
Размерность массива - (2, 3), количество размерностей - 2





array([[1., 1., 1.],
       [1., 1., 1.]])
## Чему равень ndim и shape в следующих случаях
print(np.diag([1,2,3]).shape, np.diag([1,2,3]).ndim)
print(np.zeros((5, 5, 5)).shape, np.zeros((5, 5, 5)).ndim)
(3, 3) 2
(5, 5, 5) 3

Метод reshape позволяет преобразовать размеры массива без изменения данных

array = np.arange(0, 6, 0.5)
array = array.reshape((2, 6))
array
array([[0. , 0.5, 1. , 1.5, 2. , 2.5],
       [3. , 3.5, 4. , 4.5, 5. , 5.5]])

Для того что бы развернуть многомерный массив в вектор, можно воспользоваться функцией ravel

array = np.ravel(array)
array
array([0. , 0.5, 1. , 1.5, 2. , 2.5, 3. , 3.5, 4. , 4.5, 5. , 5.5])
# Какие будут массивы?
print(np.ravel(np.diag([1,2])))
print(np.reshape(np.diag([1,2]), [1, 4]))
[1 0 0 2]
[[1 0 0 2]]

Индексация

В NumPy работает привычная индексация Python, включая использование отрицательных индексов и срезов

print(array[0])
print(array[-1])
print(array[1:-1])
print(array[1:-1:2])
print(array[::-1])
0.0
5.5
[0.5 1.  1.5 2.  2.5 3.  3.5 4.  4.5 5. ]
[0.5 1.5 2.5 3.5 4.5]
[5.5 5.  4.5 4.  3.5 3.  2.5 2.  1.5 1.  0.5 0. ]
print(array.shape)
(12,)
print(array[None,0:, None].ndim, array[None,0:, None].shape)
array[None,0:, None]
3 (1, 12, 1)





array([[[0. ],
        [0.5],
        [1. ],
        [1.5],
        [2. ],
        [2.5],
        [3. ],
        [3.5],
        [4. ],
        [4.5],
        [5. ],
        [5.5]]])

Замечание: Индексы и срезы в многомерных массивах не нужно разделять квадратными скобками

т.е. вместо matrix[i][j] нужно использовать matrix[i, j]

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

array[[0, 2, 4, 6, 8, 10]]
array([0., 1., 2., 3., 4., 5.])
array[[True, False, True, False, True, False, True, False, True, False, True, False]]
array([0., 1., 2., 3., 4., 5.])
# Что будет выведено?
x = np.array([[1, 2, 3]])
y = np.array([1, 2, 3])

print (x.shape, y.shape)

print(np.array_equal(x, y))
print(np.array_equal(x, y[None, :]))
(1, 3) (3,)
False
True
x = np.arange(10)
x
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
x[(x % 2 == 0) & (x > 5)]
array([6, 8])
print(x)
y = x[x>5] 
y *= 2
print(y)
print(x)
[0 1 2 3 4 5 6 7 8 9]
[12 14 16 18]
[0 1 2 3 4 5 6 7 8 9]

Для копирования в numpy есть метод copy

x.copy()
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

Чтение данных с помощью функции genfromtxt

with open('out.npz', 'wb') as f:
    np.save(f, x)
    
with open('out.npz', 'rb') as f:
    print(f.read())
    
with open('out.npz', 'rb') as f:
    y = np.load(f)
    print(y)    
b"\x93NUMPY\x01\x00v\x00{'descr': '<i8', 'fortran_order': False, 'shape': (10,), }                                                           \n\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\t\x00\x00\x00\x00\x00\x00\x00"
[0 1 2 3 4 5 6 7 8 9]
iris = np.genfromtxt('iris_subset.txt', delimiter=', ', names=True, dtype=[('sepal_length_in_cm', 'f8'), 
                                                                          ('sepal_width_in_cm', 'f8'), 
                                                                          ('petal_length_in_cm', 'f8'), 
                                                                          ('petal_width_in_cm', 'f8'),
                                                                          ('class', 'U10')])
iris
array([(1.000e+00,   1. ,   10.,   121. , 'setosa'),
       (1.000e+00, 314. ,   13.,   121. , 'versicolor'),
       (1.134e+03,   1. ,  103.,  1421. , 'setosa'),
       (1.000e+00, 141. ,   10.,   121. , 'versicolor'),
       (1.440e+02,   1. , 4582., 13481. , 'versicolor'),
       (1.000e+00,  13.3,   10.,   121. , 'versicolor'),
       (1.141e+03,   1. , 1341.,  1231.1, 'setosa'),
       (7.320e+02, 131. ,  139.,    92.1, 'setosa')],
      dtype=[('sepal_length_in_cm', '<f8'), ('sepal_width_in_cm', '<f8'), ('petal_length_in_cm', '<f8'), ('petal_width_in_cm', '<f8'), ('class', '<U10')])

Значения строки можно запросить по индексу, а значения колонки по её названию

print('Описание первого элемента: %s'%iris[0])
print('Значения столбца sepal_length_in_cm: %s'%iris['sepal_length_in_cm'])
Описание первого элемента: (1., 1., 10., 121., 'setosa')
Значения столбца sepal_length_in_cm: [1.000e+00 1.000e+00 1.134e+03 1.000e+00 1.440e+02 1.000e+00 1.141e+03
 7.320e+02]
sepal_length_setosa = iris['sepal_length_in_cm'][iris['class'] == 'setosa']
sepal_length_versicolor = iris['sepal_length_in_cm'][iris['class'] == 'versicolor']

print('Значения слтобца sepal_length_in_cm\n\tclass setosa: %s\n\tclass versicolor: %s'%(sepal_length_setosa, 
                                                                                         sepal_length_versicolor))
Значения слтобца sepal_length_in_cm
	class setosa: [1.000e+00 1.134e+03 1.141e+03 7.320e+02]
	class versicolor: [  1.   1. 144.   1.]

При чтение данных из файла можно пропускать строки в конце и в начале, используя skip_header и skip_footer, а также брать только нужные столбцы - usecols

iris_class = np.genfromtxt('iris_subset.txt', delimiter=', ', skip_header=1, usecols=4, dtype='U10')
iris_class
array(['setosa', 'versicolor', 'setosa', 'versicolor', 'versicolor',
       'versicolor', 'setosa', 'setosa'], dtype='<U10')
iris_features = np.genfromtxt('iris_subset.txt', delimiter=', ', skip_header=1, usecols=range(4))
iris_features
array([[1.0000e+00, 1.0000e+00, 1.0000e+01, 1.2100e+02],
       [1.0000e+00, 3.1400e+02, 1.3000e+01, 1.2100e+02],
       [1.1340e+03, 1.0000e+00, 1.0300e+02, 1.4210e+03],
       [1.0000e+00, 1.4100e+02, 1.0000e+01, 1.2100e+02],
       [1.4400e+02, 1.0000e+00, 4.5820e+03, 1.3481e+04],
       [1.0000e+00, 1.3300e+01, 1.0000e+01, 1.2100e+02],
       [1.1410e+03, 1.0000e+00, 1.3410e+03, 1.2311e+03],
       [7.3200e+02, 1.3100e+02, 1.3900e+02, 9.2100e+01]])
features_setosa = iris_features[iris_class == 'setosa']
features_versicolor = iris_features[iris_class == 'versicolor']

Операции в NumPy можно производить непосредственно над векторами одинаковой размерности без использования циклов

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

sepal_length_versicolor - sepal_length_setosa
array([    0., -1133.,  -997.,  -731.])

Аналогчино для многомерных массивов

features_versicolor - features_setosa
array([[ 0.00000e+00,  3.13000e+02,  3.00000e+00,  0.00000e+00],
       [-1.13300e+03,  1.40000e+02, -9.30000e+01, -1.30000e+03],
       [-9.97000e+02,  0.00000e+00,  3.24100e+03,  1.22499e+04],
       [-7.31000e+02, -1.17700e+02, -1.29000e+02,  2.89000e+01]])

Broadcasting

Broadcasting снимает правило одной размерности и позволяет производить арифметические операции над массивами разных, но всё-таки созгласованных размерностей. Простейшим примером является умножение вектора на число:

Imgur

2*np.arange(1, 4)
array([2, 4, 6])

Правило согласования размерностей выражается в одном предложение:

In order to broadcast, the size of the trailing axes for both arrays in an operation must either be the same size or one of them must be one

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

a  = np.ones((2,3,4))
b = np.ones(4)
c = a * b # here a.shape=(2,3,4) and b.shape is considered to be (1,1,4)

Прибавим к каждой строчки матрицы один и тот же вектор:

Imgur

np.array([[0, 0, 0], [10, 10, 10], [20, 20, 20], [30, 30, 30]]) + np.arange(3)
array([[ 0,  1,  2],
       [10, 11, 12],
       [20, 21, 22],
       [30, 31, 32]])

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

Imgurl

Сначала нужно преоброзовать вектор к виду:

np.arange(4)[:, np.newaxis]
array([[0],
       [1],
       [2],
       [3]])

А затем к нему добавить матрицу:

np.arange(4)[:, np.newaxis]+np.array([[0, 0, 0], [10, 10, 10], [20, 20, 20], [30, 30, 30]])
array([[ 0,  0,  0],
       [11, 11, 11],
       [22, 22, 22],
       [33, 33, 33]])

Так же в NumPy реализованно много полезных операций для работы с массивами: np.min, np.max, np.sum, np.mean и т.д.

print('Среднее значение всех значений класса versicolor: %s'%np.mean(features_versicolor))
print('Среднее значение каждого признака класса versicolor: %s'%np.mean(features_versicolor, axis=1))
Среднее значение всех значений класса versicolor: 1192.20625
Среднее значение каждого признака класса versicolor: [ 112.25    68.25  4552.      36.325]

Теперь эффективно посчитаем $\frac{1}{n} \sum\limits_{i=1}^n |x_i-y_i|$ для каждой пары $(x, y)$, где $x$ - вектор признаков объекта из класса setosa, а $y$ - вектор признаков объекта из класса versicolor

np.mean(np.abs(features_setosa - features_versicolor[:, np.newaxis]), axis=2)
array([[7.900000e+01, 7.090000e+02, 9.727750e+02, 2.672250e+02],
       [3.500000e+01, 6.665000e+02, 9.302750e+02, 2.247250e+02],
       [4.518750e+03, 4.382250e+03, 4.121975e+03, 4.637475e+03],
       [3.075000e+00, 6.345750e+02, 8.983500e+02, 2.516500e+02]])

Операции

x = np.arange(40).reshape(5, 2, 4)
print(x)
[[[ 0  1  2  3]
  [ 4  5  6  7]]

 [[ 8  9 10 11]
  [12 13 14 15]]

 [[16 17 18 19]
  [20 21 22 23]]

 [[24 25 26 27]
  [28 29 30 31]]

 [[32 33 34 35]
  [36 37 38 39]]]
print(x.mean())
print(np.mean(x))
19.5
19.5
x.mean(axis=0)
array([[16., 17., 18., 19.],
       [20., 21., 22., 23.]])
x.mean(axis=1)
array([[ 2.,  3.,  4.,  5.],
       [10., 11., 12., 13.],
       [18., 19., 20., 21.],
       [26., 27., 28., 29.],
       [34., 35., 36., 37.]])
x.mean(axis=2)
array([[ 1.5,  5.5],
       [ 9.5, 13.5],
       [17.5, 21.5],
       [25.5, 29.5],
       [33.5, 37.5]])
x.mean(axis=(0,2))
array([17.5, 21.5])
x.mean(axis=(0,1,2))
19.5

Конкатенация многомерных массивов

Конкатенировать несколько массивом можно с помощью функций np.concatenate, np.hstack, np.vstack, np.dstack

x = np.arange(10).reshape(5, 2)
y = np.arange(100, 120).reshape(5, 4)
x
array([[0, 1],
       [2, 3],
       [4, 5],
       [6, 7],
       [8, 9]])
y
array([[100, 101, 102, 103],
       [104, 105, 106, 107],
       [108, 109, 110, 111],
       [112, 113, 114, 115],
       [116, 117, 118, 119]])
np.hstack((x, y))
array([[  0,   1, 100, 101, 102, 103],
       [  2,   3, 104, 105, 106, 107],
       [  4,   5, 108, 109, 110, 111],
       [  6,   7, 112, 113, 114, 115],
       [  8,   9, 116, 117, 118, 119]])
x = np.ones([2, 3])
y = np.zeros([2, 2])
# Какой будет результат
print(np.hstack((x,y)).shape)
print(np.vstack((x,y)).shape)
(2, 5)



---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)

Cell In[54], line 3
      1 # Какой будет результат
      2 print(np.hstack((x,y)).shape)
----> 3 print(np.vstack((x,y)).shape)


File /opt/anaconda3/lib/python3.12/site-packages/numpy/core/shape_base.py:289, in vstack(tup, dtype, casting)
    287 if not isinstance(arrs, list):
    288     arrs = [arrs]
--> 289 return _nx.concatenate(arrs, 0, dtype=dtype, casting=casting)


ValueError: all the input array dimensions except for the concatenation axis must match exactly, but along dimension 1, the array at index 0 has size 3 and the array at index 1 has size 2
p = np.arange(1).reshape([1, 1, 1, 1])
p
array([[[[0]]]])
print("vstack: ", np.vstack((p, p)).shape)
print("hstack: ", np.hstack((p, p)).shape)
print("dstack: ", np.dstack((p, p)).shape)
print("concatenate: ", np.concatenate((p, p), axis=3).shape)
vstack:  (2, 1, 1, 1)
hstack:  (1, 2, 1, 1)
dstack:  (1, 1, 2, 1)
concatenate:  (1, 1, 1, 2)

Типы

x = [1, 2, 70000]
np.array(x, dtype=np.float32)
array([1.e+00, 2.e+00, 7.e+04], dtype=float32)
np.array(x, dtype=np.uint16)
/tmp/ipykernel_984447/2771282312.py:1: DeprecationWarning: NumPy will stop allowing conversion of out-of-bound Python integers to integer arrays.  The conversion of 70000 to uint16 will fail in the future.
For the old behavior, usually:
    np.array(value).astype(dtype)
will give the desired result (the cast overflows).
  np.array(x, dtype=np.uint16)





array([   1,    2, 4464], dtype=uint16)
np.array(x, dtype=np.unicode_)
array(['1', '2', '70000'], dtype='<U5')

Функциональное программирование

def f(value):
    return np.sqrt(value)
print(np.apply_along_axis(f, 0, np.arange(10)))
[0.         1.         1.41421356 1.73205081 2.         2.23606798
 2.44948974 2.64575131 2.82842712 3.        ]
vf = np.vectorize(f)
%%timeit 
vf(np.arange(100000))
146 ms ± 2.4 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%%timeit 
np.apply_along_axis(f, 0, np.arange(100000)) 
1.89 ms ± 31.9 μs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
%%timeit 
np.array([f(v) for v in np.arange(100000)])
129 ms ± 861 μs per loop (mean ± std. dev. of 7 runs, 10 loops each)

Pandas

pandas.pydata.org/docs/

Подключаем библиотеку Pandas, предназначенную для считывания, предобработки и быстрой визуализации данных, а также для простой аналитики.

import pandas as pd
df = pd.read_csv("titanic.csv", sep='\t')
df.head(3)
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C
2 3 1 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
view = df[df['Sex'] == 'female']
list(((df['Sex'] == 'female') & (df['Age'] > 30)).index)
[0,
 1,
 2,
 3,
 4,
 5,
 6,
 7,
 8,
 9,
 10,
 11,
 12,
 13,
 14,
 15,
 16,
 17,
 18,
 19,
 20,
 21,
 22,
 23,
 24,
 25,
 26,
 27,
 28,
 29,
 30,
 31,
 32,
 33,
 34,
 35,
 36,
 37,
 38,
 39,
 40,
 41,
 42,
 43,
 44,
 45,
 46,
 47,
 48,
 49,
 50,
 51,
 52,
 53,
 54,
 55,
 56,
 57,
 58,
 59,
 60,
 61,
 62,
 63,
 64,
 65,
 66,
 67,
 68,
 69,
 70,
 71,
 72,
 73,
 74,
 75,
 76,
 77,
 78,
 79,
 80,
 81,
 82,
 83,
 84,
 85,
 86,
 87,
 88,
 89,
 90,
 91,
 92,
 93,
 94,
 95,
 96,
 97,
 98,
 99,
 100,
 101,
 102,
 103,
 104,
 105,
 106,
 107,
 108,
 109,
 110,
 111,
 112,
 113,
 114,
 115,
 116,
 117,
 118,
 119,
 120,
 121,
 122,
 123,
 124,
 125,
 126,
 127,
 128,
 129,
 130,
 131,
 132,
 133,
 134,
 135,
 136,
 137,
 138,
 139,
 140,
 141,
 142,
 143,
 144,
 145,
 146,
 147,
 148,
 149,
 150,
 151,
 152,
 153,
 154,
 155]
df[(df['Sex'] == 'female') & (df['Age'] > 30)].index
Index([1, 3, 11, 15, 18, 25, 40, 52, 61, 85, 98, 123, 132], dtype='int64')
df.drop(index=(df[(df['Sex'] == 'female') & (df['Age'] > 30)].index),axis=1, inplace=True)
df.loc[78]
PassengerId                               79
Survived                                   1
Pclass                                     2
Name           Caldwell, Master. Alden Gates
Sex                                     male
Age                                     0.83
SibSp                                      0
Parch                                      2
Ticket                                248738
Fare                                    29.0
Cabin                                    NaN
Embarked                                   S
Name: 78, dtype: object
df.iloc[0]
PassengerId                          1
Survived                             0
Pclass                               3
Name           Braund, Mr. Owen Harris
Sex                               male
Age                               22.0
SibSp                                1
Parch                                0
Ticket                       A/5 21171
Fare                              7.25
Cabin                              NaN
Embarked                             S
Name: 0, dtype: object
df.describe()
PassengerId Survived Pclass Age SibSp Parch Fare
count 143.000000 143.000000 143.000000 113.000000 143.000000 143.000000 143.000000
mean 80.902098 0.307692 2.461538 26.702035 0.601399 0.391608 27.526018
std 44.536473 0.463161 0.776134 14.483237 1.075593 0.813919 40.406013
min 1.000000 0.000000 1.000000 0.830000 0.000000 0.000000 6.750000
25% 43.500000 0.000000 2.000000 19.000000 0.000000 0.000000 7.925000
50% 81.000000 0.000000 3.000000 24.000000 0.000000 0.000000 13.000000
75% 118.500000 1.000000 3.000000 33.000000 1.000000 0.000000 29.597900
max 156.000000 1.000000 3.000000 71.000000 5.000000 5.000000 263.000000
df[["Sex", "Cabin"]].describe()
Sex Cabin
count 143 25
unique 2 23
top male C23 C25 C27
freq 100 2

Срезы в DataFrame

Индексация

df.sort_values("Age", inplace=True)
df.head(3)
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
78 79 1 2 Caldwell, Master. Alden Gates male 0.83 0 2 248738 29.000 NaN S
7 8 0 3 Palsson, Master. Gosta Leonard male 2.00 3 1 349909 21.075 NaN S
119 120 0 3 Andersson, Miss. Ellis Anna Maria female 2.00 4 2 347082 31.275 NaN S
df.iloc[78]
PassengerId                              67
Survived                                  1
Pclass                                    2
Name           Nye, Mrs. (Elizabeth Ramell)
Sex                                  female
Age                                    29.0
SibSp                                     0
Parch                                     0
Ticket                           C.A. 29395
Fare                                   10.5
Cabin                                   F33
Embarked                                  S
Name: 66, dtype: object
df.loc[78]
PassengerId                               79
Survived                                   1
Pclass                                     2
Name           Caldwell, Master. Alden Gates
Sex                                     male
Age                                     0.83
SibSp                                      0
Parch                                      2
Ticket                                248738
Fare                                    29.0
Cabin                                    NaN
Embarked                                   S
Name: 78, dtype: object
df.loc[[78, 79, 100], ["Age", "Cabin"]]
Age Cabin
78 0.83 NaN
79 30.00 NaN
100 28.00 NaN

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

df_slice_copy = df.loc[[78, 79, 100], ["Age", "Cabin"]].copy()
df_slice_copy[:] = 3
df_slice_copy
Age Cabin
78 3.0 3
79 3.0 3
100 3.0 3

Если хотите менять основную таблицу, то используйте loc

df.head(3)
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
78 79 1 2 Caldwell, Master. Alden Gates male 0.83 0 2 248738 29.000 NaN S
7 8 0 3 Palsson, Master. Gosta Leonard male 2.00 3 1 349909 21.075 NaN S
119 120 0 3 Andersson, Miss. Ellis Anna Maria female 2.00 4 2 347082 31.275 NaN S
some_slice = df["Age"].isin([20, 25,30])
df.loc[some_slice, "Fare"] = df.loc[some_slice, "Fare"] * 10

Так лучше не делать:

slice_df = df[some_slice]
slice_df["Fare"] = slice_df["Fare"] * 10
/tmp/ipykernel_984447/1355601167.py:2: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  slice_df["Fare"] = slice_df["Fare"] * 10

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

Замечание: Если передаём название одного столбца, то получаем объект класса pandas.Series, а если список названий столбцов, то получаем pandas.DataFrame, чтобы получить numpy.array обратитесь к полю values.

Series и DataFrame имеют много общих методов

df["Age"].head(5)
78     0.83
7      2.00
119    2.00
16     2.00
43     3.00
Name: Age, dtype: float64
df[["Age"]].head(5)
Age
78 0.83
7 2.00
119 2.00
16 2.00
43 3.00

pd.Series

Одномерные срезы датафреймов имеют тип pd.Series.

Можно получить np.array из pd.Series, но вы не хотите этого делать.

df["Age"].head(5).values
array([0.83, 2.  , 2.  , 2.  , 3.  ])

Можно достать и индекс

df["Age"].head(5).index
Index([78, 7, 119, 16, 43], dtype='int64')

Создаются они примерно также, как np.array. Опционально указывается индекс

pd.Series([1, 2, 3], index=["Red", "Green", "Blue"])
Red      1
Green    2
Blue     3
dtype: int64
pd.Series(1, index=["Red", "Green", "Blue"])
Red      1
Green    1
Blue     1
dtype: int64
pd.Series([1, 2, 3], index=["Red", "Green", "Blue"])
Red      1
Green    2
Blue     3
dtype: int64

Series можно перевести в DataFrame

s = pd.Series([1, 2, 3], index=["Red", "Green", "Blue"])
s.to_frame("Values")
Values
Red 1
Green 2
Blue 3
s.loc["Red"]
1
s.iloc[0]
1

Объединение таблиц

df1 = df[["Age", "Parch"]].copy()
df2 = df[["Ticket", "Fare"]].copy()
df1.join(df2).head(5)
Age Parch Ticket Fare
78 0.83 2 248738 29.0000
7 2.00 1 349909 21.0750
119 2.00 2 347082 31.2750
16 2.00 1 382652 29.1250
43 3.00 2 SC/Paris 2123 41.5792
df1 = df[["Age", "Parch", "PassengerId"]].copy()
df2 = df[["Ticket", "Fare", "PassengerId"]].copy()
pd.merge(df1, df2, on=["PassengerId"]).head(5)
Age Parch PassengerId Ticket Fare
0 0.83 2 79 248738 29.0000
1 2.00 1 8 349909 21.0750
2 2.00 2 120 347082 31.2750
3 2.00 1 17 382652 29.1250
4 3.00 2 44 SC/Paris 2123 41.5792
pd.merge(df1, df2, on=["PassengerId"], how="inner").head(5)
Age Parch PassengerId Ticket Fare
0 0.83 2 79 248738 29.0000
1 2.00 1 8 349909 21.0750
2 2.00 2 120 347082 31.2750
3 2.00 1 17 382652 29.1250
4 3.00 2 44 SC/Paris 2123 41.5792

Группировка

print("Pclass 1: ", df[df["Pclass"] == 1]["Age"].mean())
print("Pclass 2: ", df[df["Pclass"] == 2]["Age"].mean())
print("Pclass 3: ", df[df["Pclass"] == 3]["Age"].mean())
Pclass 1:  36.86363636363637
Pclass 2:  26.68576923076923
Pclass 3:  23.26923076923077
df.groupby(["Pclass"])[["Age"]].mean()
Age
Pclass
1 36.863636
2 26.685769
3 23.269231
df.groupby(["Survived", "Pclass"])
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x73b08903f7d0>
df.groupby(["Survived", "Pclass"])["PassengerId"].count()
Survived  Pclass
0         1         18
          2         16
          3         65
1         1          7
          2         11
          3         26
Name: PassengerId, dtype: int64
df.groupby(["Survived", "Pclass"])[["PassengerId", "Cabin"]].count()
PassengerId Cabin
Survived Pclass
0 1 18 12
2 16 1
3 65 1
1 1 7 7
2 11 2
3 26 2
df.groupby(["Survived", "Pclass"])[["PassengerId", "Fare"]].describe()
PassengerId Fare
count mean std min 25% 50% 75% max count mean std min 25% 50% 75% max
Survived Pclass
0 1 18.0 82.555556 44.501450 7.0 40.75 88.5 117.00 156.0 18.0 80.035183 66.109719 27.7208 51.896875 61.2771 78.721875 263.0000
2 16.0 107.187500 44.842270 21.0 72.50 122.0 145.25 151.0 16.0 33.555725 32.412477 10.5000 12.881250 23.5000 31.740600 130.0000
3 65.0 80.892308 42.930585 1.0 49.00 87.0 114.00 155.0 65.0 19.123272 20.710190 6.7500 7.895800 8.0500 21.075000 98.2500
1 1 7.0 84.000000 49.568135 24.0 44.00 89.0 117.50 152.0 7.0 90.966057 85.998766 26.2833 35.500000 63.3583 106.560400 263.0000
2 11.0 57.181818 35.261362 10.0 33.00 57.0 73.00 134.0 11.0 21.627273 10.581905 10.5000 11.750000 26.0000 28.375000 41.5792
3 26.0 72.807692 46.318048 3.0 34.00 72.0 109.50 147.0 26.0 16.698400 24.254889 7.1417 7.756250 7.9250 14.244775 124.7500

Работа с timestamp'ами

tdf = df.copy()
tdf["ts"] = range(1560000000, 1560000000 + tdf.shape[0])
tdf.head(2)
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked ts
78 79 1 2 Caldwell, Master. Alden Gates male 0.83 0 2 248738 29.000 NaN S 1560000000
7 8 0 3 Palsson, Master. Gosta Leonard male 2.00 3 1 349909 21.075 NaN S 1560000001
tdf["ts"] = pd.to_datetime(tdf["ts"], unit="s")
tdf.head(2)
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked ts
78 79 1 2 Caldwell, Master. Alden Gates male 0.83 0 2 248738 29.000 NaN S 2019-06-08 13:20:00
7 8 0 3 Palsson, Master. Gosta Leonard male 2.00 3 1 349909 21.075 NaN S 2019-06-08 13:20:01
tdf.set_index("ts", inplace=True)
tdf.resample("15s").sum()[["PassengerId", "Survived", "Pclass", "Sex"]]
PassengerId Survived Pclass Sex
ts
2019-06-08 13:20:00 862 7 41 malemalefemalemalefemalemalefemalefemalemalefe...
2019-06-08 13:20:15 1302 4 40 femalefemalefemalefemalemalemalefemalefemalefe...
2019-06-08 13:20:30 1235 3 38 malemalefemalefemalemalemalemalemalemalemalema...
2019-06-08 13:20:45 1628 6 33 femalefemalemalemalemalemalemalemalefemalemale...
2019-06-08 13:21:00 1057 5 37 malemalemalemalefemalefemalemalefemalemalemale...
2019-06-08 13:21:15 1144 6 37 malemalefemalefemalemalefemalemalemalemalemale...
2019-06-08 13:21:30 1590 0 28 malemalemalemalemalemalemalemalemalemalemalema...
2019-06-08 13:21:45 845 4 33 malemalemalemalemalemalemalemalemalemalefemale...
2019-06-08 13:22:00 912 6 41 femalemalemalemalemalefemalemalemalemalemalema...
2019-06-08 13:22:15 994 3 24 malemalefemalemalemalefemalefemalemale

Rolling функции

Imgurl

tdf.sort_index(inplace=True)
tdf[["Fare"]].rolling(window=5).mean().head(10)
Fare
ts
2019-06-08 13:20:00 NaN
2019-06-08 13:20:01 NaN
2019-06-08 13:20:02 NaN
2019-06-08 13:20:03 NaN
2019-06-08 13:20:04 30.41084
2019-06-08 13:20:05 30.19084
2019-06-08 13:20:06 29.31584
2019-06-08 13:20:07 28.61084
2019-06-08 13:20:08 30.72334
2019-06-08 13:20:09 26.62250

Можно делать вместе с groupby

rol = tdf[["Sex", "Fare"]].groupby(["Sex"]).rolling(window=5).mean()
rol.head(100)
Fare
Sex ts
female 2019-06-08 13:20:02 NaN
2019-06-08 13:20:04 NaN
2019-06-08 13:20:06 NaN
2019-06-08 13:20:07 NaN
2019-06-08 13:20:09 27.67584
... ... ...
male 2019-06-08 13:21:26 14.02416
2019-06-08 13:21:27 17.12416
2019-06-08 13:21:28 12.72000
2019-06-08 13:21:29 16.34084
2019-06-08 13:21:30 19.81000

100 rows × 1 columns

rol.loc['male'].head(10)
Fare
ts
2019-06-08 13:20:00 NaN
2019-06-08 13:20:01 NaN
2019-06-08 13:20:03 NaN
2019-06-08 13:20:05 NaN
2019-06-08 13:20:08 29.35750
2019-06-08 13:20:11 32.93750
2019-06-08 13:20:12 30.97084
2019-06-08 13:20:19 26.98918
2019-06-08 13:20:20 28.28418
2019-06-08 13:20:26 22.64668

Работа со строками

df["Name"].str.lower()\
          .str.replace(",", " ")\
          .str.split(".").str[1]\
          .head(10)
78                    alden gates
7                   gosta leonard
119              ellis anna maria
16                         eugene
43      simonne marie anne andree
63                         harald
10                 marguerite rut
58               constance mirium
50                     juha niilo
24                 torborg danira
Name: Name, dtype: object

Работа с NaN'ами

df["Cabin"].head(15)
78     NaN
7      NaN
119    NaN
16     NaN
43     NaN
63     NaN
10      G6
58     NaN
50     NaN
24     NaN
147    NaN
59     NaN
125    NaN
39     NaN
9      NaN
Name: Cabin, dtype: object
df["Cabin"].dropna().head(15)
10              G6
136            D47
27     C23 C25 C27
102            D26
151             C2
97         D10 D12
88     C23 C25 C27
118        B58 B60
139            B86
75           F G73
23              A6
66             F33
21             D56
148             F2
137           C123
Name: Cabin, dtype: object
df["Cabin"].fillna(3).head(5)
78     3
7      3
119    3
16     3
43     3
Name: Cabin, dtype: object
df["Cabin"].fillna(method="bfill").head(15)
/tmp/ipykernel_984447/671977776.py:1: FutureWarning: Series.fillna with 'method' is deprecated and will raise in a future version. Use obj.ffill() or obj.bfill() instead.
  df["Cabin"].fillna(method="bfill").head(15)





78      G6
7       G6
119     G6
16      G6
43      G6
63      G6
10      G6
58     D47
50     D47
24     D47
147    D47
59     D47
125    D47
39     D47
9      D47
Name: Cabin, dtype: object
pd.isna(df["Cabin"]).head(10)
78      True
7       True
119     True
16      True
43      True
63      True
10     False
58      True
50      True
24      True
Name: Cabin, dtype: bool

Функция apply

def dummpy_example(row):
    return row['Sex'] * row['Pclass']

df['dummy_example'] = df.apply(dummpy_example, axis=1)
df.tail(3)
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked dummy_example
128 129 1 3 Peter, Miss. Anna female NaN 1 1 2668 22.3583 F E69 C femalefemalefemale
140 141 0 3 Boulos, Mrs. Joseph (Sultana) female NaN 0 2 2678 15.2458 NaN C femalefemalefemale
154 155 0 3 Olsen, Mr. Ole Martin male NaN 0 0 Fa 265302 7.3125 NaN S malemalemale

Визуализация

tdf["Fare"].plot()
<Axes: xlabel='ts'>

png

tdf["Fare"].resample("10s").mean().plot()
<Axes: xlabel='ts'>

png

tdf["Sex"].hist()
<Axes: >

png