为简单起见的假设:
mux = pd.MultiIndex.from_arrays([
list('aaaabbbbbccddddd'),
list('tuvwtuvwtuvwtuvw')
], names=['one', 'two'])
df = pd.DataFrame({'col': np.arange(len(mux))}, mux)
col
one two
a t 0
u 1
v 2
w 3
b t 4
u 5
v 6
w 7
t 8
c u 9
v 10
d w 11
t 12
u 13
v 14
w 15
col
one two
a t 0
u 1
v 2
w 3
col
two
t 0
u 1
v 2
w 3
col
one two
a t 0
b t 4
t 8
d t 12
col
one two
b t 4
u 5
v 6
w 7
t 8
d w 11
t 12
u 13
v 14
w 15
问题2b
我如何获得级别“二”中对应于“t”和“w”的所有值?
col
one two
a t 0
w 3
b t 4
w 7
t 8
d w 11
t 12
w 15
如何从df
检索横截面,即具有索引特定值的单行?具体来说,如何检索('c','u')
的横截面,由
col
one two
c u 9
如何选择与('c','u')
和('a','w')
相对应的两行?
col
one two
c u 9
a w 3
col
one two
a t 0
u 1
v 2
w 3
b t 4
t 8
d t 12
col
one two
a u 1
v 2
b u 5
v 6
d w 11
w 15
np.random.seed(0)
mux2 = pd.MultiIndex.from_arrays([
list('aaaabbbbbccddddd'),
np.random.choice(10, size=16)
], names=['one', 'two'])
df2 = pd.DataFrame({'col': np.arange(len(mux2))}, mux2)
col
one two
a 5 0
0 1
3 2
3 3
b 7 4
9 5
3 6
5 7
2 8
c 4 9
7 10
d 6 11
8 12
8 13
1 14
6 15
col
one two
b 7 4
9 5
c 7 10
d 6 11
8 12
8 13
6 15
注
本帖的结构如下:
对于有兴趣了解附加功能、实现细节和手头主题的其他信息的读者,将包括注释(非常类似于本文)。这些笔记是通过搜索文档和发现各种晦涩难懂的特征,并根据我自己(承认有限)的经验汇编而成的。
dataframe.xs
-从series/dataframe中提取一个特定的截面。
dataframe.query
-动态地指定切片和/或筛选操作(例如,作为动态计算的html" target="_blank">表达式。在某些情况下比在其他情况下更适用。也请参阅文档的这一节,以查询多索引。
使用multiindex.get_level_values
生成带有掩码的布尔索引(通常与index.isin
结合使用,尤其是在使用多个值进行筛选时)。这在某些情况下也很有用。
从这四个习语的角度来看各种切片和过滤问题将是有益的,可以更好地理解什么可以应用于给定的情况。理解并不是所有的习语在每种情况下都同样有效(如果有的话)是非常重要的。如果一个习语没有被列为下面问题的潜在解决方案,这意味着习语不能有效地应用于该问题。
如何选择级别“一”中具有“A”的行?
col
one two
a t 0
u 1
v 2
w 3
您可以使用loc
,作为适用于大多数情况的通用解决方案:
df.loc[['a']]
TypeError: Expected tuple, got str
df.xs('a', level=0, axis=0, drop_level=False)
# df.xs('a', drop_level=False)
这里,需要drop_level=false
参数来防止XS
删除结果中的级别“一”(我们切片的级别)。
这里的另一个选项是使用query
:
df.query("one == 'a'")
如果索引没有名称,则需要将查询字符串更改为“ilevel_0=='a'”
。
df[df.index.get_level_values('one') == 'a']
# If your levels are unnamed, or if you need to select by position (not label),
# df[df.index.get_level_values(0) == 'a']
col
two
t 0
u 1
v 2
w 3
df.loc['a'] # Notice the single string argument instead the list.
或者,
df.xs('a', level=0, axis=0, drop_level=True)
# df.xs('a')
注意,我们可以省略drop_level
参数(默认情况下假定为true
)。
注意
您可能会注意到,经过筛选的DataFrame可能仍然具有所有级别,即使在打印出DataFrame时没有显示这些级别。例如,
v = df.loc[['a']]
print(v)
col
one two
a t 0
u 1
v 2
w 3
print(v.index)
MultiIndex(levels=[['a', 'b', 'c', 'd'], ['t', 'u', 'v', 'w']],
labels=[[0, 0, 0, 0], [0, 1, 2, 3]],
names=['one', 'two'])
v.index = v.index.remove_unused_levels()
print(v.index)
MultiIndex(levels=[['a'], ['t', 'u', 'v', 'w']],
labels=[[0, 0, 0, 0], [0, 1, 2, 3]],
names=['one', 'two'])
col
one two
a t 0
b t 4
t 8
d t 12
df.loc[(slice(None), 't'), :]
它只是工作!™,但它是笨重的。我们可以使用pd.indexslice
API简化更自然的切片语法。
idx = pd.IndexSlice
df.loc[idx[:, 't'], :]
这里干净多了。
注意
为什么需要跨列的尾随片:
?这是因为,loc
可用于沿着两个轴进行选择和切片(axis=0
或axis=1
)。如果不明确表示要在哪个轴上进行切片,操作就会变得模棱两可。请参阅切片文档中的红色大框。
df.loc(axis=0)[pd.IndexSlice[:, 't']]
使用xs
,它是
df.xs('t', axis=0, level=1, drop_level=False)
对于query
,它是
df.query("two == 't'")
# Or, if the first level has no name,
# df.query("ilevel_1 == 't'")
最后,使用get_level_values
,您可以
df[df.index.get_level_values('two') == 't']
# Or, to perform selection by position/integer,
# df[df.index.get_level_values(1) == 't']
col
one two
b t 4
u 5
v 6
w 7
t 8
d w 11
t 12
u 13
v 14
w 15
df.loc[['b', 'd']]
items = ['b', 'd']
df.query("one in @items")
# df.query("one == @items", parser='pandas')
# df.query("one in ['b', 'd']")
# df.query("one == ['b', 'd']", parser='pandas')
并且,使用get_level_values
+index.isin
:
df[df.index.get_level_values("one").isin(['b', 'd'])]
我将如何获得所有的值对应的“T”和“W”在级别“二”?
col
one two
a t 0
w 3
b t 4
w 7
t 8
d w 11
t 12
w 15
对于loc
,这只能与pd.indexslice
结合。
df.loc[pd.IndexSlice[:, ['t', 'w']], :]
items = ['t', 'w']
df.query("two in @items")
# df.query("two == @items", parser='pandas')
# df.query("two in ['t', 'w']")
# df.query("two == ['t', 'w']", parser='pandas')
df[df.index.get_level_values('two').isin(['t', 'w'])]
如何从df
检索横截面,即具有索引特定值的单行?具体来说,如何检索('c','u')
的横截面,由
col
one two
c u 9
通过指定一组键来使用loc
:
df.loc[('c', 'u'), :]
或者,
df.loc[pd.IndexSlice[('c', 'u')]]
PerformanceWarning: indexing past lexsort depth may impact performance.
df_sort = df.sort_index()
df_sort.loc[('c', 'u')]
df.xs(('c', 'u'))
df.query("one == 'c' and two == 'u'")
你现在可以看到,这将是相对难以概括的。但对于这个特殊的问题仍然可以。
对于跨越多个级别的访问,仍然可以使用get_level_values
,但不建议使用:
m1 = (df.index.get_level_values('one') == 'c')
m2 = (df.index.get_level_values('two') == 'u')
df[m1 & m2]
如何选择与('c','u')
和('a','w')
相对应的两行?
col
one two
c u 9
a w 3
df.loc[[('c', 'u'), ('a', 'w')]]
# df.loc[pd.IndexSlice[[('c', 'u'), ('a', 'w')]]]
cses = [('c', 'u'), ('a', 'w')]
levels = ['one', 'two']
# This is a useful check to make in advance.
assert all(len(levels) == len(cs) for cs in cses)
query = '(' + ') or ('.join([
' and '.join([f"({l} == {repr(c)})" for l, c in zip(levels, cs)])
for cs in cses
]) + ')'
print(query)
# ((one == 'c') and (two == 'u')) or ((one == 'a') and (two == 'w'))
df.query(query)
如果我有多个级别呢?
在这种情况下,一个选项是使用Droplevel
删除您没有检查的级别,然后使用isin
测试成员资格,然后对最终结果进行布尔索引。
df[df.index.droplevel(unused_level).isin([('c', 'u'), ('a', 'w')])]
如何检索与级别“一”中的“A”或级别“二”中的“T”对应的所有行?
col
one two
a t 0
u 1
v 2
w 3
b t 4
t 8
d t 12
这实际上很难用loc
来实现,同时确保正确性并保持代码的清晰度。df.loc[pd.indexslice['a',not']]
不正确,它被解释为df.loc[pd.indexslice[('a',not')]]
(即选择横截面)。您可以考虑使用pd.concat
单独处理每个标签的解决方案:
pd.concat([
df.loc[['a'],:], df.loc[pd.IndexSlice[:, 't'],:]
])
col
one two
a t 0
u 1
v 2
w 3
t 0 # Does this look right to you? No, it isn't!
b t 4
t 8
d t 12
但是您会注意到其中一行是重复的。这是因为该行满足两个切片条件,因此出现了两次。相反,您需要做的是
v = pd.concat([
df.loc[['a'],:], df.loc[pd.IndexSlice[:, 't'],:]
])
v[~v.index.duplicated()]
但是,如果您的DataFrame本身包含重复的索引(您想要的),那么这将不会保留它们。极其谨慎地使用。
对于query
,这非常简单:
df.query("one == 'a' or two == 't'")
m1 = (df.index.get_level_values('one') == 'a')
m2 = (df.index.get_level_values('two') == 't')
df[m1 | m2]
col
one two
a u 1
v 2
b u 5
v 6
d w 11
w 15
通常,像这样的切片问题需要显式地将键列表传递给loc
。一种方法是:
keys = [('a', 'u'), ('a', 'v'), ('b', 'u'), ('b', 'v'), ('d', 'w')]
df.loc[keys, :]
如果您想保存一些键入,您将认识到有一种模式可以对“a”、“B”及其子层进行切片,因此我们可以将切片任务分成两个部分,并concat
得到结果:
pd.concat([
df.loc[(('a', 'b'), ('u', 'v')), :],
df.loc[('d', 'w'), :]
], axis=0)
“a”和“b”的切片规范(('a','b'),('u','v'))
,因为索引的子级别对每个级别都是相同的。
如何获取级别“Two”中的值大于5的所有行?
col
one two
b 7 4
9 5
c 7 10
d 6 11
8 12
8 13
6 15
这可以使用query
完成,
df2.query("two > 5")
和get_level_values
。
df2[df2.index.get_level_values('two') > 5]
如果需要对multiindex
列进行切片,该怎么办?
np.random.seed(0)
mux3 = pd.MultiIndex.from_product([
list('ABCD'), list('efgh')
], names=['one','two'])
df3 = pd.DataFrame(np.random.choice(10, (3, len(mux))), columns=mux3)
print(df3)
one A B C D
two e f g h e f g h e f g h e f g h
0 5 0 3 3 7 9 3 5 2 4 7 6 8 8 1 6
1 7 7 8 1 5 9 8 9 4 3 0 3 5 0 2 3
2 8 1 3 3 3 7 0 1 9 9 0 4 7 3 2 7
以下是您需要对四个习惯用法进行的更改,以便它们能够与列一起工作。
>
要使用loc
进行切片,请使用
df3.loc[:, ....] # Notice how we slice across the index with `:`.
或者,
df3.loc[:, pd.IndexSlice[...]]
df.loc[:, {condition}]
df3.T.query(...).T
问题内容: 我在不同的列中有数据,但是我不知道如何提取数据以将其保存在另一个变量中。 如何选择然后将其保存到df1中? 我试过了 似乎没有任何工作。 问题答案: 列名(字符串)无法按照你尝试的方式进行切片。 在这里,你有两个选择。如果从上下文中知道要切出哪些变量,则可以通过将列表传递给语法来仅返回那些列的视图。 或者,如果需要对它们进行数字索引而不是按其名称进行索引(例如,你的代码应在不知道前两列
问题内容: 我有以下pd.DataFrame: 它具有带有和层次结构级别的MultiIndex列。该标签从0到n,并为每个标签,有两个和列。 我想子选择此DataFrame的所有(或)列。 问题答案: 有一种方法可以与布尔索引一起使用,以获得预期的结果。
我试图提取数据帧中的第7到14列。然而 只给出第1到第3行。 有人知道如果我想找到这些专栏我该怎么做吗? 我知道如何使用列名,如,但由于名称太多,我只想在R中键入类似的内容。 提前感谢。
是否有任何方法可以在数据框中按索引(即整数)选择行,按列名选择列? 我尝试使用loc,但它返回一个错误,我知道iloc只适用于索引。 这是数据帧df的第一行。我愿意选择第一行,名为“Volume”的列,并尝试使用df.loc[0,'Volume']
问题内容: 摘要:这不起作用: 但是这样做: 为什么? 再生产: 这不起作用: 但是这样做: 链接到笔记本 我的问题是: 为什么只有第二种方式起作用?我似乎看不到选择/索引逻辑的差异。 版本是0.10.0 编辑:这不应该再这样了。从0.11版开始,提供。参见此处:http : //pandas.pydata.org/pandas- docs/stable/indexing.html 问题答案: 大
我正在尝试从多索引数据帧中仅使用一个索引来创建新的数据帧。 理想情况下,我想要这样的东西: 和: 基本上,我想删除除level之外的多索引的所有其他索引。有没有一个简单的方法可以做到这一点?