Pandas 在行上设置多索引,然后转置到列
Pandas setting multi-index on rows, then transposing to columns
如果我有一个简单的数据框:
print(a)
one two three
0 A 1 a
1 A 2 b
2 B 1 c
3 B 2 d
4 C 1 e
5 C 2 f
我可以通过发出以下命令轻松地在行上创建多索引:
a.set_index(['one', 'two'])
three
one two
A 1 a
2 b
B 1 c
2 d
C 1 e
2 f
是否有类似的简单方法在列上创建多索引?
我想结束:
one A B C
two 1 2 1 2 1 2
0 a b c d e f
在这种情况下,创建行多索引然后转置它会非常简单,但在其他示例中,我会想要在行和列上创建多索引。
我认为简短的回答是否。要具有 multi-index 列,数据框应该有两(或更多)行要转换为 headers(如 multi-index 行的列)。如果你有这种数据框,创建 multi-index header 并不是那么困难。它可以在很长的代码行中完成,您可以在任何其他数据帧中重复使用它,只应记住 header 的行号,如果不同则更改:
df = pd.DataFrame({'a':['foo_0', 'bar_0', 1, 2, 3], 'b':['foo_0', 'bar_1', 11, 12, 13],
'c':['foo_1', 'bar_0', 21, 22, 23], 'd':['foo_1', 'bar_1', 31, 32, 33]})
数据框:
a b c d
0 foo_0 foo_0 foo_1 foo_1
1 bar_0 bar_1 bar_0 bar_1
2 1 11 21 31
3 2 12 22 32
4 3 13 23 33
正在创建 multi-index object:
arrays = [df.iloc[0].tolist(), df.iloc[1].tolist()]
tuples = list(zip(*arrays))
index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second'])
df.columns = index
Multi-index header 结果:
first foo_0 foo_1
second bar_0 bar_1 bar_0 bar_1
0 foo_0 foo_0 foo_1 foo_1
1 bar_0 bar_1 bar_0 bar_1
2 1 11 21 31
3 2 12 22 32
4 3 13 23 33
最后我们需要删除 0-1 行然后重置行索引:
df = df.iloc[2:].reset_index(drop=True)
"one-line" 版本(唯一需要更改的是指定 header 索引和数据框本身):
idx_first_header = 0
idx_second_header = 1
df.columns = pd.MultiIndex.from_tuples(list(zip(*[df.iloc[idx_first_header].tolist(),
df.iloc[idx_second_header].tolist()])), names=['first', 'second'])
df = df.drop([idx_first_header, idx_second_header], axis=0).reset_index(drop=True)
是的!这叫换位。
a.set_index(['one', 'two']).T
让我们借鉴@ragesz 的post,因为他们使用了一个更好的例子来演示。
df = pd.DataFrame({'a':['foo_0', 'bar_0', 1, 2, 3], 'b':['foo_0', 'bar_1', 11, 12, 13],
'c':['foo_1', 'bar_0', 21, 22, 23], 'd':['foo_1', 'bar_1', 31, 32, 33]})
df.T.set_index([0, 1]).T
您可以使用 pivot_table
然后对数据框进行一系列操作以获得所需的形式:
df_pivot = pd.pivot_table(df, index=['one', 'two'], values='three', aggfunc=np.sum)
def rename_duplicates(old_list): # Replace duplicates in the index with an empty string
seen = {}
for x in old_list:
if x in seen:
seen[x] += 1
yield " "
else:
seen[x] = 0
yield x
col_group = df_pivot.unstack().stack().reset_index(level=-1)
col_group.index = rename_duplicates(col_group.index.tolist())
col_group.index.name = df_pivot.index.names[0]
col_group.T
one A B C
two 1 2 1 2 1 2
0 a b c d e f
来自未来的讯息
对于从 2016 年开始遇到这些问题和答案的任何迷失的灵魂,有一个非常简单的解决方案也适用于多索引:
设置
id1 = ['A', 'B', 'C']
id2 = [1, 2]
identifiers = list(itertools.product(id1,id2))
identifier_names = ['one', 'two']
df = pd.DataFrame(identifiers, columns=identifier_names)
df['three'] = ['a','b','c','d','e','f']
df.set_index(identifier_names, inplace=True)
print(df)
three
one two
A 1 a
2 b
B 1 c
2 d
C 1 e
2 f
解决方案
df = df.stack().unstack(identifier_names)
one A B C
two 1 2 1 2 1 2
three a b c d e f
希望这可以节省我花了 3 个小时来发现的人!
如果我有一个简单的数据框:
print(a)
one two three
0 A 1 a
1 A 2 b
2 B 1 c
3 B 2 d
4 C 1 e
5 C 2 f
我可以通过发出以下命令轻松地在行上创建多索引:
a.set_index(['one', 'two'])
three
one two
A 1 a
2 b
B 1 c
2 d
C 1 e
2 f
是否有类似的简单方法在列上创建多索引?
我想结束:
one A B C
two 1 2 1 2 1 2
0 a b c d e f
在这种情况下,创建行多索引然后转置它会非常简单,但在其他示例中,我会想要在行和列上创建多索引。
我认为简短的回答是否。要具有 multi-index 列,数据框应该有两(或更多)行要转换为 headers(如 multi-index 行的列)。如果你有这种数据框,创建 multi-index header 并不是那么困难。它可以在很长的代码行中完成,您可以在任何其他数据帧中重复使用它,只应记住 header 的行号,如果不同则更改:
df = pd.DataFrame({'a':['foo_0', 'bar_0', 1, 2, 3], 'b':['foo_0', 'bar_1', 11, 12, 13],
'c':['foo_1', 'bar_0', 21, 22, 23], 'd':['foo_1', 'bar_1', 31, 32, 33]})
数据框:
a b c d
0 foo_0 foo_0 foo_1 foo_1
1 bar_0 bar_1 bar_0 bar_1
2 1 11 21 31
3 2 12 22 32
4 3 13 23 33
正在创建 multi-index object:
arrays = [df.iloc[0].tolist(), df.iloc[1].tolist()]
tuples = list(zip(*arrays))
index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second'])
df.columns = index
Multi-index header 结果:
first foo_0 foo_1
second bar_0 bar_1 bar_0 bar_1
0 foo_0 foo_0 foo_1 foo_1
1 bar_0 bar_1 bar_0 bar_1
2 1 11 21 31
3 2 12 22 32
4 3 13 23 33
最后我们需要删除 0-1 行然后重置行索引:
df = df.iloc[2:].reset_index(drop=True)
"one-line" 版本(唯一需要更改的是指定 header 索引和数据框本身):
idx_first_header = 0
idx_second_header = 1
df.columns = pd.MultiIndex.from_tuples(list(zip(*[df.iloc[idx_first_header].tolist(),
df.iloc[idx_second_header].tolist()])), names=['first', 'second'])
df = df.drop([idx_first_header, idx_second_header], axis=0).reset_index(drop=True)
是的!这叫换位。
a.set_index(['one', 'two']).T
让我们借鉴@ragesz 的post,因为他们使用了一个更好的例子来演示。
df = pd.DataFrame({'a':['foo_0', 'bar_0', 1, 2, 3], 'b':['foo_0', 'bar_1', 11, 12, 13],
'c':['foo_1', 'bar_0', 21, 22, 23], 'd':['foo_1', 'bar_1', 31, 32, 33]})
df.T.set_index([0, 1]).T
您可以使用 pivot_table
然后对数据框进行一系列操作以获得所需的形式:
df_pivot = pd.pivot_table(df, index=['one', 'two'], values='three', aggfunc=np.sum)
def rename_duplicates(old_list): # Replace duplicates in the index with an empty string
seen = {}
for x in old_list:
if x in seen:
seen[x] += 1
yield " "
else:
seen[x] = 0
yield x
col_group = df_pivot.unstack().stack().reset_index(level=-1)
col_group.index = rename_duplicates(col_group.index.tolist())
col_group.index.name = df_pivot.index.names[0]
col_group.T
one A B C
two 1 2 1 2 1 2
0 a b c d e f
来自未来的讯息
对于从 2016 年开始遇到这些问题和答案的任何迷失的灵魂,有一个非常简单的解决方案也适用于多索引:
设置
id1 = ['A', 'B', 'C']
id2 = [1, 2]
identifiers = list(itertools.product(id1,id2))
identifier_names = ['one', 'two']
df = pd.DataFrame(identifiers, columns=identifier_names)
df['three'] = ['a','b','c','d','e','f']
df.set_index(identifier_names, inplace=True)
print(df)
three
one two
A 1 a
2 b
B 1 c
2 d
C 1 e
2 f
解决方案
df = df.stack().unstack(identifier_names)
one A B C
two 1 2 1 2 1 2
three a b c d e f
希望这可以节省我花了 3 个小时来发现的人!