Создание пустого MultiIndex

Я хотел бы создать пустой DataFrame с MultiIndex, прежде чем назначать ему строки. Я уже обнаружил, что пустым фреймам данных не нравится, когда им на лету назначаются MultiIndex, поэтому я устанавливаю MultiIndex имена во время создания. Однако я не хочу назначать уровни, так как это будет сделано позже. Это лучший код, который я получил до сих пор:

def empty_multiindex(names):
    """
    Creates empty MultiIndex from a list of level names.
    """
    return MultiIndex.from_tuples(tuples=[(None,) * len(names)], names=names)

Что дает мне

In [2]:

empty_multiindex(['one','two', 'three'])

Out[2]:

MultiIndex(levels=[[], [], []],
           labels=[[-1, -1, -1], [-1, -1, -1], [-1, -1, -1]],
           names=[u'one', u'two', u'three'])

а также

In [3]:
DataFrame(index=empty_multiindex(['one','two', 'three']))

Out[3]:
one two three
NaN NaN NaN

Ну, мне эти NaN не нужны. Я могу легко удалить их позже, но это явно хакерское решение. У кого-нибудь есть лучше?


person dmvianna    schedule 03.02.2015    source источник
comment
почему ты хочешь сделать это?   -  person Andy Hayden    schedule 03.02.2015
comment
@AndyHayden Я пытаюсь написать достаточно общую функцию для обработки произвольного количества имен. Мое задание состоит в том, чтобы создать частотные таблицы с очень произвольными и причудливыми итоговыми и промежуточными итогами, которые можно свернуть и развернуть на панели инструментов. Создание фреймов данных перед их передачей в Django упрощает мою жизнь.   -  person dmvianna    schedule 03.02.2015
comment
Зачем делать это как MI, а не как столбцы? Как правило, панды довольно плохо обновляются построчно (поскольку каждый раз приходится копировать все данные). Не могли бы вы сделать ИМ позже (после постройки)?   -  person Andy Hayden    schedule 03.02.2015
comment
@AndyHayden удобнее и читабельнее создавать метки по назначению (df2.loc[(name, key2, True), :] = df1.loc[(key1, key2), :].sum()), чем пытать Series перед назначением, добавляя к нему. А поддерживать параллельные кадры данных для индексов и данных было бы еще хуже.   -  person dmvianna    schedule 04.02.2015
comment
Думаю, я бы сказал, что DataFrame не может быть подходящей структурой данных для использования в этом случае.   -  person Andy Hayden    schedule 04.02.2015
comment
@AndyHayden Я прислушиваюсь к предложениям.   -  person dmvianna    schedule 04.02.2015
comment
Ну, не зная точных спецификаций, трудно дать лучшее решение, вы пробовали просто использовать словарь?   -  person Andy Hayden    schedule 04.02.2015
comment
@AndyHayden dict не даст мне индексацию DataFrame панд и такие методы, как sum (), которые я могу комбинировать с индексацией. Я согласен, что может быть лучшее решение (например, создание объекта с нуля, который делает то, что я хочу). Но на данный момент я оптимизирую время разработчика, а не время обработки.   -  person dmvianna    schedule 05.02.2015


Ответы (4)


Решение состоит в том, чтобы не использовать ярлыки. Это отлично работает для меня:

>>> my_index = pd.MultiIndex(levels=[[],[],[]],
                             labels=[[],[],[]],
                             names=[u'one', u'two', u'three'])
>>> my_index
MultiIndex(levels=[[], [], []],
           labels=[[], [], []],
           names=[u'one', u'two', u'three'])
>>> my_columns = [u'alpha', u'beta']
>>> df = pd.DataFrame(index=my_index, columns=my_columns)
>>> df
Empty DataFrame
Columns: [alpha, beta]
Index: []
>>> df.loc[('apple','banana','cherry'),:] = [0.1, 0.2]
>>> df
                    alpha beta
one   two    three            
apple banana cherry   0.1  0.2

Надеюсь, это поможет!

Для версии Pandas ›= 0.25.1: ключевое слово labels заменено на codes.

person RoG    schedule 09.07.2015
comment
[[],[],[]] при желании можно заменить на [[]]*3. - person OrangeSherbet; 09.04.2017
comment
Это выдает предупреждение об устаревании Pandas '0.25.1'. - person buechel; 18.09.2019
comment
@buechel ключевое слово labels было заменено на codes в версии 0.25.1. - person xuva; 07.11.2019

Другим решением, которое может быть немного проще, является использование функции set_index:

>>> import pandas as pd
>>> df = pd.DataFrame(columns=['one', 'two', 'three', 'alpha', 'beta'])
>>> df = df.set_index(['one', 'two', 'three'])
>>> df
Empty DataFrame
Columns: [alpha, beta]
Index: []
>>> df.loc[('apple','banana','cherry'),:] = [0.1, 0.2]
>>> df
                    alpha beta
one   two    three            
apple banana cherry   0.1  0.2
person Jean Paul    schedule 21.08.2017
comment
Все еще работает в 2021 году (v.1.2.3) - person alextsil; 12.04.2021

Использование pd.MultiIndex.from_tuples может быть более простым.

import pandas as pd
ind = pd.MultiIndex.from_tuples([], names=(u'one', u'two', u'three'))
df = pd.DataFrame(columns=['alpha', 'beta'], index=ind)
df.loc[('apple','banana','cherry'), :] = [4, 3]
df

                      alpha beta
one     two     three       
apple   banana  cherry    4    3
person ronkov    schedule 27.08.2020

Использование pd.MultiIndex.from_arrays позволяет получить несколько более лаконичное решение при явном определении индекса:

import pandas as pd
ind = pd.MultiIndex.from_arrays([[]] * 3, names=(u'one', u'two', u'three'))
df = pd.DataFrame(columns=['alpha', 'beta'], index=ind)
df.loc[('apple','banana','cherry'), :] = [4, 3]

                     alpha  beta
one   two    three              
apple banana cherry      4     3
person mcsoini    schedule 17.11.2019