Имя серии кортежей вызывает InvalidIndexError в Pandas 1.2.4, но не в 0.25.3

avatar
user3556757
9 августа 2021 в 06:19
150
0
0

Эта игрушка воспроизводит проблему:

import pandas as pd
print(f"pandas: {pd.__version__}")
!python --version   

#artificial 2
qf = pd.Series(index = pd.to_datetime(['12Dec2020', '13Dec2020','14Dec2020', '15Dec2020','16Dec2020']),
                    data= [1,1,-1,-1,-1], 
          name=('coz1', 'this_bar'),
         )
qf.index.name="Date"
qf = qf.groupby(
    (qf != qf.shift())
    .cumsum()
).cumsum().apply(int)
qf.head(10)

 

Когда я запускаю его в 0.25.3 Pandas, он работает.

pandas: 0.25.3
Python 3.7.11
Date
2020-12-12    1
2020-12-13    2
2020-12-14   -1
2020-12-15   -2
2020-12-16   -3
Name: (coz1, this_bar), dtype: int64

Но когда я запускаю его в 1.2.4 Pandas, он завершается с ошибкой InvalidIndexError

pandas: 1.2.4
Python 3.9.4

---------------------------------------------------------------------------
InvalidIndexError                         Traceback (most recent call last)
<ipython-input-1-f28184e3b2db> in <module>
      9          )
     10 qf.index.name="Date"
---> 11 qf = qf.groupby(
     12     (qf != qf.shift())
     13     .cumsum()

~\.conda\envs\yagi\lib\site-packages\pandas\core\series.py in groupby(self, by, axis, level, as_index, sort, group_keys, squeeze, observed, dropna)
   1718         axis = self._get_axis_number(axis)
   1719 
-> 1720         return SeriesGroupBy(
   1721             obj=self,
   1722             keys=by,

~\.conda\envs\yagi\lib\site-packages\pandas\core\groupby\groupby.py in __init__(self, obj, keys, axis, level, grouper, exclusions, selection, as_index, sort, group_keys, squeeze, observed, mutated, dropna)
    558             from pandas.core.groupby.grouper import get_grouper
    559 
--> 560             grouper, exclusions, obj = get_grouper(
    561                 obj,
    562                 keys,

~\.conda\envs\yagi\lib\site-packages\pandas\core\groupby\grouper.py in get_grouper(obj, key, axis, level, sort, observed, mutated, validate, dropna)
    796     for i, (gpr, level) in enumerate(zip(keys, levels)):
    797 
--> 798         if is_in_obj(gpr):  # df.groupby(df['name'])
    799             in_axis, name = True, gpr.name
    800             exclusions.add(name)

~\.conda\envs\yagi\lib\site-packages\pandas\core\groupby\grouper.py in is_in_obj(gpr)
    788             return False
    789         try:
--> 790             return gpr is obj[gpr.name]
    791         except (KeyError, IndexError):
    792             # IndexError reached in e.g. test_skip_group_keys when we pass

~\.conda\envs\yagi\lib\site-packages\pandas\core\series.py in __getitem__(self, key)
    857             try:
    858                 # For labels that don't resolve as scalars like tuples and frozensets
--> 859                 result = self._get_value(key)
    860 
    861                 return result

~\.conda\envs\yagi\lib\site-packages\pandas\core\series.py in _get_value(self, label, takeable)
    959 
    960         # Similar to Index.get_value, but we do not fall back to positional
--> 961         loc = self.index.get_loc(label)
    962         return self.index._get_values_for_loc(self, loc, label)
    963 

~\.conda\envs\yagi\lib\site-packages\pandas\core\indexes\datetimes.py in get_loc(self, key, method, tolerance)
    644         """
    645         if not is_scalar(key):
--> 646             raise InvalidIndexError(key)
    647 
    648         orig_key = key

InvalidIndexError: ('coz1', 'this_bar')

Я определил причину как передачу кортежа параметру name вызова Series. Если я сделаю это простой строкой, все будет работать нормально.

import pandas as pd
print(f"pandas: {pd.__version__}")
!python --version   

qf=None
#artificial 2
jf = pd.Series(index = pd.to_datetime(['12Dec2020', '13Dec2020','14Dec2020', '15Dec2020','16Dec2020']),
                    data= [1,1,-1,-1,-1], 
          name="NotATuple",
         )
jf.index.name="Date"
jf = jf.groupby(
    (jf != jf.shift())
    .cumsum()
).cumsum().apply(int)
jf.head(10)     

pandas: 1.2.4
Python 3.9.4
Date
2020-12-12    1
2020-12-13    2
2020-12-14   -1
2020-12-15   -2
2020-12-16   -3
Name: NotATuple, dtype: int64

это большая проблема, потому что серия qf создается фрагментом .loc многоуровневого столбца DataFrame, а значение позже добавляется обратно в исходный фрейм данных, из которого оно было получено. Так что я вынужден сделать грубый хак, показанный во фрагменте:

    wf = df.loc[:,idx[sec, 'this_bar']].dropna(axis="index")
    
    #hack pt1 of 2
    original_name = wf.name
    wf.name="placeholder"

    wf = wf.groupby(
        (wf != wf.shift())
        .cumsum()
    ).cumsum().apply(int)
    
    pf = wf.shift()

    #hack pt2 of 2
    wf.name=original_name
    pf.name=original_name

    df.loc[:,idx[sec, 'this_bar']] == np.nan   #reset
    df.loc[:,idx[sec, 'this_bar']] = wf
    df.loc[:,idx[sec, 'prev_bar']] = pf
    
    #cosmetic column:
    df.loc[:,idx[sec, f'prev_{period}']] = df.loc[:,idx[sec, 'prev_bar']]

Интересно, это ошибка в Pandas 1.2.4?

Источник

Ответы (0)