Pandas: рдмрдЧ: рдорд▓реНрдЯреАрдЖрдИрдВрдбреЗрдХреНрд╕ рдХреЗ рд▓рд┐рдП рдзреБрд░реА рд╡рд┐рдлрд▓ рд░рд╣рддреА рд╣реИ рдпрджрд┐ рдореМрдЬреВрджрд╛ рд╕реВрдЪрдХрд╛рдВрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

рдХреЛ рдирд┐рд░реНрдорд┐рдд 27 рдирд╡ре░ 2018  ┬╖  5рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: pandas-dev/pandas

рдХреЛрдб рдирдореВрдирд╛, рдПрдХ рдХреЙрдкреА-рдкреЗрд╕реНрдЯ рдХрд░рдиреЗ рдпреЛрдЧреНрдп рдЙрджрд╛рд╣рд░рдг

df  = pd.DataFrame([['A', 'A1', 'label1', 1],
             ['A', 'A2', 'label2', 2],
             ['B', 'A1', 'label1', 3],
             ['B', 'A2', 'label2', 4]], columns=['index_1', 'index_2', 'label', 'value'])
df = df.set_index(['index_1', 'index_2'])

pivoted_df = df.pivot(index=None,
                     columns='label',
                     values = 'value')

рд╕рдорд╕реНрдпрд╛ рдХрд╛ рд╡рд┐рд╡рд░рдг

рдкрд┐рд╡рдЯ рдлрд╝рдВрдХреНрд╢рди NotImplementedError: isna is not defined for MultiIndex рддреНрд░реБрдЯрд┐ рджреЗрддрд╛ рд╣реИред рдЬрдм рд╕реВрдЪрдХрд╛рдВрдХ None ред


---------------------------------------------------------------------------
NotImplementedError                       Traceback (most recent call last)
<ipython-input-84-54426dadf31d> in <module>()
      2 pivoted_df = df.pivot(index=None,
      3                      columns='label',
----> 4                      values = 'value')

~\AppData\Local\Continuum\anaconda3\lib\site-packages\pandas\core\frame.py in pivot(self, index, columns, values)
   5192         """
   5193         from pandas.core.reshape.reshape import pivot
-> 5194         return pivot(self, index=index, columns=columns, values=values)
   5195 
   5196     _shared_docs['pivot_table'] = """

~\AppData\Local\Continuum\anaconda3\lib\site-packages\pandas\core\reshape\reshape.py in pivot(self, index, columns, values)
    404         else:
    405             index = self[index]
--> 406         index = MultiIndex.from_arrays([index, self[columns]])
    407 
    408         if is_list_like(values) and not isinstance(values, tuple):

~\AppData\Local\Continuum\anaconda3\lib\site-packages\pandas\core\indexes\multi.py in from_arrays(cls, arrays, sortorder, names)
   1272         from pandas.core.arrays.categorical import _factorize_from_iterables
   1273 
-> 1274         labels, levels = _factorize_from_iterables(arrays)
   1275         if names is None:
   1276             names = [getattr(arr, "name", None) for arr in arrays]

~\AppData\Local\Continuum\anaconda3\lib\site-packages\pandas\core\arrays\categorical.py in _factorize_from_iterables(iterables)
   2541         # For consistency, it should return a list of 2 lists.
   2542         return [[], []]
-> 2543     return map(list, lzip(*[_factorize_from_iterable(it) for it in iterables]))

~\AppData\Local\Continuum\anaconda3\lib\site-packages\pandas\core\arrays\categorical.py in <listcomp>(.0)
   2541         # For consistency, it should return a list of 2 lists.
   2542         return [[], []]
-> 2543     return map(list, lzip(*[_factorize_from_iterable(it) for it in iterables]))

~\AppData\Local\Continuum\anaconda3\lib\site-packages\pandas\core\arrays\categorical.py in _factorize_from_iterable(values)
   2513         codes = values.codes
   2514     else:
-> 2515         cat = Categorical(values, ordered=True)
   2516         categories = cat.categories
   2517         codes = cat.codes

~\AppData\Local\Continuum\anaconda3\lib\site-packages\pandas\core\arrays\categorical.py in __init__(self, values, categories, ordered, dtype, fastpath)
    359 
    360             # we're inferring from values
--> 361             dtype = CategoricalDtype(categories, dtype.ordered)
    362 
    363         elif is_categorical_dtype(values):

~\AppData\Local\Continuum\anaconda3\lib\site-packages\pandas\core\dtypes\dtypes.py in __init__(self, categories, ordered)
    136 
    137     def __init__(self, categories=None, ordered=None):
--> 138         self._finalize(categories, ordered, fastpath=False)
    139 
    140     <strong i="12">@classmethod</strong>

~\AppData\Local\Continuum\anaconda3\lib\site-packages\pandas\core\dtypes\dtypes.py in _finalize(self, categories, ordered, fastpath)
    161         if categories is not None:
    162             categories = self.validate_categories(categories,
--> 163                                                   fastpath=fastpath)
    164 
    165         self._categories = categories

~\AppData\Local\Continuum\anaconda3\lib\site-packages\pandas\core\dtypes\dtypes.py in validate_categories(categories, fastpath)
    318         if not fastpath:
    319 
--> 320             if categories.hasnans:
    321                 raise ValueError('Categorial categories cannot be null')
    322 

pandas\_libs\properties.pyx in pandas._libs.properties.CachedProperty.__get__()

~\AppData\Local\Continuum\anaconda3\lib\site-packages\pandas\core\indexes\base.py in hasnans(self)
   2237         """ return if I have any nans; enables various perf speedups """
   2238         if self._can_hold_na:
-> 2239             return self._isnan.any()
   2240         else:
   2241             return False

pandas\_libs\properties.pyx in pandas._libs.properties.CachedProperty.__get__()

~\AppData\Local\Continuum\anaconda3\lib\site-packages\pandas\core\indexes\base.py in _isnan(self)
   2218         """ return if each value is nan"""
   2219         if self._can_hold_na:
-> 2220             return isna(self)
   2221         else:
   2222             # shouldn't reach to this condition by checking hasnans beforehand

~\AppData\Local\Continuum\anaconda3\lib\site-packages\pandas\core\dtypes\missing.py in isna(obj)
    104     Name: 1, dtype: bool
    105     """
--> 106     return _isna(obj)
    107 
    108 

~\AppData\Local\Continuum\anaconda3\lib\site-packages\pandas\core\dtypes\missing.py in _isna_new(obj)
    115     # hack (for now) because MI registers as ndarray
    116     elif isinstance(obj, ABCMultiIndex):
--> 117         raise NotImplementedError("isna is not defined for MultiIndex")
    118     elif isinstance(obj, (ABCSeries, np.ndarray, ABCIndexClass,
    119                           ABCExtensionArray)):

NotImplementedError: isna is not defined for MultiIndex

рдЕрдкреЗрдХреНрд╖рд┐рдд рдЙрддреНрдкрд╛рджрди

index_1 | index_2 | рд▓реЗрдмрд▓ 1 | Label2
- | - | - | -
рдП | рдП 1 | 1.0 | рдиреЗрди
|| рдП 2 | рдирд╛рдПрди | 2.0
B | A1 | 3.0 | рдиреЗрди
|| рдП 2 | рдирд╛рдПрди | 4.0

pd.show_versions() рдХрд╛ рдЖрдЙрдЯрдкреБрдЯ

рд╕реНрдерд╛рдкрд┐рдд рд╕рдВрд╕реНрдХрд░рдг

рдкреНрд░рддрд┐рдмрджреНрдз: рдХреЛрдИ рдирд╣реАрдВ
рдЕрдЬрдЧрд░: 3.6.5.final.0
рдкрд╛рдпрдерди-рдмрд┐рдЯреНрд╕: 64
рдУрдПрд╕: рд╡рд┐рдВрдбреЛрдЬ
OS- рд░рд┐рд▓реАрдЬрд╝: 10
рдорд╢реАрди: AMD64
рдкреНрд░реЛрд╕реЗрд╕рд░: Intel64 рдлреИрдорд┐рд▓реА 6 рдореЙрдбрд▓ 85 рд╕реНрдЯреЗрдкрд┐рдВрдЧ 4, рдЬреЗрдиреНрдпреБрдЕрд▓ рдЖрдИрдЯреЗрд▓
рдмрд╛рдЗрдЯрдСрд░реНрдбрд░: рдереЛрдбрд╝рд╛
LC_ALL: рдХреЛрдИ рдирд╣реАрдВ
рд▓реИрдВрдЧ: рдХреЛрдИ рдирд╣реАрдВ
LOCALE: рдХреЛрдИ рдирд╣реАрдВред рдХреЛрдИ рдирд╣реАрдВ

рдкрд╛рдВрдбрд╛: 0.23.4
pytest: 3.5.1
рдкрд╛рдЗрдк: 10.0.1
рд╕реЗрдЯрдкреНрдЯреВрд▓: 39.1.0
рд╕рд╛рдЗрдерди: 0.28.2
рд╕реБрдиреНрди: 1.15.4
рдбрд░рдкреЛрдХ: рез.рез.реж
рд╡реНрдпрдВрдЧреНрдп: рдХреЛрдИ рдирд╣реАрдВ
xarray: рдХреЛрдИ рдирд╣реАрдВ
рдЖрдИрдкреАрдереЙрди: 6.4.0
рд╕реНрдлрд┐рдВрдХреНрд╕: 1.7.4
patsy: 0.5.0
рджрд┐рдирд╛рдВрдХ: 2.7.3
pytz: 2018.4
рдмреНрд▓реЙрд╕реНрдХ: рдХреЛрдИ рдирд╣реАрдВ
рдЕрдбрд╝рдЪрди: 1.2.1
рдЯреЗрдмрд▓: 3.4.3
рд╕рдВрдЦреНрдпрд╛: 2.6.5
рдкрдВрдЦ: рдХреЛрдИ рдирд╣реАрдВ
matplotlib: 2.2.2
Openpyxl: 2.5.3
xlrd: 1.1.0
xlwt: 1.3.0
xlsxwriter: 1.0.4
lxml: 4.2.1
bs4: 4.6.0
html5lib: 1.0.1
рд╕реНрдХреНрд▓реИрд▓реНрдХреЗрдореА: 1.2.7
pymysql: рдХреЛрдИ рдирд╣реАрдВ
рдорд╛рдирд╕ 2: рдХреЛрдИ рдирд╣реАрдВ
jinja2: 2.10
s3fs: рдХреЛрдИ рдирд╣реАрдВ
fastparquet: рдХреЛрдИ рдирд╣реАрдВ
pandas_gbq: рдХреЛрдИ рдирд╣реАрдВ
pandas_datareader: рдХреЛрдИ рдирд╣реАрдВ

рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА

рд╕рдорд╛рдзрд╛рди рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж https://github.com/pandas-dev/pandas/issues/23955#issuecomment -480804068ред рдпрджрд┐ рдпрд╣ рдХрд┐рд╕реА рдХреЛ рдкрд░реЗрд╢рд╛рдиреА рд╕реЗ рдмрдЪрд╛рддрд╛ рд╣реИ, рддреЛ рдпрд╣рд╛рдВ рдПрдХ рд╕рд╛рдорд╛рдиреНрдпреАрдХрд░рдг рд╣реИ

def multiindex_pivot(df, columns=None, values=None):
    #https://github.com/pandas-dev/pandas/issues/23955
    names = list(df.index.names)
    df = df.reset_index()
    list_index = df[names].values
    tuples_index = [tuple(i) for i in list_index] # hashable
    df = df.assign(tuples_index=tuples_index)
    df = df.pivot(index="tuples_index", columns=columns, values=values)
    tuples_index = df.index  # reduced
    index = pd.MultiIndex.from_tuples(tuples_index, names=names)
    df.index = index
    return df

рд╕рднреА 5 рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

рдЗрд╕ рдкрд░ рдХреЛрдИ рдЕрдкрдбреЗрдЯ? рдЬреИрд╕рд╛ рдХрд┐ рдореИрдВ рд╕рдордЭрддрд╛ рд╣реВрдВ, рд╡рд░реНрддрдорд╛рди рдореЗрдВ pivot() рд╡рд┐рдзрд┐ рд╕рд┐рд░реНрдл рдХрдИ рдЗрдВрдбреЗрдХреНрд╕рд░реНрд╕ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддреА рд╣реИ, index рддрд░реНрдХ рдПрдХ рд╕реВрдЪреА рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рдФрд░ рдЬрдм None рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╡рд┐рдлрд▓ рд░рд╣рддрд╛ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддрд╛ рд╣реИ рдореМрдЬреВрджрд╛ MultiIndex рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВред

рдЕрдм рддрдХ, рдореИрдВ рдПрдХ рдЗрдВрдбреЗрдХреНрд╕ рдХреЛ рдореВрд▓ рдЗрдВрдбреЗрдХреНрд╕, рдкрд┐рд╡рдЯ рдХреЗ рдХрдИ рд╕реНрддрд░реЛрдВ рдХреЗ рд╕рдВрдпреЛрдЬрди рдХреЗ рд░реВрдк рдореЗрдВ рдПрдХрд▓ рдЗрдВрдбреЗрдХреНрд╕ рдЬреЗрдирд░реЗрдЯ рдХрд░рдХреЗ рд╣рд▓ рдХрд░рддрд╛ рд╣реВрдВ рдФрд░ рдлрд┐рд░ рдХреЙрдиреНрдЯреЗрдХреНрд╕реНрдЯ рдЗрдВрдбреЗрдХреНрд╕ рдХреЛ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░рдХреЗ рдорд▓реНрдЯреАрдЖрдИрдВрдбреЗрдХреНрд╕ рдХреЗ рд╡рд┐рднрд┐рдиреНрди рд╕реНрддрд░реЛрдВ рдХреЛ рдлрд┐рд░ рд╕реЗ рд╕рдВрдЧрдард┐рдд рдХрд░рддрд╛ рд╣реВрдВред @ рд╕рд░реНрдЬрдирдкрд╛рд▓реА рдЙрджрд╛рд╣рд░рдг рдкрд░ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд:

(df.reset_index()
 .assign(new_index=lambda dd: dd['index_1'].str.cat(dd['index_2'], sep='_'))
 .pivot(index='new_index', columns='label', values='value')
 .assign(index_1=lambda dd: dd.index.str.split('_').str.get(0),
         index_2=lambda dd: dd.index.str.split('_').str.get(1))
 .set_index(['index_1', 'index_2']))

рдЖрдЙрдЯрдкреБрдЯ:

| | рд▓реЗрдмрд▓ | рд▓реЗрдмрд▓ 1 | рд▓реЗрдмрд▓ 2 |
| --------- | --------- | -------- | -------- |
| index_1 | index_1 | | |
| рдП | A1 | 1.0 | NaN |
| | A2 | NaN | 2.0 | |
| B | A1 | 3.0 | NaN |
|| A2 | NaN | 4.0 | |

рдХрд┐рд╕реА рднреА рддрд░рд╣ рд╕реЗ, рдХреНрдпрд╛ рдорд▓реНрдЯреАрдПрдВрдбреЗрдХреНрд╕ pivot() рдСрдкрд░реЗрд╢рди рдХреЗ рд╕рд╛рде рд╕реНрд╡реАрдХрд╛рд░ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ?

рд╕рдорд╛рдзрд╛рди рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж https://github.com/pandas-dev/pandas/issues/23955#issuecomment -480804068ред рдпрджрд┐ рдпрд╣ рдХрд┐рд╕реА рдХреЛ рдкрд░реЗрд╢рд╛рдиреА рд╕реЗ рдмрдЪрд╛рддрд╛ рд╣реИ, рддреЛ рдпрд╣рд╛рдВ рдПрдХ рд╕рд╛рдорд╛рдиреНрдпреАрдХрд░рдг рд╣реИ

def multiindex_pivot(df, columns=None, values=None):
    #https://github.com/pandas-dev/pandas/issues/23955
    names = list(df.index.names)
    df = df.reset_index()
    list_index = df[names].values
    tuples_index = [tuple(i) for i in list_index] # hashable
    df = df.assign(tuples_index=tuples_index)
    df = df.pivot(index="tuples_index", columns=columns, values=values)
    tuples_index = df.index  # reduced
    index = pd.MultiIndex.from_tuples(tuples_index, names=names)
    df.index = index
    return df

рдзреБрд░реА рдПрдкреАрдЖрдИ рдХреЗ рд╕рд╛рде рдПрдХрд░реВрдкрддрд╛ рдХреЗ рд▓рд┐рдП @gmacario рдЯрд┐рдкреНрдкрдгреА рдХрд╛ рдорд╛рдореВрд▓реА рд╕рдорд╛рдпреЛрдЬрди

def multiindex_pivot(df, index=None, columns=None, values=None):
    #https://github.com/pandas-dev/pandas/issues/23955
    if index is None:
        names = list(df.index.names)
        df = df.reset_index()
    else:
        names = index
    list_index = df[names].values
    tuples_index = [tuple(i) for i in list_index] # hashable
    df = df.assign(tuples_index=tuples_index)
    df = df.pivot(index="tuples_index", columns=columns, values=values)
    tuples_index = df.index  # reduced
    index = pd.MultiIndex.from_tuples(tuples_index, names=names)
    df.index = index
    return df

рдЙрдкрдпреЛрдЧ:

df.pipe(multiindex_pivot, index=['idx_column1', 'idx_column2'], columns='foo', values='bar')

рдПрдХ рдФрд░ рдорд╛рдореВрд▓реА рд╡реГрджреНрдзрд┐ рдЬреЛ рдХрдИ columns= рднреА (рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдкрд░реАрдХреНрд╖рдг рдирд╣реАрдВ, рд▓реЗрдХрд┐рди рдореЗрд░реЗ рдЙрджрд╛рд╣рд░рдгреЛрдВ рдореЗрдВ рдХрд╛рдо рдХрд░рддреА рд╣реИ) рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреА рд╣реИ:

def multiindex_pivot(df, index=None, columns=None, values=None):
    # https://github.com/pandas-dev/pandas/issues/23955
    if index is None:
        names = list(df.index.names)
        df = df.reset_index()
    else:
        names = index
    df = df.assign(tuples_index=[tuple(i) for i in df[names].values])  # hashable
    df = df.assign(tuples_columns=[tuple(i) for i in df[columns].values])  # hashable
    df = df.pivot(index='tuples_index', columns='tuples_columns', values=values)
    df.index = pd.MultiIndex.from_tuples(df.index, names=names)  # reduced
    df.columns = pd.MultiIndex.from_tuples(df.columns, names=columns)  # reduced
    return df

рдЙрдкрдпреЛрдЧ:

df.pipe(multiindex_pivot,
        index=['idx_column1', 'idx_column2'],
        columns=['col_column1', 'col_column2'],
        values='bar')

рдЕрднреА рддрдХ рдПрдХ рдФрд░ рдереЛрдбрд╝рд╛ рд╕реБрдзрд╛рд░ рд╕рдВрд╕реНрдХрд░рдг:

def multiIndex_pivot(df, index = None, columns = None, values = None):
    # https://github.com/pandas-dev/pandas/issues/23955
    output_df = df.copy(deep = True)
    if index is None:
        names = list(output_df.index.names)
        output_df = output_df.reset_index()
    else:
        names = index
    output_df = output_df.assign(tuples_index = [tuple(i) for i in output_df[names].values])
    if isinstance(columns, list):
        output_df = output_df.assign(tuples_columns = [tuple(i) for i in output_df[columns].values])  # hashable
        output_df = output_df.pivot(index = 'tuples_index', columns = 'tuples_columns', values = values) 
        output_df.columns = pd.MultiIndex.from_tuples(output_df.columns, names = columns)  # reduced
    else:
        output_df = output_df.pivot(index = 'tuples_index', columns = columns, values = values)    
    output_df.index = pd.MultiIndex.from_tuples(output_df.index, names = names)
    return output_df

рдЙрдкрдпреЛрдЧ:

df.pipe(multiIndex_pivot, index = ['idx_column1', 'idx_column2'], columns = ['col_column1', 'col_column2'], values = 'bar')
рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕

рд╕рдВрдмрдВрдзрд┐рдд рдореБрджреНрджреЛрдВ

Ashutosh-Srivastav picture Ashutosh-Srivastav  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

ericdf picture ericdf  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

scls19fr picture scls19fr  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

andreas-thomik picture andreas-thomik  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

BDannowitz picture BDannowitz  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ