有人可以解释这三种切片方法有何不同? 我见过the docs, 而且我已经看过these answers,但我仍然发现自己无法解释三者是如何不同的。对我来说,它们在很大程度上似乎是可以互换的,因为它们处于较低的切片水平。
例如,假设我们想获得DataFrame
的前五行。这三个都是如何运作的?
df.loc[:5]
df.ix[:5]
df.iloc[:5]
有人可以提出三种使用区别更清楚的案例吗?
答案 0 :(得分:758)
注意:在pandas版本0.20.0及更高版本中,ix
为deprecated,我们鼓励使用loc
和iloc
。我已经将这个答案的部分内容完整地描述为ix
,作为早期版本熊猫用户的参考。下面添加了示例,显示ix
的替代方法。
首先,这里回顾一下三种方法:
loc
从索引中获取带有特定标签的行(或列)。 iloc
获取索引中特定位置的行(或列)(因此只需要整数)。ix
通常会尝试表现得像loc
,但如果索引中没有标签,则会回归到iloc
的行为。重要的是要注意一些可能使ix
使用起来有些棘手的细微之处:
如果索引是整数类型,ix
将仅使用基于标签的索引,而不会回退到基于位置的索引。如果标签不在索引中,则会引发错误。
如果索引不包含仅整数,则给定一个整数,ix
将立即使用基于位置的索引而不是基于标签的索引。但是,如果ix
被赋予其他类型(例如字符串),则可以使用基于标签的索引。
为了说明三种方法之间的差异,请考虑以下系列:
>>> s = pd.Series(np.nan, index=[49,48,47,46,45, 1, 2, 3, 4, 5])
>>> s
49 NaN
48 NaN
47 NaN
46 NaN
45 NaN
1 NaN
2 NaN
3 NaN
4 NaN
5 NaN
我们将使用整数值3
来查看切片。
在这种情况下,s.iloc[:3]
会返回前3行(因为它将3视为一个位置),而s.loc[:3]
会返回前8行(因为它将3视为标签):< / p>
>>> s.iloc[:3] # slice the first three rows
49 NaN
48 NaN
47 NaN
>>> s.loc[:3] # slice up to and including label 3
49 NaN
48 NaN
47 NaN
46 NaN
45 NaN
1 NaN
2 NaN
3 NaN
>>> s.ix[:3] # the integer is in the index so s.ix[:3] works like loc
49 NaN
48 NaN
47 NaN
46 NaN
45 NaN
1 NaN
2 NaN
3 NaN
注意s.ix[:3]
返回与s.loc[:3]
相同的系列,因为它首先查找标签而不是位置(并且s
的索引是整数类型)。
如果我们尝试使用索引中的整数标签(例如6
),该怎么办?
此处s.iloc[:6]
按预期返回系列的前6行。但是,s.loc[:6]
会引发KeyError,因为6
不在索引中。
>>> s.iloc[:6]
49 NaN
48 NaN
47 NaN
46 NaN
45 NaN
1 NaN
>>> s.loc[:6]
KeyError: 6
>>> s.ix[:6]
KeyError: 6
根据上面提到的细微差别,s.ix[:6]
现在引发了一个KeyError,因为它尝试像loc
一样工作,但无法在索引中找到6
。因为我们的索引是整数类型ix
,所以不会像iloc
一样回归。
但是,如果我们的索引是混合类型,则给定整数ix
会立即表现为iloc
而不是引发KeyError:
>>> s2 = pd.Series(np.nan, index=['a','b','c','d','e', 1, 2, 3, 4, 5])
>>> s2.index.is_mixed() # index is mix of different types
True
>>> s2.ix[:6] # now behaves like iloc given integer
a NaN
b NaN
c NaN
d NaN
e NaN
1 NaN
请注意,ix
仍然可以接受非整数并且行为类似于loc
:
>>> s2.ix[:'c'] # behaves like loc given non-integer
a NaN
b NaN
c NaN
作为一般建议,如果您仅使用标签进行索引,或仅使用整数位置编制索引,请坚持使用loc
或iloc
以避免意外结果 - 请勿使用{{1} }。
有时给定一个DataFrame,您需要为行和列混合标签和位置索引方法。
例如,请考虑以下DataFrame。如何最好地将行切割为包括&#39; c&#39; 和取前四列?
ix
在早期版本的pandas中(0.20.0之前)>>> df = pd.DataFrame(np.nan,
index=list('abcde'),
columns=['x','y','z', 8, 9])
>>> df
x y z 8 9
a NaN NaN NaN NaN NaN
b NaN NaN NaN NaN NaN
c NaN NaN NaN NaN NaN
d NaN NaN NaN NaN NaN
e NaN NaN NaN NaN NaN
让你可以非常巧妙地做到这一点 - 我们可以按标签和列的位置对行进行切片(注意列为ix
}将默认为基于位置的切片,因为ix
不是列名称):
4
在pandas的更高版本中,我们可以使用>>> df.ix[:'c', :4]
x y z 8
a NaN NaN NaN NaN
b NaN NaN NaN NaN
c NaN NaN NaN NaN
和另一种方法的帮助来实现此结果:
iloc
get_loc()
是一种索引方法,意思是&#34;获取该索引中标签的位置&#34;。请注意,由于使用>>> df.iloc[:df.index.get_loc('c') + 1, :4]
x y z 8
a NaN NaN NaN NaN
b NaN NaN NaN NaN
c NaN NaN NaN NaN
进行切片不包含其端点,因此如果我们需要行&#39; c&#39;同样。
熊猫还有其他例子。文档here。
答案 1 :(得分:108)
iloc
基于整数定位。因此,无论您的行标签是什么,您都可以通过
df.iloc[0]
或最后五行
df.iloc[-5:]
您也可以在列上使用它。这将检索第3列:
df.iloc[:, 2] # the : in the first position indicates all rows
您可以将它们组合起来以获得行和列的交叉点:
df.iloc[:3, :3] # The upper-left 3 X 3 entries (assuming df has 3+ rows and columns)
另一方面,.loc
使用命名索引。让我们设置一个数据框,其中包含字符串作为行标签和列标签:
df = pd.DataFrame(index=['a', 'b', 'c'], columns=['time', 'date', 'name'])
然后我们可以通过
获得第一行df.loc['a'] # equivalent to df.iloc[0]
和<{p>的'date'
列的后两行
df.loc['b':, 'date'] # equivalent to df.iloc[1:, 1]
等等。现在,值得指出的是DataFrame
的默认行和列索引是0的整数,在这种情况下iloc
和loc
将以相同的方式工作。这就是为什么你的三个例子是等价的。 如果您有非数字索引,例如字符串或日期时间, df.loc[:5]
会引发错误。
此外,您只需使用数据框的__getitem__
:
df['time'] # equivalent to df.loc[:, 'time']
现在假设您要混合位置和命名索引,即使用行上的名称和列上的位置进行索引(澄清一下,我的意思是从我们的数据框中选择,而不是在行索引中创建包含字符串的数据框)和列索引中的整数)。这是.ix
的来源:
df.ix[:2, 'time'] # the first two rows of the 'time' column
我认为值得一提的是你也可以将布尔向量传递给loc
方法。例如:
b = [True, False, True]
df.loc[b]
将返回df
的第1行和第3行。这相当于df[b]
的选择,但它也可以用于通过布尔向量进行赋值:
df.loc[b, 'name'] = 'Mary', 'John'
答案 2 :(得分:82)
在我看来,接受的答案令人困惑,因为它使用只有缺失值的DataFrame。我也不喜欢.iloc
的基于位置一词,而是更喜欢整数位置,因为它更具描述性,而且恰好是.iloc
代表。关键词是INTEGER - .iloc
需要INTEGERS。
有关更多信息,请参阅我非常详细的blog series子集选择
由于.ix
已被弃用,我们只关注.loc
和.iloc
之间的差异。
在我们讨论差异之前,了解DataFrames有标签可以帮助识别每个列和每个索引,这一点非常重要。我们来看看示例DataFrame:
df = pd.DataFrame({'age':[30, 2, 12, 4, 32, 33, 69],
'color':['blue', 'green', 'red', 'white', 'gray', 'black', 'red'],
'food':['Steak', 'Lamb', 'Mango', 'Apple', 'Cheese', 'Melon', 'Beans'],
'height':[165, 70, 120, 80, 180, 172, 150],
'score':[4.6, 8.3, 9.0, 3.3, 1.8, 9.5, 2.2],
'state':['NY', 'TX', 'FL', 'AL', 'AK', 'TX', 'TX']
},
index=['Jane', 'Nick', 'Aaron', 'Penelope', 'Dean', 'Christina', 'Cornelia'])
粗体中的所有字词都是标签。标签age
,color
,food
,height
,score
和state
用于列 。其他标签Jane
,Nick
,Aaron
,Penelope
,Dean
,Christina
,Cornelia
用于<强>索引强>
在DataFrame中选择特定行的主要方法是使用.loc
和.iloc
索引器。这些索引器中的每一个也可用于同时选择列,但现在更容易关注行。此外,每个索引器都使用一组括号,这些括号紧跟其名称后进行选择。
我们将首先讨论.loc
索引器,它仅通过索引或列标签选择数据。在我们的示例DataFrame中,我们提供了有意义的名称作为索引的值。许多DataFrames没有任何有意义的名称,而是默认只有从0到n-1的整数,其中n是DataFrame的长度。
您可以使用三种不同的输入.loc
使用字符串
选择带有.loc的单行要选择单行数据,请将索引标签放在.loc
后面的括号内。
df.loc['Penelope']
这会将数据行作为Series
返回age 4
color white
food Apple
height 80
score 3.3
state AL
Name: Penelope, dtype: object
使用.loc和字符串列表选择多行
df.loc[['Cornelia', 'Jane', 'Dean']]
这将返回一个DataFrame,其中的行按列表中指定的顺序排列:
使用带有切片表示法的.loc选择多行
切片表示法由开始,停止和步骤值定义。按标签切片时,pandas在返回时包含停止值。以下切片从Aaron到Dean,包括在内。其步长未明确定义,但默认为1。
df.loc['Aaron':'Dean']
复杂切片的采用方式与Python列表相同。
现在转向.iloc
。 DataFrame中的每一行和每列数据都有一个定义它的整数位置。 这是在输出中直观显示的标签的补充。整数位置只是从0开始的顶部/左侧的行数/列数。
您可以使用三种不同的输入.iloc
选择带有整数
的.iloc的单行df.iloc[4]
这将第5行(整数位置4)作为Series
返回age 32
color gray
food Cheese
height 180
score 1.8
state AK
Name: Dean, dtype: object
使用带有整数列表的.iloc选择多行
df.iloc[[2, -2]]
这将返回第三行和第二行到最后一行的DataFrame:
使用带有切片表示法的.iloc选择多行
df.iloc[:5:3]
.loc/.iloc
的一个优秀能力是它们能够同时选择行和列。在上面的示例中,从每个选择中返回所有列。我们可以选择具有与行相同类型输入的列。我们只需要使用逗号分隔行和列选择。
例如,我们可以选择行Jane,而Dean只选择列高度,分数和状态,如下所示:
df.loc[['Jane', 'Dean'], 'height':]
这使用行的标签列表和列
的切片表示法我们可以自然地使用.iloc
仅使用整数执行类似的操作。
df.iloc[[1,4], 2]
Nick Lamb
Dean Cheese
Name: food, dtype: object
.ix
用于与标签和整数位置同时进行选择,这些选项虽然有用但有时令人困惑和含糊不清,幸好它已被弃用。如果您需要使用混合标签和整数位置进行选择,则必须同时选择标签或整数位置。
例如,如果我们想要选择行Nick
和Cornelia
以及第2列和第4列,我们可以使用.loc
将整数转换为带有以下内容的标签:
col_names = df.columns[[2, 4]]
df.loc[['Nick', 'Cornelia'], col_names]
或者,使用get_loc
索引方法将索引标签转换为整数。
labels = ['Nick', 'Cornelia']
index_ints = [df.index.get_loc(label) for label in labels]
df.iloc[index_ints, [2, 4]]
.loc索引器也可以进行布尔选择。例如,如果我们有兴趣查找年龄超过30的所有行并仅返回food
和score
列,我们可以执行以下操作:
df.loc[df['age'] > 30, ['food', 'score']]
您可以使用.iloc
复制此内容,但不能将其传递给布尔系列。您必须将布尔系列转换为numpy数组,如下所示:
df.iloc[(df['age'] > 30).values, [2, 4]]
可以使用.loc/.iloc
进行列选择。您可以使用冒号选择所有行:
df.loc[:, 'color':'score':2]
[]
也可以选择行和列,但不能同时选择。大多数人都熟悉DataFrame索引运算符的主要用途,即选择列。字符串选择单个列作为Series,字符串列表选择多个列作为DataFrame。
df['food']
Jane Steak
Nick Lamb
Aaron Mango
Penelope Apple
Dean Cheese
Christina Melon
Cornelia Beans
Name: food, dtype: object
使用列表选择多列
df[['food', 'score']]
人们不太熟悉的是,当使用切片表示法时,选择是通过行标签或整数位置进行的。这非常令人困惑,我几乎从不使用它,但确实有效。
df['Penelope':'Christina'] # slice rows by label
df[2:6:2] # slice rows by integer location
.loc/.iloc
显式选择行是非常优选的。单独的索引操作符无法同时选择行和列。
df[3:5, 'color']
TypeError: unhashable type: 'slice'
答案 3 :(得分:0)
示例:
df1.iloc [:5]
df1.loc ['A','B']