【问题标题】:Removing rows from groups in a dataframe that have a minimum value in a certain column从数据框中的组中删除某一列中具有最小值的行
【发布时间】:2018-05-19 09:10:52
【问题描述】:

我在 csv 文件中有一个数据集。我已经使用 pandas 作为数据框导入了它。然后,我根据我命名为 Vf 的列从最小到最大对数据进行排序。

从这里我的代码试图做什么: 将已排序的数据帧 (DF) 分组为 11 个组。 计算每组中对应的最小值和最大值之间的差异。 遍历每个组并检查任何组的最小值和最大值之间的差异是否大于 0.2。 如果任何组都满足此条件,我希望代码从原始数据框中删除包含该组最小值的数据行。 然后再次对数据框进行排序和分组,减去该行。 再次遍历每个组,检查最小值和最大值之间的差异。 它应该继续这样做,直到它遍历每个组并发现它们的最小值和最大值之间的差异都不大于 0.2。

据我所知,现在我的代码可以做到这一点。但是当我想要它时它不会停止,即当所有组的最小值和最大值之间的差异小于 0.2 时,它不会停止。此外,此时它实际上似乎将行添加回原始数据帧。

这里是代码。请注意,我已将其设置为仅遍历数据中的前 2 组。另请注意,我的 for 循环中的行要求它打印语句和排序数据框的形状。这一切都是为了提供调试信息。

def celling():
import numpy as np
import pandas as pd
Data = input("Name of File: ")
DF = pd.read_csv("Y:\CHRIS\{}.csv".format(Data), skiprows = 20, names = ["Serial","Bin","Ir","Vf"])

def sort(Data):
    SortedDF = Data.sort_values(by='Vf')
    GroupedDF = SortedDF.groupby(np.arange(len(SortedDF))//11)
    GroupMax = GroupedDF["Vf"].max()
    GroupMin = GroupedDF["Vf"].min()
    GroupDiff = GroupMax - GroupMin
    GroupMinIndices = GroupedDF["Vf"].idxmin()
#sort(DF)
    for i in range(2):

        if GroupDiff[i] > 0.2:
            DF = Data[Data.index != GroupMinIndices[i]]
            print("Group {} was bad.".format(i))
            print(SortedDF.shape)
            sort(DF)
        else:
            print("Group {} is good.".format(i))
        print(SortedDF.shape)
sort(DF)

以下是原始数据框的示例:

        Serial  Bin       Ir     Vf
    0        1  1.0  0.00161  170.7
    1        2  1.0  0.00157  173.3
    2        3  1.0  0.00169  171.0
    3        4  1.0  0.00145  172.7
    4        5  1.0  0.00170  171.4
    5        6  1.0  0.00160  172.6
    6        7  1.0  0.00180  172.4
    7        8  1.0  0.00169  172.1
    8        9  1.0  0.00147  170.9
    9       10  1.0  0.00151  172.3
    10      11  1.0  0.00142  171.8
    11      12  1.0  0.00168  171.5

这是一个按 Vf 排序的数据帧示例:

    Serial  Bin       Ir     Vf
477    478  1.0  0.00180  170.0
359    360  1.0  0.00139  170.1
247    248  1.0  0.00197  170.1
575    576  1.0  0.00159  170.2
267    268  1.0  0.00178  170.2
178    179  1.0  0.00277  170.3
82      83  1.0  0.00145  170.3
574    575  1.0  0.00162  170.3
97      98  1.0  0.00190  170.3
399    400  1.0  0.00172  170.4
21      22  1.0  0.00166  170.4
67      68  1.0  0.00176  170.5
103    104  1.0  0.00154  170.5
553    554  1.0  0.00169  170.5
533    534  1.0  0.00167  170.5
177    178  1.0  0.00160  170.5
35      36  1.0  0.00150  170.5
186    187  1.0  0.00165  170.5
363    364  1.0  0.00172  170.6
487    488  1.0  0.00159  170.6

因此,理想情况下,代码在这里应该做的是检查此示例的前 11 行,注意这 11 中的最大值和最小值之间的差大于 0.2,并从第一行中删除具有最小值的行11,在这种情况下,这将是序列号的行。 478. 然后它应该重新组合数据,上面示例中的第 2-12 行现在将构成第一组 11。然后它应该注意到最小/最大差异仍然大于 0.2 并重新开始。下面应该是代码完成后上面示例中的第一组 11 个

178    179  1.0  0.00277  170.3
82      83  1.0  0.00145  170.3
574    575  1.0  0.00162  170.3
97      98  1.0  0.00190  170.3
399    400  1.0  0.00172  170.4
21      22  1.0  0.00166  170.4
67      68  1.0  0.00176  170.5
103    104  1.0  0.00154  170.5
553    554  1.0  0.00169  170.5
533    534  1.0  0.00167  170.5
177    178  1.0  0.00160  170.5

这是我目前的代码的结果:

Group 0 was bad.
(643, 4)
Group 0 was bad.
(642, 4)
Group 0 was bad.
(641, 4)
Group 0 was bad.
(640, 4)
Group 0 was bad.
(639, 4)
Group 0 is good.
(638, 4)
Group 1 was bad.
(638, 4)
Group 0 is good.
(637, 4)
Group 1 was bad.
(637, 4)
Group 0 is good.
(636, 4)
Group 1 was bad.
(636, 4)
Group 0 is good.
(635, 4)
Group 1 was bad.
(635, 4)
Group 0 is good.
(634, 4)
Group 1 was bad.
(634, 4)
Group 0 is good.
(633, 4)
Group 1 is good.
(633, 4)
(634, 4)
(635, 4)
(636, 4)
(637, 4)
(638, 4)
(639, 4)
Group 1 is good.
(639, 4)
(640, 4)
Group 1 is good.
(640, 4)
(641, 4)
Group 1 is good.
(641, 4)
(642, 4)
Group 1 is good.
(642, 4)
(643, 4)
Group 1 is good.
(643, 4)
(643, 4)

请注意,当它读取第 0 组的最大值和最小值之间的差异大于 0.2 时,它是如何不断删除行的。然后它移动到第 1 组。当它读取第 1 组中的最大/最小差异大于 0.2 时,它会删除该行并返回到 for 循环的开头(我知道这不是很有效) .但是,请注意,理论上它应该在读取后立即停止,而不是第 0 组是好的,然后第 1 组是好的,但它没有。请注意,在读取它们都很好之后,它似乎开始将行添加回数据框中。

如果有人能解释我的代码为什么这样做,或者解释我的代码在做什么,如果它没有这样做,将不胜感激。请注意,我是 python 新手,所以请善待! :)

【问题讨论】:

  • 您能否在给定示例数据的情况下添加预期的输出。
  • @Haleemur Ali 完成。如果还不清楚,请告诉我。

标签: python pandas dataframe


【解决方案1】:

这是一个棘手的问题,所以让我们从重述它开始。

  1. 使用列Vf 对数据进行排序
  2. group 连续 11 行并找到最小-最大分布超过 0.2 的第一组。
  3. 从该组开始拆分两部分数据,第一部分将是 good 部分,第二部分将是 bad 并要求要从其开头删除的行。
  4. 删除行从部分的开始,直到VfVf.shift(-10)之间的差不超过0.2
  5. 重复这些步骤 (group-split-remove),直到拆分有一个空的坏部分
  6. 加入所有好的部分以获得最终结果
  7. (可选)为最终结果分配组 ID

创建示例排序数据框:

df = pd.read_table(io.StringIO("""    Serial  Bin       Ir     Vf
477    478  1.0  0.00180  170.0
359    360  1.0  0.00139  170.1
247    248  1.0  0.00197  170.1
575    576  1.0  0.00159  170.2
267    268  1.0  0.00178  170.2
178    179  1.0  0.00277  170.3
82      83  1.0  0.00145  170.3
574    575  1.0  0.00162  170.3
97      98  1.0  0.00190  170.3
399    400  1.0  0.00172  170.4
21      22  1.0  0.00166  170.4
67      68  1.0  0.00176  170.5
103    104  1.0  0.00154  170.5
553    554  1.0  0.00169  170.5
533    534  1.0  0.00167  170.5
177    178  1.0  0.00160  170.5
35      36  1.0  0.00150  170.5
186    187  1.0  0.00165  170.5
363    364  1.0  0.00172  170.6
487    488  1.0  0.00159  170.6"""), sep='\s+')

这里是辅助函数:

def grouper(frame):
    return np.arange(len(frame)) // 11

def remove(frame): 
    return (
        (frame.Vf.shift(-10).fillna(frame.Vf.max()) - frame.Vf) < 0.2
    ).cumsum() > 0

def split_df(frame): 
    return frame.groupby(
        grouper(frame)
    ).Vf.transform(
        lambda x: (x.max() - x.min()) > 0.2
    ).cumsum() > 0

column.cumsum() &gt; 0 where column is 具有布尔类型,在遇到第一个真值后过滤所有行,包括为真的行。

下面的函数实现了上面的递归逻辑(借助上面定义的一些辅助函数)

def group_split_remove(frame):
    temp = frame[split_df(frame)]
    if len(temp) == 0:
        return frame
    return pd.concat([frame[~split_df(frame)], group_split_remove(temp[remove(temp)])])

现在,python 中的递归并不总是最好的策略,因此,如果上述方法不够快或达到最大递归深度,请将其重新表述为 while 循环。但是,我相信递归公式在这种情况下更具可读性

使用您的样本(排序)数据,group_split_remove(df) 返回以下数据框:

     Serial  Bin       Ir     Vf
178     179  1.0  0.00277  170.3
82       83  1.0  0.00145  170.3
574     575  1.0  0.00162  170.3
97       98  1.0  0.00190  170.3
399     400  1.0  0.00172  170.4
21       22  1.0  0.00166  170.4
67       68  1.0  0.00176  170.5
103     104  1.0  0.00154  170.5
553     554  1.0  0.00169  170.5
533     534  1.0  0.00167  170.5
177     178  1.0  0.00160  170.5
35       36  1.0  0.00150  170.5
186     187  1.0  0.00165  170.5
363     364  1.0  0.00172  170.6
487     488  1.0  0.00159  170.6

如您所见,前 11 行与您的预期输出完全匹配。

最后一个可选步骤是分配一个 group_id,可以按如下方式完成:

res['group_id'] = grouper(res)

【讨论】:

  • 我没有得到这个输出。您能否发布您为获得该输出而编写的完整代码。正如我所说,我是 Python 新手,所以我可能没有正确执行您的代码。也很抱歉回复延迟,非常感谢您的帮助。我只是没有太多时间看这个。
  • 您能否解释一下.cumsum() &gt; 0split_dfremove 中所做的事情
  • 最后,如果您能指出我的原始代码中的任何问题以供我自己学习使用,那将非常有帮助,谢谢。
  • 查看完整代码的更新答案。按照它们在答案中出现的顺序执行块以获得我得到的输出。您的代码没有实现从 bad 组中删除任何行的逻辑,也没有递归地将好的组与固定的坏组连接起来。
猜你喜欢
  • 2021-11-12
  • 2014-02-27
  • 1970-01-01
  • 2015-10-19
  • 2012-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多