Le bloc de données de Pandas est pratique, mais je ne suis pas sûr de la gestion de la mémoire. J'étais curieux de savoir où et comment il était réellement placé, alors je l'ai recherché.
import pandas as pd
df = pd.DataFrame({'A': [1, 2], 'B': [3.0, 4.0], 'C': [5, 6]})
for block in df._data.blocks:
memory_address = block.values.__array_interface__['data'][0]
memory_hex = block.values.data.hex()
print(f"({id(block)}) {block}")
print(f"<{memory_address}> {memory_hex}")
print()
(4886642416) FloatBlock: slice(1, 2, 1), 1 x 2, dtype: float64
<140474854679968> 00000000000008400000000000001040
(4886642608) IntBlock: slice(0, 4, 2), 2 x 2, dtype: int64
<140474585659872> 0100000000000000020000000000000005000000000000000600000000000000
Le nombre entre le crochet angulaire est l'adresse mémoire et le nombre qui suit est la représentation hexadécimale de la valeur mémoire. Puisque les colonnes A et C sont toutes deux des valeurs Int, vous pouvez voir qu'elles sont allouées collectivement en mémoire. Je vois?
La trame de données gère des blocs de données via une classe appelée BlockManger. L'idée autour de ceci est l'article "[Une feuille de route pour des structures de données scientifiques riches en Python](https://wesmckinney.com/blog/a-roadmap-for-rich-scientific-data-structures-in-python/] par l'auteur de Pandas. ) »Est facile à comprendre.
Si vous suivez le type de variable qui apparaît dans le code ci-dessus, ce sera comme suit.
Vous pouvez voir que le bloc contient le ndarray de NumPy.
Donc, à partir de maintenant, c'est le monde de NumPy, "2.2. Advanced NumPy - Notes de cours Scipy Vous pouvez obtenir l'adresse mémoire avec ndarray .__ array_interface__ ['data'] [0]
. Et puisque vous pouvez obtenir la vue de la mémoire avec ndarray.data
, vous pouvez également regarder la valeur de la mémoire.
Notez que lorsque vous imprimez le memoryview, il est affiché sous la forme «<mémoire à 0x11b6a3ad0>», mais c'est l'adresse de l'instance de memoryview, qui est différente de l'adresse de la valeur. Pour plus d'informations, consultez «[Numpy, Python3.6 --not capable de comprendre pourquoi l'adresse est différente? --Stack Overflow](https://stackoverflow.com/questions/52032545/numpy-python3-6-not-able-to-understand-" pourquoi-l'adresse-est-différente) ».
Faisons quelques opérations simples de trame de données et expérimentons comment l'allocation de mémoire change.
df1 = df[0:1]
(4886726416) FloatBlock: slice(1, 2, 1), 1 x 1, dtype: float64
<140474854679968> 0000000000000840
(4886727088) IntBlock: slice(0, 4, 2), 2 x 1, dtype: int64
<140474585659872> 01000000000000000500000000000000
Le premier est la tranche de la première ligne. Vous pouvez voir que l'adresse mémoire n'a pas changé et que la plage de référence est devenue plus courte. L'instance de bloc a changé.
df2 = df[1:2]
(4886798416) FloatBlock: slice(1, 2, 1), 1 x 1, dtype: float64
<140474854679976> 0000000000001040
(4886798896) IntBlock: slice(0, 4, 2), 2 x 1, dtype: int64
<140474585659880> 02000000000000000600000000000000
C'est la tranche sur la deuxième ligne. Puisque toutes les adresses mémoire sont +8, vous pouvez voir qu'elles se réfèrent au même bloc mémoire simplement en déplaçant le pointeur.
df['D'] = [True, False]
(4886642416) FloatBlock: slice(1, 2, 1), 1 x 2, dtype: float64
<140474854679968> 00000000000008400000000000001040
(4886642608) IntBlock: slice(0, 4, 2), 2 x 2, dtype: int64
<140474585659872> 0100000000000000020000000000000005000000000000000600000000000000
(4886800144) BoolBlock: slice(3, 4, 1), 1 x 2, dtype: bool
<140474855093504> 0100
Ajoutez une colonne. Pour les colonnes existantes, non seulement l'adresse mémoire, mais également le bloc ne change pas.
df3 = df.append(df)
(4886726224) IntBlock: slice(0, 1, 1), 1 x 4, dtype: int64
<140474855531008> 0100000000000000020000000000000001000000000000000200000000000000
(4509301648) FloatBlock: slice(1, 2, 1), 1 x 4, dtype: float64
<140474585317312> 0000000000000840000000000000104000000000000008400000000000001040
(4509301840) IntBlock: slice(2, 3, 1), 1 x 4, dtype: int64
<140474585630688> 0500000000000000060000000000000005000000000000000600000000000000
(4509301552) BoolBlock: slice(3, 4, 1), 1 x 4, dtype: bool
<140474855008224> 01000100
J'ai essayé de combiner les lignes. La disposition de la mémoire a radicalement changé. Il existe également deux IntBlocks. Cela provoque une fragmentation, alors j'aimerais que vous le mettiez ensemble au bon moment.
df4 = df3._consolidate()
(4509301552) BoolBlock: slice(3, 4, 1), 1 x 4, dtype: bool
<140474855008224> 01000100
(4509301648) FloatBlock: slice(1, 2, 1), 1 x 4, dtype: float64
<140474585317312> 0000000000000840000000000000104000000000000008400000000000001040
(4886728240) IntBlock: slice(0, 4, 2), 2 x 4, dtype: int64
<140475125920528> 01000000000000000200000000000000010000000000000002000000000000000500000000000000060000000000000005000000000000000600000000000000
Quand j'ai appelé la méthode privée _consolidate ()
, les valeurs Int ont été regroupées et placées à la nouvelle adresse mémoire.