【问题标题】:Extracting a portion of values from a Dataframe.从 Dataframe 中提取部分值。
【发布时间】:2017-09-07 01:03:20
【问题描述】:

我想编写一个函数来选择数据框的一部分,这样: 在输入中给出“first_non_zero_index”(在我们的例子中是行的索引)和值阈值(例如 4),返回索引,称为“last_non_zero_index”,这样 df.loc[first_non_zero_index:last_index] 将产生输出结果.此外,在两个非零值之间只允许最多 10 个连续的零。

非常感谢您的帮助。非常感激。 提前谢谢了。 卡罗

输入数据框:

id, ts,value,
id1,2017-04-27 01:35:30,0
id1,2017-04-27 01:36:30,0
id1,2017-04-27 01:37:00,0
id1,2017-04-27 01:38:00,0
id1,2017-04-27 01:39:00,0
id1,2017-04-27 01:40:00,0
id1,2017-04-27 01:41:00,0
id1,2017-04-27 01:42:00,0
id1,2017-04-27 01:43:00,0
id1,2017-04-27 01:44:00,0
id1,2017-04-27 01:45:30,4.0
id1,2017-04-27 01:46:00,99.0
id1,2017-04-27 01:47:30,100.0
id1,2017-04-27 01:48:30,100.0
id1,2017-04-27 01:49:30,100.0
id1,2017-04-27 01:50:30,100.0
id1,2017-04-27 01:51:30,100.0
id1,2017-04-27 01:52:00,100.0
id1,2017-04-27 01:53:00,0
id1,2017-04-27 01:54:00,0
id1,2017-04-27 02:55:30,5.0
id1,2017-04-27 02:56:00,6.0  
id1,2017-04-27 02:57:30,7.0 
id1,2017-04-27 02:58:00,8.0
id1,2017-04-27 02:59:30,4.0
id1,2017-04-27 02:00:30,0
id1,2017-04-27 02:01:30,0
id1,2017-04-27 02:02:00,0
id1,2017-04-27 02:03:00,0
id1,2017-04-27 02:04:00,0
id1,2017-04-27 02:05:00,0
id1,2017-04-27 02:06:00,0
id1,2017-04-27 02:07:00,0
id1,2017-04-27 02:08:00,0
id1,2017-04-27 02:09:00,0
id1,2017-04-27 02:10:00,0
id1,2017-04-27 02:11:00,0
id1,2017-04-27 02:12:30,4.0
id1,2017-04-27 02:13:00,99.0
id1,2017-04-27 02:14:30,1000.0
id1,2017-04-27 02:15:30,1000.0
id1,2017-04-27 02:16:30,1000.0
id1,2017-04-27 02:17:30,1000.0
id1,2017-04-27 02:18:30,1000.0
id1,2017-04-27 01:19:00,1000.0
id1,2017-04-27 02:20:00,0
id1,2017-04-27 02:20:00,0
id1,2017-04-27 02:21:00,0
id1,2017-04-27 02:22:30,5.0
id1,2017-04-27 02:23:00,6.0  
id1,2017-04-27 02:24:30,7.0 
id1,2017-04-27 02:25:00,8.0
id1,2017-04-27 02:26:30,4.0
id1,2017-04-27 02:27:30,0
id1,2017-04-27 02:28:00,0
id1,2017-04-27 02:29:00,0
id1,2017-04-27 02:30:00,0
id1,2017-04-27 02:31:00,0
id1,2017-04-27 02:32:00,0
id1,2017-04-27 02:33:00,0
id1,2017-04-27 02:34:00,0
id1,2017-04-27 02:35:00,0
id1,2017-04-27 02:36:00,0
id1,2017-04-27 02:37:00,0

输出数据框:

id, ts,value,
id1,2017-04-27 01:45:30,4.0
id1,2017-04-27 01:46:00,99.0
id1,2017-04-27 01:47:30,100.0
id1,2017-04-27 01:48:30,100.0
id1,2017-04-27 01:49:30,100.0
id1,2017-04-27 01:50:30,100.0
id1,2017-04-27 01:51:30,100.0
id1,2017-04-27 01:52:00,100.0
id1,2017-04-27 01:53:00,0
id1,2017-04-27 01:54:00,0
id1,2017-04-27 02:55:30,5.0
id1,2017-04-27 02:56:00,6.0  
id1,2017-04-27 02:57:30,7.0 
id1,2017-04-27 02:58:00,8.0
id1,2017-04-27 02:59:30,4.0

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    这应该让你走上正轨。它将接受输入数据帧并返回一个输出数据帧,该数据帧从通过“阈值”的第一个元素到通过它的最后一个元素。

    import pandas as pd
    df = pd.read_csv('data.csv')
    
    def extractPartialDataframe(df, threshold):
        indicesList = df[df.value >= threshold].index.tolist()
        new_df = df.iloc[min(indicesList): max(indicesList) + 1]
        new_df.reset_index(inplace=True)
        return new_df
    
    trimmedDF = extractPartialDataframe(df, 4)
    maxConsecutiveZeros = 10
    consecutives = trimmedDF["value"].groupby((trimmedDF["value"]!=trimmedDF["value"].shift(1)).cumsum()).transform('count')
    
    tooManyConsecutiveZeros = trimmedDF[(trimmedDF["value"] == 0)&( consecutives > maxConsecutiveZeros)].index.tolist()
    final_df = trimmedDF.iloc[:tooManyConsecutiveZeros[0]]
    print (final_df)
    

    OUTPUT
    
    10  id1  2017-04-27 01:45:30    4.0
    11  id1  2017-04-27 01:46:00   99.0
    12  id1  2017-04-27 01:47:30  100.0
    13  id1  2017-04-27 01:48:30  100.0
    14  id1  2017-04-27 01:49:30  100.0
    15  id1  2017-04-27 01:50:30  100.0
    16  id1  2017-04-27 01:51:30  100.0
    17  id1  2017-04-27 01:52:00  100.0
    18  id1  2017-04-27 01:53:00    0.0
    19  id1  2017-04-27 01:54:00    0.0
    20  id1  2017-04-27 02:55:30    5.0
    21  id1  2017-04-27 02:56:00    6.0
    22  id1  2017-04-27 02:57:30    7.0
    23  id1  2017-04-27 02:58:00    8.0
    24  id1  2017-04-27 02:59:30    4.0
    

    【讨论】:

    • 非常感谢 AustinOB。我不清楚的是如何在(例如第 18 行和第 19 行)两个非零值之间选择零值?
    • 我不确定你在问什么。输出中包含零值,因为 indicesList 包含所有值 [10, 11, ..., 23, 24]。它不包括 18 和 19,但原始 DataFrame 的切片是从索引 10-24 返回的。如果您询问如何访问这些行,您可以获取返回的数据帧,并执行类似返回DF[returnedDF.value == 0] 的操作
    • 好的。但是,这意味着 indicesList 还将包括许多其他行的索引,例如。正确的?如果是,这不是我要找的,因为它将包括包含任意数量的连续零的值序列。我只想要那些不超过 10 个的。
    • 您提供的解决方案与我实施的解决方案非常接近。我遇到的困难是只选择满足我上面表达的属性的正确的。
    • 我确实运行了您的解决方案,它按照我说的做。这是不正确的。
    【解决方案2】:

    我猜你的阈值是指一个分隔符(阈值可能建议使用>=<= 操作,而我认为你想要== 所需的输出,因为在你的示例)。

    找到第一个非零值:

    start = (df['value'] != 0).tolist().index(True)
    

    找到分隔符(在您的示例中为 4.0):

    fours = (df['value'] == 4).tolist()
    

    按第一个非零分割到第一个非零之后的第一个分隔符:

    df.iloc[start:fours.index(True, start+1)+1]
    

    输出应该像你的例子:

             id                   ts  value
        10  id1  2017-04-27 01:45:30    4.0
        11  id1  2017-04-27 01:46:00   99.0
        12  id1  2017-04-27 01:47:30  100.0
        13  id1  2017-04-27 01:48:30  100.0
        14  id1  2017-04-27 01:49:30  100.0
        15  id1  2017-04-27 01:50:30  100.0
        16  id1  2017-04-27 01:51:30  100.0
        17  id1  2017-04-27 01:52:00  100.0
        18  id1  2017-04-27 01:53:00    0.0
        19  id1  2017-04-27 01:54:00    0.0
        20  id1  2017-04-27 02:55:30    5.0
        21  id1  2017-04-27 02:56:00    6.0
        22  id1  2017-04-27 02:57:30    7.0
        23  id1  2017-04-27 02:58:00    8.0
        24  id1  2017-04-27 02:59:30    4.0
    

    [更新]

    我不知道这个列表理解是否有熊猫等价物,但也许它可以启发你:

    valid = [df['value'][i:i+10].sum() >= 4 for i in range(len(df))]
    
    df.iloc[start:valid.index(True, start+1)]
    

    上面不是你问的,它会在前 10 个小于 4 的连续值处停止。严格来说你问的更像是这样的:

    valid = [bool(df['value'][i:i+10].sum()) or value >= 4 
             for i, value in enumerate(df['value'])]
    

    如果性能不差的话,使用它可能比不断敲打你的头以找到“纯熊猫”方法要好。

    【讨论】:

    • 首先,非常感谢您的回答。好吧,我所说的阈值是一个值,它标识了我需要的值序列。在设置阈值 = 4 的特定情况下,意味着:我想要以值>=阈值“开始”并且以值
    • 我发现难以实现的是如何判断序列不应停在第一个或第二个、第三个、...十个零处,如果在那之后值 >= 4。跨度>
    • 我认为除了遍历所有行之外没有优雅的方法可以做到这一点 - 但比我更聪明的人可能会想出一个解决方案。
    • 保罗再次感谢。我正在非常努力地得到它。我相信我们能做到。您的解决方案正在帮助我从另一个角度看待整个问题。谢谢。
    • 感谢 AustinOB。不幸的是,您的解决方案并没有完全解决问题。您的所有代码都可以用很少的几行代码重写,例如:threshold = 4consecutives = df["value"].groupby((df["value"]!=df["value"].shift(1)).cumsum()).transform('count') series = df[(df["value"]!=0)|(consecutives<threshold)] print(series)。我需要的是只取我在开头指定的第一段。
    猜你喜欢
    • 2019-12-27
    • 2021-06-03
    • 1970-01-01
    • 2015-11-04
    • 1970-01-01
    • 2018-01-22
    • 1970-01-01
    • 2023-01-28
    • 2021-06-18
    相关资源
    最近更新 更多