Выполнил Бибик Денис, ММП.

Оптимизация кода для препроцессинга данных

In [1]:
import pandas as pd
import numpy as np

Часть 1.Корректировка данных, слайд 13

  1. Сгенерируем похожие данные
In [2]:
num_elenments = 3000000

measures = [str(np.random.choice(range(100, 200))) + '/' + str(np.random.choice(range(80, 100))) 
            for i in range(num_elenments)]
df_ = pd.DataFrame(measures, columns = ['Давление'])
In [3]:
df_.head()
Out[3]:
Давление
0 195/87
1 116/93
2 146/91
3 172/84
4 147/98

Перед каждым экспирементом будем копировать датасет

In [4]:
df = df_.copy()
In [5]:
%%time
#Оригинальный код
tmp = df['Давление'].str.split('/')
df['в.давл.'] = tmp.apply(lambda x: x[0])
df['н.давл.'] = tmp.apply(lambda x: x[1])
CPU times: user 8.89 s, sys: 588 ms, total: 9.48 s
Wall time: 9.47 s
In [6]:
df = df_.copy()
In [7]:
%%time
#Попробуем избавится от apply
tmp = df['Давление'].str.split('/').str
df['в.давл.'] = tmp.get(0)
df['н.давл.'] = tmp.get(1)
CPU times: user 8.88 s, sys: 644 ms, total: 9.52 s
Wall time: 9.44 s
In [8]:
df = df_.copy()
In [9]:
%%time
#Теперь импользуем встроенную параметр expand
df[['в.давл.', 'н.давл.']] = df['Давление'].str.split('/', expand=True)
CPU times: user 4.82 s, sys: 164 ms, total: 4.99 s
Wall time: 4.99 s

Ускорение почти в два раза

In [10]:
df = df_.copy()
In [11]:
%%time
#Попробуем такой вариант, он не будет работать если будут ошибки в формате
st = '/'.join(df['Давление'])
df[['в.давл.', 'н.давл.']] = pd.DataFrame(np.array(st.split('/')).reshape(-1, 2))
CPU times: user 963 ms, sys: 164 ms, total: 1.13 s
Wall time: 1.13 s

Ускоорение в 8 раз

Часть 2. Заполнение данных, слайд 19

  1. Сгенерируем похожие данные
In [12]:
num_elements = 5000000
train_len = int(0.75 * num_elements)
num_nan = 300000
df_ = pd.DataFrame(np.random.choice(a = range(60, 100), size = (num_elements, 1)), columns = ['площадь'])
df_['data'] = ['train'] * train_len +  ['test'] * (num_elements - train_len)
nan_positions = np.random.choice(num_elements, num_nan, replace=False)
df_.loc[nan_positions, 'площадь'] = np.nan
In [13]:
df_.head()
Out[13]:
площадь data
0 72.0 train
1 73.0 train
2 93.0 train
3 69.0 train
4 80.0 train
In [14]:
df = df_.copy()
In [15]:
%%time
#Оригинальный код
df.loc[df['data'] == 'train', 'площадь'] =\
df[df['data'] == 'train']['площадь'].fillna(df[df['data'] == 'train']['площадь'].mean())
df.loc[df['data'] == 'test', 'площадь'] =\
df[df['data'] == 'test']['площадь'].fillna(df[df['data'] == 'test']['площадь'].mean())
CPU times: user 2.58 s, sys: 132 ms, total: 2.71 s
Wall time: 2.71 s
In [16]:
df = df_.copy()
In [17]:
%%time
#Используем transform
gb = df.groupby('data')
df['площадь'] = gb.transform(lambda x: x.fillna(x.mean()))
CPU times: user 849 ms, sys: 304 ms, total: 1.15 s
Wall time: 1.15 s

Ускорение более чем в два раза

In [18]:
df = df_.copy()

Разберемся что сколько времени занимает в коде выше

In [19]:
%%time
gb = df.groupby('data')
iterate = list(gb)
del iterate
CPU times: user 417 ms, sys: 120 ms, total: 537 ms
Wall time: 536 ms
In [20]:
%%time
m = gb.mean()
CPU times: user 37.6 ms, sys: 15.9 ms, total: 53.6 ms
Wall time: 52.4 ms
In [21]:
%%time
df['площадь'] = gb.transform(lambda x: x.fillna(0))
CPU times: user 628 ms, sys: 240 ms, total: 868 ms
Wall time: 867 ms

Получается что transform занимает значимую часть времени

In [22]:
df = df_.copy()
In [23]:
%%time
gb = df.groupby('data')
mean = gb.mean()
for gn, x in gb:
    x['площадь'].fillna(mean.loc[gn])
CPU times: user 709 ms, sys: 188 ms, total: 897 ms
Wall time: 895 ms

Ускорили еще на 250 мс