Pandas: групповые имена в индексе и столбцах - PullRequest
1 голос
/ 03 апреля 2020

У меня есть фрейм данных, который использует MultiIndex для индекса и столбцов. Например:

df = pd.DataFrame(index=pd.MultiIndex.from_product([[1,2], [1,2,3], [4,5]], names=['i','j', 'k']), columns=pd.MultiIndex.from_product([[1,2], [1,2]], names=['x', 'y']))
for c in df.columns:
    df[c] = np.random.randint(100, size=(12,1))

x       1       2
y       1   2   1   2
i j k
1 1 4  10  13   0  76
    5  92  37  52  40
  2 4  88  77  50  22
    5  75  31  19   1
  3 4  61  23   5  47
    5  43  68  10  21
2 1 4  23  15  17   5
    5  47  68   6  94
  2 4   0  12  24  54
    5  83  27  46  19
  3 4   7  22   5  15
    5   7  10  89  79

Я хочу сгруппировать значения по имени в индексе и по имени в столбцах. Для каждой такой группы у нас будет двумерный массив чисел (а не ряд). Я хочу объединить std() всех записей в этом двумерном массиве.

Например, скажем, я группирую ['i', 'x'], одна группа будет иметь значения i=1 и x=1. Я хочу вычислить std для каждого из этих двухмерных массивов и получить DataFrame со значениями i в качестве индекса и значениями x в виде столбцов.

Каков наилучший способ достижения этого?

Если я сделаю stack(), чтобы получить x в качестве индекса, я все равно буду вычислять несколько std() вместо одного, так как все еще будет несколько столбцов.

Ответы [ 3 ]

1 голос
/ 03 апреля 2020

Вы можете использовать вложенные списки. Для вашего примера, с данным типом DataFrame (не таким, как значения случайные; вы можете захотеть зафиксировать начальное значение так, чтобы результаты были сопоставимы), а i и x в качестве интересующих индексов, это будет работать так:

# get values of the top level row index
rows = set(df.index.get_level_values(0))
# get values of the top level column index
columns = set(df.columns.get_level_values(0))

# for every sub-dataframe (every combination of top-level indices) 
# compute sampling standard deviation (1 degree of freedom) across all values
df_groupSD = pd.DataFrame([[df.loc[(row, )][(col, )].values.std(ddof=1)  
                            for col in columns] for row in rows], 
                          index = rows, columns = columns)

# show result
display(df_groupSD)  

Вывод:

    1           2
1   31.455115   25.433812
2   29.421699   33.748962

Конечно, могут быть и лучшие способы.

1 голос
/ 03 апреля 2020

Попробуйте следующий код:

df.groupby(level=0).apply(lambda grp: grp.stack().std())
1 голос
/ 03 апреля 2020

Вы можете использовать stack, чтобы поставить уровень столбца 'y' в качестве индекса, а затем groupby только i, чтобы получить:

print (df.stack(level='y').groupby(['i']).std())
x          1          2
i                      
1  32.966811  23.933462
2  28.668825  28.541835
...