Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PERF: MultiIndex._engine use smaller dtypes #58411

Merged
merged 3 commits into from Apr 30, 2024

Conversation

GianlucaFicarelli
Copy link
Contributor

Use smaller dtypes in MultiIndex._engine if possible.
Reduce both loading time and memory (peak and used).
The improvement should be more relevant when working with big indices.
Below there are 2 examples.

  • closes #xxxx (Replace xxxx with the GitHub issue number)
  • Tests added and passed if fixing a bug or adding a new feature
  • All code checks passed.
  • Added type annotations to new arguments/methods/functions.
  • Added an entry in the latest doc/source/whatsnew/vX.X.X.rst file if fixing a bug or adding a new feature.

Improvement when engine.values uses uint32 instead of uint64:

  • idx._engine: from 8.53 s to 2.45 s
  • _engine.values.nbytes: from 800000000 to 400000000
  • _engine:
    • from: peak memory: 5805.98 MiB, increment: 5218.30 MiB
    • to: peak memory: 2794.02 MiB, increment: 2193.25 MiB

Time, Pandas 2.2.2:

In [4]: %time idx = pd.MultiIndex.from_product([np.arange(1000), np.arange(1000), np.arange(100)], names=["x0", "x1", "x2"])
   ...: 
CPU times: user 250 ms, sys: 191 ms, total: 442 ms
Wall time: 457 ms

In [5]: %time idx._engine
   ...: 
CPU times: user 2.83 s, sys: 4.01 s, total: 6.84 s
Wall time: 8.53 s
Out[5]: <pandas.core.indexes.multi.MultiIndexUIntEngine at 0x117363d50>

In [6]: idx._engine.values.dtype
Out[6]: dtype('uint64')

In [7]: idx._engine.values.nbytes
Out[7]: 800000000

Time, PR branch:

In [3]: %time idx = pd.MultiIndex.from_product([np.arange(1000), np.arange(1000), np.arange(100)], names=["x0", "x1", "x2"])
CPU times: user 282 ms, sys: 192 ms, total: 474 ms
Wall time: 565 ms

In [4]: %time idx._engine
CPU times: user 963 ms, sys: 838 ms, total: 1.8 s
Wall time: 2.45 s
Out[4]: <pandas.core.indexes.multi.MultiIndexUInt32Engine at 0x10ab54f90>

In [5]: idx._engine.values.dtype
Out[5]: dtype('uint32')

In [6]: idx._engine.values.nbytes
Out[6]: 400000000

Memory, Pandas 2.2.2:

In [4]: %memit idx = pd.MultiIndex.from_product([np.arange(1000), np.arange(1000), np.arange(100)], names=["x0", "x1", "x2"])
peak memory: 587.48 MiB, increment: 477.49 MiB

In [5]: %memit idx._engine
peak memory: 5805.98 MiB, increment: 5218.30 MiB

Memory, PR branch:

In [4]: %memit idx = pd.MultiIndex.from_product([np.arange(1000), np.arange(1000), np.arange(100)], names=["x0", "x1", "x2"])
peak memory: 600.49 MiB, increment: 477.43 MiB

In [5]: %memit idx._engine
peak memory: 2794.02 MiB, increment: 2193.25 MiB

Improvement when engine.values still needs to use uint64:

  • idx._engine: from 17.6 s to 4.56 s
  • _engine.values.nbytes: from 390625000 to 390625000 (unchanged since the dtype is the same)
  • _engine:
    • from: peak memory: 9106.29 MiB, increment: 8472.42 MiB
    • to: peak memory: 5325.37 MiB, increment: 4674.05 MiB

Time, Pandas 2.2.2:

In [3]: %time idx = pd.MultiIndex.from_product([np.arange(5)] * 11)
CPU times: user 265 ms, sys: 104 ms, total: 369 ms
Wall time: 371 ms

In [4]: %time idx._engine
CPU times: user 5.28 s, sys: 9.4 s, total: 14.7 s
Wall time: 17.6 s
Out[4]: <pandas.core.indexes.multi.MultiIndexUIntEngine at 0x11bde3cd0>

In [5]: idx._engine.values.dtype
Out[5]: dtype('uint64')

In [6]: idx._engine.values.nbytes
Out[6]: 390625000

Time, PR branch:

In [3]: %time idx = pd.MultiIndex.from_product([np.arange(5)] * 11)
CPU times: user 268 ms, sys: 112 ms, total: 380 ms
Wall time: 381 ms

In [4]: %time idx._engine
CPU times: user 2.24 s, sys: 1.75 s, total: 3.99 s
Wall time: 4.56 s
Out[4]: <pandas.core.indexes.multi.MultiIndexUInt64Engine at 0x1209d0e40>

In [6]: idx._engine.values.dtype
Out[6]: dtype('uint64')

In [7]: idx._engine.values.nbytes
Out[7]: 390625000

Memory, Pandas 2.2.2:

In [4]: %memit idx = pd.MultiIndex.from_product([np.arange(5)] * 11)
peak memory: 633.76 MiB, increment: 523.95 MiB

In [5]: %memit idx._engine
peak memory: 9106.29 MiB, increment: 8472.42 MiB

In [6]: idx._engine
Out[6]: <pandas.core.indexes.multi.MultiIndexUIntEngine at 0x117505750>

Memory, PR branch:

In [4]: %memit idx = pd.MultiIndex.from_product([np.arange(5)] * 11)
peak memory: 651.32 MiB, increment: 523.31 MiB

In [5]: %memit idx._engine
peak memory: 5325.37 MiB, increment: 4674.05 MiB

In [6]: idx._engine
Out[6]: <pandas.core.indexes.multi.MultiIndexUInt64Engine at 0x117323290>

@mroeschke mroeschke added Performance Memory or execution speed performance MultiIndex labels Apr 24, 2024
pandas/_libs/index.pyx Outdated Show resolved Hide resolved

# Check the total number of bits needed for our representation:
if lev_bits[0] > 64:
# The levels would overflow a 64 bit uint - use Python integers:
return MultiIndexPyIntEngine(self.levels, self.codes, offsets)
return MultiIndexUIntEngine(self.levels, self.codes, offsets)
if lev_bits[0] > 32:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible for the existing engine to get resized where it would exceed e.g. int32 max? Or would a new engine just be created?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you clarify in what cases the existing engine would exceed int32 max?
In cases where MultiIndex._set_levels() is called internally, this would also call _reset_cache() so the engine is recreated.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't exactly remember what path this goes through, but a snippet like

n = np.iinfo(np.uint8).max
ser = pd.Series(range(n), index=pd.MultiIndex.from_arrays([range(n]))
ser.iloc[n+1] = n+1
ser.index.some_method_that_uses_the_engine

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried the snippet above with some slight adjustment:

In [34]: n = np.iinfo(np.uint8).max - 1

In [35]: ser = pd.Series(range(n), index=pd.MultiIndex.from_arrays([range(n)]))

In [36]: ser.index._cache
Out[36]: {}

In [37]: ser.index._engine
Out[37]: <pandas.core.indexes.multi.MultiIndexUInt8Engine at 0x118e0fed0>

In [38]: ser.index._engine.values
Out[38]: 
array([  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, 156, 157,
       158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170,
       171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183,
       184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196,
       197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
       210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222,
       223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235,
       236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248,
       249, 250, 251, 252, 253, 254, 255], dtype=uint8)

In [39]: n
Out[39]: 254

In [40]: ser.index._cache
Out[40]: 
{'levels': FrozenList([[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, ...]]),
 '_engine': <pandas.core.indexes.multi.MultiIndexUInt8Engine at 0x118e0fed0>}

In [41]: ser.loc[n+1] = n+1

In [42]: ser.index._cache
Out[42]: {'levels': FrozenList([[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, ...]])}

In [43]: ser.index._engine
Out[43]: <pandas.core.indexes.multi.MultiIndexUInt16Engine at 0x107288270>

In [44]: ser.index._cache
Out[44]: 
{'levels': FrozenList([[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, ...]]),
 '_engine': <pandas.core.indexes.multi.MultiIndexUInt16Engine at 0x107288270>}

So it seems that after calling ser.loc, the engine is automatically deleted from the cache (or the index is a copy, since id returns a different number)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great thanks for checking

@GianlucaFicarelli
Copy link
Contributor Author

I executed the asv benchmarks for multiindex_object (on a Linux workstation, although not tuned for benchmarking) with these results:

asv continuous -f 1.1 41014db0e8 20f3bc015b -b '^multiindex_object'
| Change   | Before [41014db0] <improve_index_engine~4>   | After [20f3bc01] <improve_index_engine~1>   |   Ratio | Benchmark (Parameter)                                                                                      |
|----------|----------------------------------------------|---------------------------------------------|---------|------------------------------------------------------------------------------------------------------------|
| +        | 7.14±0.05μs                                  | 8.44±0.08μs                                 |    1.18 | multiindex_object.GetLoc.time_string_get_loc                                                               |
| +        | 7.31±0.04μs                                  | 8.58±0.2μs                                  |    1.17 | multiindex_object.GetLoc.time_med_get_loc                                                                  |
| +        | 7.19±0.07ms                                  | 8.38±0.2ms                                  |    1.16 | multiindex_object.GetLoc.time_med_get_loc_warm                                                             |
| +        | 7.15±0.1ms                                   | 8.22±0.2ms                                  |    1.15 | multiindex_object.GetLoc.time_small_get_loc_warm                                                           |
| -        | 1.37±0.01ms                                  | 1.23±0.01ms                                 |    0.9  | multiindex_object.Isin.time_isin_small('datetime')                                                         |
| -        | 1.36±0.04ms                                  | 1.22±0ms                                    |    0.9  | multiindex_object.Isin.time_isin_small('int')                                                              |
| -        | 1.37±0.01ms                                  | 1.23±0.01ms                                 |    0.9  | multiindex_object.Isin.time_isin_small('string')                                                           |
| -        | 4.10±0.3ms                                   | 3.59±0.03ms                                 |    0.88 | multiindex_object.SetOperations.time_operation('non_monotonic', 'int', 'union', None)                      |
| -        | 4.35±0.04ms                                  | 3.62±0.02ms                                 |    0.83 | multiindex_object.SetOperations.time_operation('non_monotonic', 'int', 'intersection', None)               |
| -        | 2.86±0.08ms                                  | 2.34±0.02ms                                 |    0.82 | multiindex_object.SetOperations.time_operation('monotonic', 'int', 'symmetric_difference', None)           |
| -        | 4.76±0.4ms                                   | 3.89±0.2ms                                  |    0.82 | multiindex_object.SetOperations.time_operation('non_monotonic', 'datetime', 'intersection', None)          |
| -        | 3.10±0.09ms                                  | 2.46±0.01ms                                 |    0.8  | multiindex_object.SetOperations.time_operation('monotonic', 'ea_int', 'intersection', False)               |
| -        | 2.93±0.2ms                                   | 2.34±0.03ms                                 |    0.8  | multiindex_object.SetOperations.time_operation('non_monotonic', 'datetime', 'symmetric_difference', False) |
| -        | 4.72±0.4ms                                   | 3.77±0.2ms                                  |    0.8  | multiindex_object.SetOperations.time_operation('non_monotonic', 'ea_int', 'intersection', None)            |
| -        | 5.03±0.1ms                                   | 3.99±0.07ms                                 |    0.79 | multiindex_object.SetOperations.time_operation('monotonic', 'ea_int', 'intersection', None)                |
| -        | 3.09±0.1ms                                   | 2.45±0.01ms                                 |    0.79 | multiindex_object.SetOperations.time_operation('monotonic', 'ea_int', 'symmetric_difference', None)        |
| -        | 4.40±0.3ms                                   | 3.48±0.2ms                                  |    0.79 | multiindex_object.SetOperations.time_operation('non_monotonic', 'datetime', 'union', None)                 |
| -        | 2.94±0.09ms                                  | 2.33±0.01ms                                 |    0.79 | multiindex_object.SetOperations.time_operation('non_monotonic', 'ea_int', 'symmetric_difference', False)   |
| -        | 4.47±0.4ms                                   | 3.51±0.2ms                                  |    0.79 | multiindex_object.SetOperations.time_operation('non_monotonic', 'ea_int', 'union', None)                   |
| -        | 3.14±0.04ms                                  | 2.44±0.02ms                                 |    0.78 | multiindex_object.SetOperations.time_operation('monotonic', 'datetime', 'intersection', False)             |
| -        | 3.14±0.03ms                                  | 2.44±0.03ms                                 |    0.78 | multiindex_object.SetOperations.time_operation('monotonic', 'string', 'intersection', False)               |
| -        | 5.33±0.5ms                                   | 4.16±0.06ms                                 |    0.78 | multiindex_object.SetOperations.time_operation('monotonic', 'string', 'intersection', None)                |
| -        | 3.35±0.1ms                                   | 2.61±0.04ms                                 |    0.78 | multiindex_object.SetOperations.time_operation('non_monotonic', 'datetime', 'symmetric_difference', None)  |
| -        | 3.38±0.1ms                                   | 2.65±0.01ms                                 |    0.78 | multiindex_object.SetOperations.time_operation('non_monotonic', 'ea_int', 'symmetric_difference', None)    |
| -        | 3.27±0.2ms                                   | 2.54±0.04ms                                 |    0.78 | multiindex_object.SetOperations.time_operation('non_monotonic', 'int', 'symmetric_difference', None)       |
| -        | 2.81±0.2ms                                   | 2.16±0.02ms                                 |    0.77 | multiindex_object.SetOperations.time_operation('monotonic', 'ea_int', 'symmetric_difference', False)       |
| -        | 3.16±0.03ms                                  | 2.42±0.01ms                                 |    0.77 | multiindex_object.SetOperations.time_operation('monotonic', 'int', 'intersection', False)                  |
| -        | 3.16±0.01ms                                  | 2.44±0.02ms                                 |    0.77 | multiindex_object.SetOperations.time_operation('monotonic', 'string', 'symmetric_difference', None)        |
| -        | 3.28±0.2ms                                   | 2.52±0ms                                    |    0.77 | multiindex_object.SetOperations.time_operation('non_monotonic', 'int', 'intersection', False)              |
| -        | 3.03±0.1ms                                   | 2.33±0.03ms                                 |    0.77 | multiindex_object.SetOperations.time_operation('non_monotonic', 'int', 'symmetric_difference', False)      |
| -        | 4.68±0.4ms                                   | 3.55±0.02ms                                 |    0.76 | multiindex_object.SetOperations.time_operation('monotonic', 'datetime', 'intersection', None)              |
| -        | 2.77±0.2ms                                   | 2.06±0.01ms                                 |    0.75 | multiindex_object.SetOperations.time_operation('monotonic', 'datetime', 'symmetric_difference', False)     |
| -        | 4.71±0.4ms                                   | 3.51±0.02ms                                 |    0.75 | multiindex_object.SetOperations.time_operation('monotonic', 'int', 'intersection', None)                   |
| -        | 2.71±0.2ms                                   | 1.99±0ms                                    |    0.74 | multiindex_object.SetOperations.time_operation('monotonic', 'int', 'symmetric_difference', False)          |
| -        | 3.45±0.03ms                                  | 2.55±0.01ms                                 |    0.74 | multiindex_object.SetOperations.time_operation('non_monotonic', 'datetime', 'intersection', False)         |
| -        | 3.46±0.04ms                                  | 2.58±0.03ms                                 |    0.74 | multiindex_object.SetOperations.time_operation('non_monotonic', 'ea_int', 'intersection', False)           |
| -        | 1.64±0.02ms                                  | 1.19±0.01ms                                 |    0.73 | multiindex_object.SetOperations.time_operation('non_monotonic', 'ea_int', 'union', False)                  |
| -        | 3.34±0.2ms                                   | 2.41±0.01ms                                 |    0.72 | multiindex_object.SetOperations.time_operation('monotonic', 'datetime', 'symmetric_difference', None)      |
| -        | 1.53±0.02ms                                  | 1.10±0.01ms                                 |    0.72 | multiindex_object.SetOperations.time_operation('monotonic', 'datetime', 'union', False)                    |
| -        | 1.61±0.02ms                                  | 1.16±0.01ms                                 |    0.72 | multiindex_object.SetOperations.time_operation('monotonic', 'ea_int', 'union', None)                       |
| -        | 5.86±0.1ms                                   | 4.19±0.07ms                                 |    0.71 | multiindex_object.SetOperations.time_operation('non_monotonic', 'string', 'intersection', None)            |
| -        | 3.41±0.2ms                                   | 2.41±0.03ms                                 |    0.71 | multiindex_object.SetOperations.time_operation('non_monotonic', 'string', 'symmetric_difference', False)   |
| -        | 1.57±0.02ms                                  | 1.10±0.01ms                                 |    0.7  | multiindex_object.SetOperations.time_operation('monotonic', 'int', 'union', None)                          |
| -        | 3.76±0.3ms                                   | 2.62±0.02ms                                 |    0.7  | multiindex_object.SetOperations.time_operation('non_monotonic', 'string', 'intersection', False)           |
| -        | 3.83±0.3ms                                   | 2.68±0.01ms                                 |    0.7  | multiindex_object.SetOperations.time_operation('non_monotonic', 'string', 'symmetric_difference', None)    |
| -        | 1.64±0.05ms                                  | 1.12±0.01ms                                 |    0.68 | multiindex_object.SetOperations.time_operation('monotonic', 'ea_int', 'union', False)                      |
| -        | 1.77±0.02ms                                  | 1.20±0.01ms                                 |    0.68 | multiindex_object.SetOperations.time_operation('non_monotonic', 'datetime', 'union', False)                |
| -        | 5.41±0.03ms                                  | 3.67±0.04ms                                 |    0.68 | multiindex_object.SetOperations.time_operation('non_monotonic', 'string', 'union', None)                   |
| -        | 1.67±0.1ms                                   | 1.12±0.01ms                                 |    0.67 | multiindex_object.SetOperations.time_operation('non_monotonic', 'int', 'union', False)                     |
| -        | 1.18±0.03ms                                  | 770±10μs                                    |    0.66 | multiindex_object.Isin.time_isin_large('datetime')                                                         |
| -        | 1.17±0.02ms                                  | 772±2μs                                     |    0.66 | multiindex_object.Isin.time_isin_large('string')                                                           |
| -        | 3.25±0.2ms                                   | 2.15±0.05ms                                 |    0.66 | multiindex_object.SetOperations.time_operation('monotonic', 'string', 'symmetric_difference', False)       |
| -        | 1.16±0.04ms                                  | 754±5μs                                     |    0.65 | multiindex_object.Isin.time_isin_large('int')                                                              |
| -        | 1.78±0.02ms                                  | 1.15±0ms                                    |    0.65 | multiindex_object.SetOperations.time_operation('monotonic', 'datetime', 'union', None)                     |
| -        | 1.66±0.03ms                                  | 1.05±0.01ms                                 |    0.63 | multiindex_object.SetOperations.time_operation('monotonic', 'int', 'union', False)                         |
| -        | 1.89±0.1ms                                   | 1.20±0.01ms                                 |    0.63 | multiindex_object.SetOperations.time_operation('non_monotonic', 'string', 'union', False)                  |
| -        | 4.46±0.3ms                                   | 2.77±0.01ms                                 |    0.62 | multiindex_object.SetOperations.time_operation('monotonic', 'string', 'union', None)                       |
| -        | 1.99±0.02ms                                  | 1.11±0.01ms                                 |    0.56 | multiindex_object.SetOperations.time_operation('monotonic', 'string', 'union', False)                      |
| -        | 30.3±5μs                                     | 16.6±2μs                                    |    0.55 | multiindex_object.GetLoc.time_large_get_loc                                                                |
| -        | 24.9±1ms                                     | 13.4±1ms                                    |    0.54 | multiindex_object.GetLoc.time_large_get_loc_warm                                                           |
| -        | 1.84±0.2ms                                   | 897±40μs                                    |    0.49 | multiindex_object.Integer.time_get_indexer                                                                 |
| -        | 29.8±0.6ms                                   | 14.2±0.4ms                                  |    0.48 | multiindex_object.Integer.time_get_indexer_and_pad                                                         |
| -        | 29.4±0.5ms                                   | 13.5±0.5ms                                  |    0.46 | multiindex_object.Integer.time_get_indexer_and_backfill                                                    |

All of them improved, except GetLoc with small and medium index. It doesn't seem a big change but it could be worth investigating.

Side note, I also tried to move the class BaseMultiIndexCodesEngine from cython to python in this commit, and I didn't notice any visible decrease of performance.

@mroeschke mroeschke added this to the 3.0 milestone Apr 30, 2024
@mroeschke mroeschke merged commit 086b047 into pandas-dev:main Apr 30, 2024
46 checks passed
@mroeschke
Copy link
Member

Thanks @GianlucaFicarelli

@GianlucaFicarelli GianlucaFicarelli deleted the improve_index_engine branch May 1, 2024 15:49
pmhatre1 pushed a commit to pmhatre1/pandas-pmhatre1 that referenced this pull request May 7, 2024
* PERF: MultiIndex._engine use smaller dtypes

* Move offsets downcasting to MultiIndex._engine

* Remove unused import uint64_t
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
MultiIndex Performance Memory or execution speed performance
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants