Python Pandas – 计算索引器并查找最近的索引值(如果没有精确匹配)
概述
在 Pandas 中,我们可以使用 Index.get_loc 方法获取给定值在索引器中的位置。如果我们查找的值恰好存在于索引器中,那么方法会返回一个整数索引,否则将抛出一个 KeyError。但有时候,在我们试图找到离目标值最近的索引项时,我们可能需要一些不同的行为。为了实现这个目标,我们可以使用 Pandas 提供的 Index.get_indexer 方法。
Index.get_indexer 的使用方法
Pandas 的 Index.get_indexer 能够返回一个给定数组元素在索引器中的位置。如果数组中的元素不在索引器中,方法将返回 -1。下面是一个简单的示例,展示了如何使用该方法查找给定 array 的索引位置。
import pandas as pd
animals = pd.Index(['cat', 'dog', 'monkey', 'elephant', 'lion', 'tiger'])
# 定义一个要查询的数组
queries = ['fish', 'cat', 'rabbit', 'dog', 'horse', 'monkey']
# 找到所有查询项在索引器的索引,-1 表示没有找到
print(animals.get_indexer(queries))
输出结果如下:
[-1 0 -1 1 -1 2]
找到最近匹配的索引项
接下来的问题是,当要查询的元素不在索引器中时,如何查找最近匹配的索引项。例如,如果要查询的元素为 2.1,在索引器中并没有 2.1 的值,但是有 2.2 和 2.0 的值。那么,我们希望获取距离查询值最近的值,即 2.2。
为了解决这个问题,我们可以使用 NumPy 的 argmin 函数。该函数返回一个数组元素所在位置的索引。我们可以通过计算查询元素与每个索引元素之差 diff 并使用 \operatorname{argmin}(|diff|) 找到最接近的匹配值的索引位置。下面是一个示例:
import pandas as pd
import numpy as np
numbers = pd.Index([1.9, 2.0, 2.1, 2.2, 2.3])
# 定义要查询的元素
query = 2.1
# 找到最近的匹配索引项
diff = np.abs(numbers - query)
closest_index = diff.argmin()
# 获得最近的匹配值
closest_value = numbers[closest_index]
print(closest_value)
输出结果为:
2.1
接下来,我们可以将上述代码片段封装成一个通用函数,以便在模型中多次调用。下面的函数会接受索引器和要查找的元素作为输入,并返回索引器中与检索元素最接近的值。
def get_closest_index_value(index, query):
diff = np.abs(index - query)
closest_index = diff.argmin()
return index[closest_index]
示例
在实际应用场景中,Pandas 的索引器是一个非常有用的工具。下面是一些示例,展示了如何使用 Index.get_indexer 方法和我们编写的 get_closest_index_value 函数来解决常见问题。
常见问题 1
给定一个时间序列和时间标签列表,找到最近的时间标签。
import pandas as pd
import numpy as np
ts = pd.Series(np.random.randn(100))
labels = pd.to_datetime(['2019-01-01', '2019-01-05', '2019-01-10'])
# 找到每个标签的索引位置
loc = ts.index.get_indexer(labels)
# 获得时间序列中与每个标签最接近的值
closest_values = [get_closest_index_value(ts.index, label) for label in labels]
print(closest_values)
常见问题 2
假设我们有一个 DataFrame,它包含物理量的时间序列数据,并且每个物理量都有一个关联的元数据值。我们希望查找与给定标量元数据值最接近的数据行。
import pandas as pd
import numpy as np
data = {'x': np.random.randn(100),
'y': np.random.randn(100),
'metadata': np.random.randint(0, 10, 100)}
df = pd.DataFrame(data)
# 定义要查询的元数据值
query_metadata = 7
# 过滤 DataFrame,只包含目标元数据值的数据行
sub_df = df[df['metadata'] == query_metadata]
# 找到元数据值最接近的数据行
closest_row = sub_df.iloc[(sub_df['x'] - query_x).abs().argsort()[0]]
print(closest_row)
结论
在本文中,我们讨论了如何在 Pandas 中查找与给定元素最接近的索引项。我们首先使用 Index.get_indexer 方法找到数组元素在索引器中的位置,然后使用 NumPy 的 argmin 函数找到最接近的匹配项。最后,我们展示了两个示例,展示了如何在实际应用中使用这种技术。
极客笔记