使用pandas进行索引的最佳实践

时间:2018-06-03 00:00:51

标签: python pandas

我想根据掩码idx选择行。我可以想到两种不同的可能性,使用iloc或仅使用括号。我已经在下面展示了两种可能性(在数据框df上)。它们是否同样可行?

idx = (df["timestamp"] >= 5) & (df["timestamp"] <= 10)
idx = idx.values
hr = df["hr"].iloc[idx]
timestamps = df["timestamp"].iloc[idx]

或以下一个:

idx = (df["timestamp"] >= 5) & (df["timestamp"] <= 10)
hr = df["hr"][idx]
timestamps = df["timestamp"][idx]

2 个答案:

答案 0 :(得分:4)

不,他们不一样。一个使用直接语法,而另一个依赖于链式索引。

关键点是:

  • pd.DataFrame.iloc主要用于基于位置的整数索引。
  • pd.DataFrame.loc最常用于标签或布尔数组。
  • 链式索引,即通过df[x][y],是explicitly discouraged,永远不需要。
  • idx.values返回numpy系列的idx数组表示。这不能提供.iloc,也无需提供.loc,这可以直接idx

下面是两个可行的例子。在任一示例中,您都可以使用类似的语法来屏蔽数据框或系列。例如,df['hr'].loc[mask]df.loc[mask]一样有效。

ILOC

这里我们使用numpy.where来提取布尔系列中True元素的整数索引。 iloc确实接受布尔数组,但在我看来,这不太清楚; “i”代表整数。

idx = (df['timestamp'] >= 5) & (df['timestamp'] <= 10)
mask = np.where(idx)[0]
df = df.iloc[mask]

LOC

当我们已经通过特定系列查询时,使用loc更自然。

mask = (df['timestamp'] >= 5) & (df['timestamp'] <= 10)
df = df.loc[mask]
  • 仅屏蔽行时,您可以完全省略loc访问者并使用df[mask]
  • 如果按行屏蔽并过滤列,则可以使用df.loc[mask, 'col_name']

Indexing and Selecting Datapandas的基础:阅读官方文档是无可替代的。

答案 1 :(得分:2)

不要混合基于__getitem__的索引和(i)基于loc的。使用其中一个。我更喜欢(i)通过索引访问时的loc,以及当您按列访问或使用布尔索引时__getitem__

以下是一些常见的索引编制方法及其相应的更正。

df.iloc[idx].loc[:, column]  
df.iloc[idx][column]      
df[column][idx]           
df[column].iloc[idx]      

当您尝试分配这些解决方案时,大多数这些解决方案都会导致管道问题(主要是以SettingWithCopyWarning的形式),因为这些解决方案会创建视图并与他们正在查看的原始DataFrame绑定。

所有这些版本的正确解决方案是df.iloc[idx, df.columns.get_loc(column)]请注意idx是一个整数索引数组,column是一个字符串标签。同样适用于loc

如果您有一系列布尔值,请改用loc,如下所示:df.loc[boolean_idx, column]

此外,这些都很好:df[column]df[boolean_mask]

有索引单行或单列的规则。根据它的完成方式,您将获得Series或DataFrame。因此,如果要将DataFrame df中的第100行索引为DataFrame切片,则需要执行以下操作:

df.iloc[[100], :]  # `:` selects every column

而不是

df.iloc[100, :]

类似于基于列的索引。

最后,如果要索引单个标量,请使用atiat

OTOH,根据您的要求,我建议第三种选择:

ts = df.loc[df.timestamp.between(5, 10), 'timestamp']

或者,如果你是整个事物的子集,

df = df[df.timestamp.between(5, 10)]