如何在 Pandas Multiindex 中重置单个索引?
How to reset a single index in Pandas Multiindex?
我有一个由多个数据帧构建的 MultiIndex DataFrame,我需要重置第一个索引。除了第一个索引,我不想改变任何东西;应保留其他所有内容的整个结构和顺序。
我目前的情况是这样的:
index = pd.MultiIndex.from_tuples([('0', 'Albert'),
('0', 'Isaac'),
('0', "Charles"),
('1', 'James'),
('1', 'Paul'),
('0', 'Wolfgang'),
('0', 'Enrico'),
('0', "John"),
('1', 'Marie'),
('1', 'Carol'),
('2', "Solomon"),
("2", "Joseph"),
("2", "Phil"),
('2', 'Danielle')],
names=['class', 'name'])
columns = ('High', 'Average')
df = pd.DataFrame([(98.8, 97.9),
(100.0, 99.9),
(76.5, 64.2),
(99.3, 98.9),
(87.2, 83.3),
(98.8, 96.5),
(100.0, 97.7),
(88.6, 64.2),
(99.3, 78.3),
(87.2, 81.0),
(78.8, 65.9),
(99.0, 95.4),
(86.1, 74.7),
(97.9, 91.1)],
index=index,
columns=columns)
这给出了一个如下所示的数据框:
High Average
class name
0 Albert 98.8 97.9
Isaac 100.0 99.9
Charles 76.5 64.2
1 James 99.3 98.9
Paul 87.2 83.3
0 Wolfgang 98.8 96.5
Enrico 100.0 97.7
John 88.6 64.2
1 Marie 99.3 78.3
Carol 87.2 81.0
2 Solomon 78.8 65.9
Joseph 99.0 95.4
Phil 86.1 74.7
Danielle 97.9 91.1
我只想将“class”索引重置为从 0 开始并迭代到“class”中的最后一个条目。最终结果应如下所示:
High Average
class name
0 Albert 98.8 97.9
Isaac 100.0 99.9
Charles 76.5 64.2
1 James 99.3 98.9
Paul 87.2 83.3
2 Wolfgang 98.8 96.5
Enrico 100.0 97.7
John 88.6 64.2
3 Marie 99.3 78.3
Carol 87.2 81.0
4 Solomon 78.8 65.9
Joseph 99.0 95.4
Phil 86.1 74.7
Danielle 97.9 91.1
我不知道该怎么做;我试过使用重新索引,set_levels;其他一些事情。我觉得这应该是一件简单的事情,所以我必须在内置函数的选项中遗漏一些东西(这将是我的首选方法,但此时即使是“hacky”就足够了!)。
一个选项是
df = df1.reset_index()
df['class'] = df['class'].astype(int).diff().fillna(0).ne(0).cumsum().astype(int)
df = df.set_index(['class', 'name'])
>>> df
index High Average
class name
0 Albert 0 98.8 97.9
Isaac 1 100.0 99.9
Charles 2 76.5 64.2
1 James 3 99.3 98.9
Paul 4 87.2 83.3
2 Wolfgang 5 98.8 96.5
Enrico 6 100.0 97.7
John 7 88.6 64.2
3 Marie 8 99.3 78.3
Carol 9 87.2 81.0
4 Solomon 10 78.8 65.9
Joseph 11 99.0 95.4
Phil 12 86.1 74.7
Danielle 13 97.9 91.1
这也不适用于索引,因此它是在 class
列中进行一些更改之前和之后设置的。
评论
在我的第一次尝试中,我使用了这个:
df = df.reset_index()
df['class'] = df['class'].astype(int).diff().abs().cumsum().fillna(0).astype(int)
df = df.set_index(['class', 'name'])
这将为给定示例生成正确的结果,因为“class”列中的差异仅为 -1
或 1
。如果差异不同于-1
、0
或 1
,这会生成错误的结果。
从第一个索引级别创建一个新索引,然后与第二个索引级别合并并将其设置为新索引:
import numpy as np
idx = df.index.get_level_values('class')
new_idx = pd.Index((idx != np.roll(idx, 1)).cumsum() -1, name='class')
df = df.set_index(pd.MultiIndex.from_arrays(
[new_idx, df.index.get_level_values('name')]))
>>> df
High Average
class name
0 Albert 98.8 97.9
Isaac 100.0 99.9
Charles 76.5 64.2
1 James 99.3 98.9
Paul 87.2 83.3
2 Wolfgang 98.8 96.5
Enrico 100.0 97.7
John 88.6 64.2
3 Marie 99.3 78.3
Carol 87.2 81.0
4 Solomon 78.8 65.9
Joseph 99.0 95.4
Phil 86.1 74.7
Danielle 97.9 91.1
@It_is_Chris
改进了解决方案
详情:
>>> idx.tolist()
['0', '0', '0', '1', '1', '0', '0', '0', '1', '1', '2', '2', '2', '2']
>>> np.roll(idx, 1).tolist()
['2', '0', '0', '0', '1', '1', '0', '0', '0', '1', '1', '2', '2', '2']
现在比较两个列表的每个元素:'0' != '2'
、'0' != '0'
直到 '2' != '2'
。你有一个布尔掩码
>>> (idx != np.roll(idx, 1)).tolist()
[True, False, False, True, False, True, False,
False, True, False, True, False, False, False]
在此布尔掩码上应用累加和减一以获得新索引:
>>> ((idx != np.roll(idx, 1)).cumsum() - 1).tolist()
[0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 4]
现在用新索引和第二级重建索引:
>>> pd.MultiIndex.from_arrays([new_idx, df.index.get_level_values('name')])
MultiIndex([(0, 'Albert'),
(0, 'Isaac'),
(0, 'Charles'),
(1, 'James'),
(1, 'Paul'),
(2, 'Wolfgang'),
(2, 'Enrico'),
(2, 'John'),
(3, 'Marie'),
(3, 'Carol'),
(4, 'Solomon'),
(4, 'Joseph'),
(4, 'Phil'),
(4, 'Danielle')],
names=['class', 'name'])
一个选项是重置索引,然后从中创建组,然后重新索引回来
df2 = df.reset_index()
df2['class'] = (df2['class'] != df2['class'].shift()).cumsum() - 1
df = df2.set_index(['class', 'name'])
>>>
High Average
class name
0 Albert 98.8 97.9
Isaac 100.0 99.9
Charles 76.5 64.2
1 James 99.3 98.9
Paul 87.2 83.3
2 Wolfgang 98.8 96.5
Enrico 100.0 97.7
John 88.6 64.2
3 Marie 99.3 78.3
Carol 87.2 81.0
4 Solomon 78.8 65.9
Joseph 99.0 95.4
Phil 86.1 74.7
Danielle 97.9 91.1
我有一个由多个数据帧构建的 MultiIndex DataFrame,我需要重置第一个索引。除了第一个索引,我不想改变任何东西;应保留其他所有内容的整个结构和顺序。
我目前的情况是这样的:
index = pd.MultiIndex.from_tuples([('0', 'Albert'),
('0', 'Isaac'),
('0', "Charles"),
('1', 'James'),
('1', 'Paul'),
('0', 'Wolfgang'),
('0', 'Enrico'),
('0', "John"),
('1', 'Marie'),
('1', 'Carol'),
('2', "Solomon"),
("2", "Joseph"),
("2", "Phil"),
('2', 'Danielle')],
names=['class', 'name'])
columns = ('High', 'Average')
df = pd.DataFrame([(98.8, 97.9),
(100.0, 99.9),
(76.5, 64.2),
(99.3, 98.9),
(87.2, 83.3),
(98.8, 96.5),
(100.0, 97.7),
(88.6, 64.2),
(99.3, 78.3),
(87.2, 81.0),
(78.8, 65.9),
(99.0, 95.4),
(86.1, 74.7),
(97.9, 91.1)],
index=index,
columns=columns)
这给出了一个如下所示的数据框:
High Average
class name
0 Albert 98.8 97.9
Isaac 100.0 99.9
Charles 76.5 64.2
1 James 99.3 98.9
Paul 87.2 83.3
0 Wolfgang 98.8 96.5
Enrico 100.0 97.7
John 88.6 64.2
1 Marie 99.3 78.3
Carol 87.2 81.0
2 Solomon 78.8 65.9
Joseph 99.0 95.4
Phil 86.1 74.7
Danielle 97.9 91.1
我只想将“class”索引重置为从 0 开始并迭代到“class”中的最后一个条目。最终结果应如下所示:
High Average
class name
0 Albert 98.8 97.9
Isaac 100.0 99.9
Charles 76.5 64.2
1 James 99.3 98.9
Paul 87.2 83.3
2 Wolfgang 98.8 96.5
Enrico 100.0 97.7
John 88.6 64.2
3 Marie 99.3 78.3
Carol 87.2 81.0
4 Solomon 78.8 65.9
Joseph 99.0 95.4
Phil 86.1 74.7
Danielle 97.9 91.1
我不知道该怎么做;我试过使用重新索引,set_levels;其他一些事情。我觉得这应该是一件简单的事情,所以我必须在内置函数的选项中遗漏一些东西(这将是我的首选方法,但此时即使是“hacky”就足够了!)。
一个选项是
df = df1.reset_index()
df['class'] = df['class'].astype(int).diff().fillna(0).ne(0).cumsum().astype(int)
df = df.set_index(['class', 'name'])
>>> df
index High Average
class name
0 Albert 0 98.8 97.9
Isaac 1 100.0 99.9
Charles 2 76.5 64.2
1 James 3 99.3 98.9
Paul 4 87.2 83.3
2 Wolfgang 5 98.8 96.5
Enrico 6 100.0 97.7
John 7 88.6 64.2
3 Marie 8 99.3 78.3
Carol 9 87.2 81.0
4 Solomon 10 78.8 65.9
Joseph 11 99.0 95.4
Phil 12 86.1 74.7
Danielle 13 97.9 91.1
这也不适用于索引,因此它是在 class
列中进行一些更改之前和之后设置的。
评论
在我的第一次尝试中,我使用了这个:
df = df.reset_index()
df['class'] = df['class'].astype(int).diff().abs().cumsum().fillna(0).astype(int)
df = df.set_index(['class', 'name'])
这将为给定示例生成正确的结果,因为“class”列中的差异仅为 -1
或 1
。如果差异不同于-1
、0
或 1
,这会生成错误的结果。
从第一个索引级别创建一个新索引,然后与第二个索引级别合并并将其设置为新索引:
import numpy as np
idx = df.index.get_level_values('class')
new_idx = pd.Index((idx != np.roll(idx, 1)).cumsum() -1, name='class')
df = df.set_index(pd.MultiIndex.from_arrays(
[new_idx, df.index.get_level_values('name')]))
>>> df
High Average
class name
0 Albert 98.8 97.9
Isaac 100.0 99.9
Charles 76.5 64.2
1 James 99.3 98.9
Paul 87.2 83.3
2 Wolfgang 98.8 96.5
Enrico 100.0 97.7
John 88.6 64.2
3 Marie 99.3 78.3
Carol 87.2 81.0
4 Solomon 78.8 65.9
Joseph 99.0 95.4
Phil 86.1 74.7
Danielle 97.9 91.1
@It_is_Chris
改进了解决方案详情:
>>> idx.tolist()
['0', '0', '0', '1', '1', '0', '0', '0', '1', '1', '2', '2', '2', '2']
>>> np.roll(idx, 1).tolist()
['2', '0', '0', '0', '1', '1', '0', '0', '0', '1', '1', '2', '2', '2']
现在比较两个列表的每个元素:'0' != '2'
、'0' != '0'
直到 '2' != '2'
。你有一个布尔掩码
>>> (idx != np.roll(idx, 1)).tolist()
[True, False, False, True, False, True, False,
False, True, False, True, False, False, False]
在此布尔掩码上应用累加和减一以获得新索引:
>>> ((idx != np.roll(idx, 1)).cumsum() - 1).tolist()
[0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 4]
现在用新索引和第二级重建索引:
>>> pd.MultiIndex.from_arrays([new_idx, df.index.get_level_values('name')])
MultiIndex([(0, 'Albert'),
(0, 'Isaac'),
(0, 'Charles'),
(1, 'James'),
(1, 'Paul'),
(2, 'Wolfgang'),
(2, 'Enrico'),
(2, 'John'),
(3, 'Marie'),
(3, 'Carol'),
(4, 'Solomon'),
(4, 'Joseph'),
(4, 'Phil'),
(4, 'Danielle')],
names=['class', 'name'])
一个选项是重置索引,然后从中创建组,然后重新索引回来
df2 = df.reset_index()
df2['class'] = (df2['class'] != df2['class'].shift()).cumsum() - 1
df = df2.set_index(['class', 'name'])
>>>
High Average
class name
0 Albert 98.8 97.9
Isaac 100.0 99.9
Charles 76.5 64.2
1 James 99.3 98.9
Paul 87.2 83.3
2 Wolfgang 98.8 96.5
Enrico 100.0 97.7
John 88.6 64.2
3 Marie 99.3 78.3
Carol 87.2 81.0
4 Solomon 78.8 65.9
Joseph 99.0 95.4
Phil 86.1 74.7
Danielle 97.9 91.1