Ниже я покажу, как создать категоричную серию с небольшим объемом памяти. Тем не менее, имейте в виду, что может быть проще process your DataFrame in chunks, если ваша проблема позволяет.
Наименьшие значения (по памяти) в массиве NumPy занимают 1 байт. Эти массивы имеют dtype np.int8
(для 8-битных ints), или np.bool
или np.dtype('S1')
.
In [121]: np.dtype('int8').itemsize
Out[121]: 1
In [124]: np.dtype('int64').itemsize
Out[124]: 8
In [122]: np.dtype('bool').itemsize
Out[122]: 1
In [123]: np.dtype('S1').itemsize
Out[123]: 1
Базовые данные в столбцах DataFrame хранятся в массивах NumPy. Итак, чтобы сделать DataFrame как можно меньшим, используйте 1-байтовый dtype. Это создает столбец DataFrame из DTYPE int8
заполненный нулями:
df['col4'] = np.zeros(len(df), dtype='int8')
Пусть 1
представляют "start"
и 2
представляют "stop"
:
df.loc[(df.col1 == 1) & (df.col2 == 0) & (df.col3 == 1), "col4"] = 1
df.loc[(df.col1 == 1) & (df.col2 == 1) & (df.col3 == 0), "col4"] = 2
Обратите внимание, что помимо памяти, требуемой для col4
колонны, выше двух строки требуют дополнительного пространства для вычисления 4 булевых рядов: по одному для каждого из трех условий и четвертого для их объединения. Если эти линии еще поднять MemoryErrors, вы можете попробовать
mask = (df.col1 == 1) # <-- requires space for 1 boolean Series, `mask`
mask &= (df.col2 == 0) # <-- requires space for 2 boolean Series: mask and a tempory Series
mask &= (df.col3 == 1) # <-- requires no additional space
df.loc[mask, 'col4'] = 1 # <-- requires no additional space
Если сохранение памяти имеет первостепенное значение, вы должны остановиться здесь. Однако, если вы хотите 1-х и 2-х отображается как "start"
и "stop"
, вы можете изменить столбец DataFrame в category
DTYPE:
df['col4'] = df['col4'].astype('category')
, а затем изменить метки категорий:
df['col4'].cat.categories = ['', 'start', 'stop']
import numpy as np
import pandas as pd
np.random.seed(2017)
nrows, ncols = 20, 3
df = pd.DataFrame(np.random.randint(2, size=(nrows, ncols)),
columns=['col1', 'col2', 'col3'])
df['col4'] = np.zeros(len(df), dtype='int8')
print(df['col4'].nbytes)
# df.loc[(df.col1 == 1) & (df.col2 == 0) & (df.col3 == 1), "col4"] = 1
# df.loc[(df.col1 == 1) & (df.col2 == 1) & (df.col3 == 0), "col4"] = 2
mask = (df.col1 == 1)
mask &= (df.col2 == 0)
mask &= (df.col3 == 1)
df.loc[mask, 'col4'] = 1
mask = (df.col1 == 1)
mask &= (df.col2 == 1)
mask &= (df.col3 == 0)
df.loc[mask, 'col4'] = 2
df['col4'] = df['col4'].astype('category')
print(df['col4'].nbytes)
df['col4'].cat.categories = ['', 'start', 'stop']
print(df['col4'].nbytes)
print(df)
20 # the number of bytes required by `col4`
44 # a category column requires a bit more space
44 # the change of labels require a tiny bit more space, but not shown here
col1 col2 col3 col4
0 1 1 0 stop
1 1 0 0
2 0 0 1
3 1 1 1
4 0 0 0
5 0 0 1
6 1 0 0
7 0 0 0
8 1 0 1 start
9 1 1 0 stop
10 1 1 1
11 1 0 1 start
12 0 0 0
13 0 0 1
14 0 0 0
15 1 0 1 start
16 0 1 0
17 0 1 1
18 1 0 1 start
19 0 0 1
большое спасибо! Поскольку я продолжаю работать с df2.groupby (["col4"]). Cumcount() + 1, я бы хотел заменить "" категорию NaN.Это возможно? – sudonym
Начиная с версии Pandas 0.19: «Установка NaN в« категориях »устарела и будет удалена в будущей версии pandas». Поэтому для обеспечения будущего кода не устанавливайте метку категории на «NaN». – unutbu
Вместо этого вы можете удалить строки, где 'col4' пуст, прежде чем применять groupby:' df.loc [df ['col4']! = '']. Groupby (['col4']). Cumcount() '. – unutbu