在 Pandas 中将两个 MultiIndex 级别合并为一个
Merge two MultiIndex levels into one in Pandas
我有一个 Pandas 数据框,它是多索引的。第二层包含年份 ([2014,2015]),第三层包含月份 ([1, 2, .., 12])。我想将这两个合并为一个级别,例如 - [1/2014、2/2014 ...、6/2015]。这怎么可能呢?
我是 Pandas 的新手。搜索了很多但找不到类似的 question/solution.
编辑:我找到了一种方法来避免与 this question 的答案一起执行此操作。我应该以这种方式创建我的数据框。这似乎是通过 DateTime 进行索引的方式。
考虑 pd.MultiIndex
和 pd.DataFrame
、mux
和 df
mux = pd.MultiIndex.from_product([list('ab'), [2014, 2015], range(1, 3)])
df = pd.DataFrame(dict(A=1), mux)
print(df)
A
a 2014 1 1
2 1
2015 1 1
2 1
b 2014 1 1
2 1
2015 1 1
2 1
如果列表代表我们想要的索引,我们想为索引重新分配一个列表。
我要第一层一样
df.index.get_level_values(0)
我希望新的第 2 级是当前第 2 级和第 3 级的字符串连接,但顺序相反
df.index.map('{0[2]}/{0[1]}'.format)
df.index = [df.index.get_level_values(0), df.index.map('{0[2]}/{0[1]}'.format)]
print(df)
A
a 1/2014 1
2/2014 1
1/2015 1
2/2015 1
b 1/2014 1
2/2014 1
1/2015 1
2/2015 1
您可以使用列表理解来重构索引。例如,如果您有一个 3 级索引并且您想要合并第二级和第三级:
lst = [(i, f'{k}/{j}') for i, j, k in df.index]
df.index = pd.MultiIndex.from_tuples(lst)
这只是对piRSquared答案的解释。
df.index.map('{0[2]}/{0[1]}'.format)
map()
方法有一个参数,它是对索引的每个元素执行的回调。在此示例中,该方法恰好是 python built-in str.format
函数。
format
函数非常强大并且有很多功能(参见 docs)。其中一个功能是通过指定位置来引用位置参数。这意味着
"Hello {1}, I am {0}, how are you?".format("Bob", "Alice")
--> Hello Alice, I am Bob, how are you?
这就是 piRSquared 答案中零的来源。
通常,如果字符串中只替换一个参数,则不需要:
"Hello {}".format("Bob")
--> Hello Bob
但是,在这种情况下,还需要两个附加功能:
- 在同一个字符串中多次使用一个元素,并且
- 从参数中选择 sub-element。
由于 map
方法将单个索引条目作为参数传递给格式函数,因此 "{0[2]}"
引用该索引的第三个元素。
现在原始问题中的索引具有三个级别,因此传递给 format
函数的每个参数都是一个包含与行索引对应的三个元素的元组。
更冗长但等效的解决方案是:
df.index.map(lambda idx: str(idx[2]) + '/' + str(idx[1]))
或
df.index.map(lambda idx: f'{idx[2]}/{idx[1]}')
我有一个 Pandas 数据框,它是多索引的。第二层包含年份 ([2014,2015]),第三层包含月份 ([1, 2, .., 12])。我想将这两个合并为一个级别,例如 - [1/2014、2/2014 ...、6/2015]。这怎么可能呢?
我是 Pandas 的新手。搜索了很多但找不到类似的 question/solution.
编辑:我找到了一种方法来避免与 this question 的答案一起执行此操作。我应该以这种方式创建我的数据框。这似乎是通过 DateTime 进行索引的方式。
考虑 pd.MultiIndex
和 pd.DataFrame
、mux
和 df
mux = pd.MultiIndex.from_product([list('ab'), [2014, 2015], range(1, 3)])
df = pd.DataFrame(dict(A=1), mux)
print(df)
A
a 2014 1 1
2 1
2015 1 1
2 1
b 2014 1 1
2 1
2015 1 1
2 1
如果列表代表我们想要的索引,我们想为索引重新分配一个列表。
我要第一层一样
df.index.get_level_values(0)
我希望新的第 2 级是当前第 2 级和第 3 级的字符串连接,但顺序相反
df.index.map('{0[2]}/{0[1]}'.format)
df.index = [df.index.get_level_values(0), df.index.map('{0[2]}/{0[1]}'.format)]
print(df)
A
a 1/2014 1
2/2014 1
1/2015 1
2/2015 1
b 1/2014 1
2/2014 1
1/2015 1
2/2015 1
您可以使用列表理解来重构索引。例如,如果您有一个 3 级索引并且您想要合并第二级和第三级:
lst = [(i, f'{k}/{j}') for i, j, k in df.index]
df.index = pd.MultiIndex.from_tuples(lst)
这只是对piRSquared答案的解释。
df.index.map('{0[2]}/{0[1]}'.format)
map()
方法有一个参数,它是对索引的每个元素执行的回调。在此示例中,该方法恰好是 python built-in str.format
函数。
format
函数非常强大并且有很多功能(参见 docs)。其中一个功能是通过指定位置来引用位置参数。这意味着
"Hello {1}, I am {0}, how are you?".format("Bob", "Alice")
--> Hello Alice, I am Bob, how are you?
这就是 piRSquared 答案中零的来源。 通常,如果字符串中只替换一个参数,则不需要:
"Hello {}".format("Bob")
--> Hello Bob
但是,在这种情况下,还需要两个附加功能:
- 在同一个字符串中多次使用一个元素,并且
- 从参数中选择 sub-element。
由于 map
方法将单个索引条目作为参数传递给格式函数,因此 "{0[2]}"
引用该索引的第三个元素。
现在原始问题中的索引具有三个级别,因此传递给 format
函数的每个参数都是一个包含与行索引对应的三个元素的元组。
更冗长但等效的解决方案是:
df.index.map(lambda idx: str(idx[2]) + '/' + str(idx[1]))
或
df.index.map(lambda idx: f'{idx[2]}/{idx[1]}')