使用另一个Series/DataFrame的值过滤DataFrame中每个X(曲线下面积)

3

我正在对DataFrame进行过滤,以获得曲线下的面积。我已经成功地得到了曲线的边界,因此我们只想要该曲线下的行。

我采用的方法是通过以下代码中的代码(1)获取 data_y_border(图中的红色曲线) (这个方法很有效)。这将包含另一列值>= 0.7的每个X的最顶部Y,以便我可以查询data_y_border[x_value]并获取相应的最顶部Y。

注意: data_y_border不是整个数据集中Y的最低值。 data(图中的蓝色矩形)是我们的数据集,而data_y_border是由Density列定义的红色区域的下边界,其中其值大于0.7:

    density_zone = data[
        (full_dataset["X" < x_right_boundary)
        & (full_dataset['Density'] >= 0.7)
        & (full_dataset['Y'] > y_lower_boundary)
    ]

data_y_border 是红色区域的底部。它下面的任何内容都没有密度大于0.7。

Area under a curve

我现在想使用每个 X 位置的 Y 值,保留所有行,其中该 X 值对应的 Y ≤ 最顶部 Y 的值(在 data_y_border 中)

我正在尝试使用 [2] 中的 loclambda 的组合来将行值与每行的最顶部 Y 进行比较,但我收到错误信息:

ValueError: Can only compare identically-labeled Series objects

代码:

[1] data_y_border = density_zone.groupby("X")["Y"].min() #returns Series

                          or

    data_y_border = density_zone.loc[density_zone.groupby("X")["Y"].idxmin() # returns DataFrame
    # as per @enke's suggestion

[2] data.loc[lambda row: row['Y'] <= data_y_border.get(row['X'])]

    # get the X value for `row`, 
    # use it as the index in `data_y_border` to get the corresponding Y // value, 
    # compare that row's Y value to see if it's less than or equal to the topmost Y. 
    # If it is, keep it

数据框中大约有23个列,但作为示例,给定以下数据数据框和data_y_border,我期望保留下面的预期输出:
data = 
X    Y        OtherDataIWantToKeep
2.0  307.0    ...
2.0  155.3    ...     
2.0  120.0    ...     
2.0  80.2     ...        
4.0  500.3    ...
4.0  270.8    ...
4.0  111.2    ...
4.0  78.23    ...
4.0  6.3      ...

data_y_border=
2.0, 155.3
4.0, 111.2

预期输出行数(包括其他列中的所有数据):

X    Y        OtherDataIWantToKeep
2.0  155.3    ...     
2.0  120.0    ...     
2.0  80.2     ...        
4.0  111.2    ...
4.0  78.23    ...
4.0  6.3      ...

我尝试了涉及.apply的组合,但是这种方法会导致键错误。我感觉问题出在上面代码中的data_y_border.get(row ['X'])部分,Pandas不喜欢在单独的筛选器上运行查询以使用该值来过滤当前数据帧。

使用loclambda过滤每个行的数据帧并将每行的值与另一个数据帧/系列中的映射值进行比较是否正确?

我考虑过iterrows(如果它们是Python / JS中的数组/列表,我会对它们进行映射),但这对于相当大的数据帧来说太昂贵了。


@enke 谢谢,我回复了你的答案。它给了我与上面的[1]相同的输出,这在我的代码中已经正常工作。是[2]让我有困难。 - GroomedGorilla
你那里的 data_y_border 不能是 data.groupby("X")["Y"].min() 的输出。例如,对于 2.0120.0<155.3。实际上,data_y_border 是如何推导出来的? - user7864386
2个回答

2

根据您的评论:

该曲线基于另一列的值。基本上是在另一列的值大于某个值时,找到每个X的最低Y。这就成为我们的曲线边界。使用该曲线,我们想找到曲线下方区域的行。

看起来data_y_border是独立于data计算的。因此,让我们将其视为给定(如问题中所给出的)。然后我们可以将其映射到data['X']并与data['Y']进行比较;然后进行过滤:

out = data[data['Y'] <= data['X'].map(data_y_border.set_index('X')['Y'])]

输出:

     X       Y OtherDataIWantToKeep
1  2.0  155.30                  ...
2  2.0  120.00                  ...
3  2.0   80.20                  ...
6  4.0  111.20                  ...
7  4.0   78.23                  ...
8  4.0    6.30                  ...

谢谢,但这两个提供的数据集与我们在上面[1]得到的数据集相同(即曲线下面的边界),已经可以正常工作。我已经更新了问题以便更清晰地表达。 - GroomedGorilla
@GroomedGorilla,我不明白你的意思。如果你有一个曲线的最小值,那么它下面就没有点了,对吧? - user7864386
该曲线基于另一列的值。基本上,它是在另一列的值大于某个特定值的行中,找到每个X的最低Y值。这就成为我们的曲线边界。使用该曲线,我们想要找到曲线下方区域的行。我会添加一个图表来解释。 - GroomedGorilla
@GroomedGorilla编辑了答案,请查看是否有效。 - user7864386
原来我们的数据有缺失,这就是为什么验证时间更长的原因。它现在可以工作了!我上面代码中的data_y_border返回一个Series,所以set_index无法使用,但我将其转换为DataFrame(然后稍后根据您之前的答案使用idxmin进行了更清晰的实现)。我还会尝试更新问题标题,使其更加清晰明了。谢谢! - GroomedGorilla

2

你不能从data_y_mins中创建一个包含data_y_mins_index和data_y_mins_values的数据框,同时还包括Y和X吗? 然后你就可以像这样进行筛选:

data[data['Y']<=data['y_min_value']]

那么您的意思是过滤掉我的问题中[1]中的y值,然后将它们作为列添加到“data”DataFrame中?问题在于如何基于每个X的最大允许Y填充这些列。遍历数据集中的行时,每个X都需要映射到该X坐标的data_y_borders值。 - GroomedGorilla
您可以通过将函数应用于每行以获得所需值来实现此操作。有关在数据框中使用apply / applymap的更多信息,请参见相关文档。 - GabrielBoehme

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接