【问题标题】:Best practices for indexing with pandas使用 pandas 进行索引的最佳实践
【发布时间】:2018-11-12 16:51:45
【问题描述】:

我想根据掩码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]

【问题讨论】:

  • 您的问题归结为您使用df['col'].iloc[idx] 还是仅使用[idx],其中idxboolean(不是int)的向量。所以你只是在询问布尔掩码的情况。
  • 说到 Pandas 索引从哪里开始。也许文档是一个好的开始。永远不要像这样混合和链接索引操作。你将进入一个充满伤害的世界。
  • 我已将您的问题标题编辑成我相信很多人都会搜索的内容。让我们看看。
  • 顺便说一句,您介意将投票/接受您认为有帮助的答案养成习惯吗?它对社区有所帮助,我注意到您似乎并不经常这样做。

标签: python pandas dataframe indexing series


【解决方案1】:

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

关键点是:

  • pd.DataFrame.iloc 主要用于基于整数位置的索引。
  • pd.DataFrame.loc 最常与标签或布尔数组一起使用。
  • 链式索引,即通过df[x][y],是explicitly discouraged,而且从来没有必要。
  • idx.values 返回idx 系列的numpy 数组表示。这不能喂.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 更自然。

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

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

【讨论】:

  • 是否使用 mask = idx.values 而不是 mask = np.where(idx)[0] 也不起作用?
  • 不,它不会工作。因为idx.values 只会给出一个布尔数组,它不能提供.iloc
  • 根据pandas.pydata.org/pandas-docs/stable/indexing.html ".iloc 主要是基于整数位置的(从轴的 0 到长度为 1),但也可以与布尔数组一起使用"
  • iloc 只能采用 numpy 数组,但不能采用系列,否则会出错。所以 idx.values 似乎是必要的
  • @machinery,是的,虽然不打算在这里复制文档(那里有更多可用的文档)。但我又更新了:)。
【解决方案2】:

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

以下是一些通常不好的索引方法:

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

以上所有方法的正确方法是df.loc[idx, col]。如果idx 是整数标签,请使用df.loc[df.index[idx], col]

当您尝试分配这些解决方案时,这些解决方案中的大多数都会导致管道出现问题(主要以 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)]

【讨论】:

  • @BenMares 那里的措辞似乎很糟糕。我打算在错误方法旁边添加 cmets 中的更正,但后来意识到它们都是错误地编写相同表达式的不同方法。请在此处查看我的edit
猜你喜欢
  • 2023-04-08
  • 2022-01-22
  • 1970-01-01
  • 1970-01-01
  • 2016-07-10
  • 1970-01-01
  • 2010-09-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多