【问题标题】:Filter sub-dataframe in nested for-loop在嵌套的 for 循环中过滤子数据框
【发布时间】:2020-06-28 19:31:24
【问题描述】:

我想过滤数据框以在嵌套 for 循环中获取子数据集,然后将 some_function 应用于每个子数据集,根据名为 @987654323 的持续时间列从每个子数据集中选择一行@,然后将所有单独的行连接到一个数据帧中。

代码如下:

def tm(df):
    total_t = []
    df['YearMonth'] = df['Timestamp'].apply(lambda x: x.strftime('%Y-%m'))
    
    for yearmonth in df['YearMonth'].unique():
        for id in df['Id'].unique():

            sub_df = df[(df['YearMonth'] == yearmonth) &(df['Id'] == id)]
            res_df = some_function(sub_df)
            res_df['TimeDiff'] = res_df['EndTime'] - res_df['StartTime'] 
            res_df = res_df.loc[(res_df['TimeDiff']> datetime.timedelta(seconds=60)) & (res_df['TimeDiff']<datetime.timedelta(minutes=5))]
            long_event = res_df.loc[res_df['TimeDiff'] ==res_df['TimeDiff'].max()]
            
            total_t.append(pd.Series(long_event))
            # total_t.append(pd.Series(long_event))
            total_t = pd.concat([total_t])

    return total_t

tm(dfx)

res_df 是一个数据框,如下所示:

    Id  Date        StartTime               EndTime                 StartVal EndVal TimeDiff
0   89  2012-03-10  2012-03-10 00:00:08.483 2012-03-10 00:00:11.607 41.5     41.0   00:00:03.124000
1   181 2012-03-10  2012-03-10 00:02:49.687 2012-03-10 00:02:52.813 41.5     41.0   00:00:03.126000

我想在每个子数据集中选择TimeDiff 最长的行,以及60seconds5minutes 范围内的行,将它们组合成一个数据框。

但是它发现了错误:

TypeError: first argument must be an iterable of pandas objects, you passed an object of type "DataFrame"

我意识到这可能是因为作为参数传递的数据帧应该是基于this questionlist 形式。我试过了

total_t = pd.concat([total_t])
# Original code :total_t = pd.concat(total_t) 

返回:

TypeError: cannot concatenate object of type '<class 'list'>'; only Series and DataFrame objs are valid

预期输出,仍然是这种格式,但行数更多:

    Id  Date        StartTime               EndTime                 StartVal EndVal TimeDiff
0   89  2012-03-10  2012-03-10 00:00:08.483 2012-03-10 00:00:11.607 41.5     41.0   00:00:03.124000
1   181 2012-03-10  2012-03-10 00:02:49.687 2012-03-10 00:02:52.813 41.5     41.0   00:00:03.126000
                                            ...

更新:

试过了:

            total_t.append(long_event)
            total_t = pd.Series(total_t)
#             total_t = pd.DataFrame(pd.concat([total_t]))
            total_t = pd.concat([total_t])

只返回一行:

0     Id   Date       StartTime               EndTime                   StartVal 
EndVal TimeDiff
37    235  2012-03-10 2012-03-10 19:43:32.260 2012-03-10 19:48:06.270   42.0 
41.5   00:04:34.010000
dtype: object

【问题讨论】:

    标签: python pandas dataframe for-loop nested


    【解决方案1】:

    IIUC 您想返回一个pd.DataFrame,其中包含每个YearMonth 和每个Id 的最大TimeDiff 5 分钟以内。是这样吗?

    首先对您的代码进行一些评论:

    • total_t.append(pd.Series(long_event)) 的第一次迭代中,total_t 是一个列表,因此您可以像以前一样就地追加。
    • 下一行:total_t = pd.concat([total_t]) 会将您的列表转换为系列
    • 从第二次迭代开始,total_t.append(pd.Series(long_event)) 将被执行,但随着 total_t 变为 pd.Series,追加操作不再存在。

    我建议您进行以下调整:

    要获取最大TimeDiff对应的行,可以这样:

    long_event = res_df.loc[res_df['TimeDiff'].idxmax()]
    

    然后你可以像你已经做的那样附加它们(无需转换为pd.Series):

    total_t.append(long_event)
    

    最后,我会通过在返回之前添加来删除total_t = pd.concat([total_t])

    total_t = pd.DataFrame(total_t)
    

    最终代码如下所示:

                long_event = res_df.loc[res_df['TimeDiff'].idxmax()]
                total_t.append(long_event)
    
        total_t = pd.DataFrame(total_t)
        return total_t
    

    使用样本数据进行测试

    伪造数据的创建

    df = pd.DataFrame({'TimeDiff': ['00:01:13.124000', '00:00:03.124000', '00:12:03.126000', '00:04:54.124000'], 
                       'Other': [1, 2, 3, 4]})
    df['TimeDiff'] = pd.to_timedelta(df.TimeDiff)
    

    结果

    df = df.loc[(df['TimeDiff']> datetime.timedelta(seconds=60)) & (df['TimeDiff']<datetime.timedelta(minutes=5))]
    total_t = []
    long_event = df.loc[df['TimeDiff'].idxmax()]
    total_t.append(long_event)
    
    # after the for loops are completed in your case
    total_t = pd.DataFrame(total_t)
    total_t
        TimeDiff                    Other
    3   0 days 00:04:54.124000000   4
    
    

    Other 列在这里只是为了证明结果是 DataFrame,因此最终包含所有其他列。

    【讨论】:

    • 嗨 Hugolmn,感谢您分享您对这个问题的看法。问题的焦点在于,在应用相同的函数后,我无法为每个子数据集的输出生成结构化表。每个子数据集包含每个月的数据,每个唯一的 id。后来我意识到我可以应用相同的函数并按月份和 id 对整个数据集进行分组,这样更直接。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-20
    • 1970-01-01
    相关资源
    最近更新 更多