【问题标题】:How to Loop Through Grouped Dataframe如何循环分组数据框
【发布时间】:2020-02-25 00:00:40
【问题描述】:

我是 python 的超级新手,但我直接尝试使用 pandas 等分析工具找出现实世界的问题。

我已经从 csv 导入了数据,但这里是数据的一个小副本:

df2 = pd.DataFrame({'SKU': [22335, 22335, 22335, 22335, 33442, 33442, 33442, 33442],
                'Date': ['2019-12-31', '2020-01-07', '2020-01-14', '2020-01-21', '2019-12-31', '2020-01-07', '2020-01-14', '2020-01-21'],
                'Urgent': [10,8,4,20,50,45,65,32],
                'Delivered': [4,7,12,10, 35,75,23,42]})

有两个项目 SKU 编号,22335 和 33442,每周开始日期,每周紧急设备请求和每周设备交付数量。至此,我已经弄清楚如何在整个数据集上计算一个 for 循环,该循环对于每一行都引用前一行的计算值:

# Create new numeric column 'Result'
df['Result'] = np.nan

# Assign initial value for the first row of 'Result' (Should be first row in each SKU group)
df.loc[0, 'Result'] = df.loc[0, 'Delivered'] + df.loc[1, 'Delivered'] - df.loc[0, 'Urgent']

# Loop through each row except for last row to calculate
for i in range(1, len(df)-1):
    df.loc[i,'Result'] = max(df.loc[i-1, 'Result'], 0) + df.loc[i+1, 'Delivered'] - df.loc[i, 'Urgent']

print(df)

但是,对我来说,下一步是仅对每个单独的 SKU(22335 和 33442 分别)执行上述操作。我尝试使用 groupby 按日期按 SKU 对每一行进行排名,但我不知道如何在我的循环中引用它:

# Convert Date datatype
df['Date'] = pd.to_datetime(df['Date'])

# Use groupby to create ranking by SKU and Date
df['SKURank'] = df.groupby('SKU')['Date'].rank(ascending = True).astype('int64')

我尝试定义一个函数,该函数可以在每次迭代时引用它自己的输出,然后使用 .apply 样式循环调用它,但老实说我完全迷失了这一点,但没有成功。

我也曾尝试遵守拆分、应用、组合原则,按 SKU 对数据进行分组,应用循环,然后将所有行重新组合在一起,但我真的不知道从哪里开始。

这是我的主要问题:

对于每个单独的 SKU 组,我应该使用哪种循环来执行与上述代码相同的任务(返回组中第一行的初始值,然后循环遍历每个后续行)?强>

如果推荐的循环形式(不管性能如何,我还没有那么高速度)要求我事先定义一个函数,我将如何创建一个函数来引用它自己的输出为后续的每一行到每个 SKU 的第一行?

更新:

天啊。亲爱的上帝,我创造了什么......它......它令人作呕......

是的,我用嵌套的 if 语句创建了一个巨大的 for 循环。是的,这太可怕了。不,它并没有做我需要的所有事情,比如在数据帧的最后一行执行循环。如果以下任何部分有意义,并且您可以指出如何使其真正发挥作用的方向,我将不胜感激。

import pandas as pd
import numpy as np

# Create dataframe for two SKUs, a weekly process date, urgent requested quantity, and delivered quantity
df = pd.DataFrame({'SKU': [22335, 22335, 22335, 22335, 33442, 33442, 33442, 33442],
                    'Date': ['2019-12-31', '2020-01-07', '2020-01-14', '2020-01-21', '2019-12-31', '2020-01-07', '2020-01-14', '2020-01-21'],
                    'Urgent': [10,8,4,20,50,45,65,32],
                    'Delivered': [4,7,12,10, 35,75,23,42]})

# Create new numeric column 'Result'
df['Result'] = np.nan

# Convert Date datatype and create 3 necessary columns
df['Date'] = pd.to_datetime(df['Date'])
df['Result'] = np.nan
df['WeeklyMiss'] = np.nan
df['Logic'] = ''

# Create list of unique SKUs in dataframe
skulst = df.SKU.unique()

print(skulst)


# Set initial indeces value 
skunum = 0
i = 0

# While loop with nested for loop to iterate over the dataframe
while skunum <= len(skulst):
    for i in range(0, len(df)-1):
        # Calculate first SKU row
        if i == 0 and df.loc[i, 'SKU'] == skulst[skunum]: 
            df.loc[i, 'Result'] = max(df.loc[i, 'Delivered'] + df.loc[i+1, 'Delivered'] - df.loc[i, 'Urgent'], 0)
            df.loc[i, 'WeeklyMiss'] = min(df.loc[i, 'Delivered'] + df.loc[i+1, 'Delivered'] - df.loc[i, 'Urgent'], 0)
            df.loc[i, 'Logic'] = 'First Row'
        # Calculate next SKU rows
        elif i > 0 and df.loc[i, 'SKU'] == skulst[skunum] and df.loc[i+1,'SKU'] == skulst[skunum]:
            df.loc[i, 'Result'] = max(df.loc[i+1, 'Delivered'] + min(df.loc[i-1, 'Result'], df.loc[i, 'Delivered']) - df.loc[i, 'Urgent'], 0)
            df.loc[i, 'WeeklyMiss'] = min(df.loc[i-1, 'Result'] + df.loc[i+1, 'Delivered'] - df.loc[i, 'Urgent'], 0)
            df.loc[i, 'Logic'] = 'Next SKU Row'
        # Calculate last SKU row
        elif i > 0 and df.loc[i, 'SKU'] == skulst[skunum] and (df.loc[i+1,'SKU'] != skulst[skunum] or i == len(df)):
            df.loc[i, 'Result'] = max(df.loc[i-1, 'Result'] - df.loc[i, 'Urgent'], 0)
            df.loc[i, 'WeeklyMiss'] = min(df.loc[i-1, 'Result'] - df.loc[i, 'Urgent'], 0)
            df.loc[i, 'Logic'] = 'Last SKU Row'
        
            
        # Calculate first SKU row and switch to next SKU 
        elif i > 0 and i < len(df) and df.loc[i, 'SKU'] != skulst[skunum] and df.loc[i-1,'SKU'] == skulst[skunum] :
            df.loc[i, 'Result'] = max(df.loc[i, 'Delivered'] + df.loc[i+1, 'Delivered'] - df.loc[i, 'Urgent'], 0)
            df.loc[i, 'WeeklyMiss'] = min(df.loc[i, 'Delivered'] + df.loc[i+1, 'Delivered'] - df.loc[i, 'Urgent'], 0)
            df.loc[i, 'Logic'] = 'First SKU Row'
            if skunum + 1 <= len(skulst):
                skunum += 1
            else:
                df.loc[i, 'Result'] = max(df.loc[i-1, 'Result'] - df.loc[i, 'Urgent'], 0)
                df.loc[i, 'WeeklyMiss'] = min(df.loc[i-1, 'Result'] - df.loc[i, 'Urgent'], 0)
                df.loc[i, 'Logic'] = 'Last SKU Row'
                continue
    else:
        print(df)
        break

【问题讨论】:

    标签: python pandas dataframe for-loop


    【解决方案1】:

    请参阅 pandas 文档中的 Group By: split-apply-combine 指南,了解如何迭代组。

    【讨论】:

    • 谢谢思南。我事先知道该资源,但我一直在尝试尽可能多地从中收集信息。不幸的是,它只是没有点击。我觉得在我可以将循环重新创建为预定义函数之前,我不会理解更高级的分组循环或迭代的基础知识。
    猜你喜欢
    • 2015-02-08
    • 2018-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-29
    • 2012-12-02
    • 2021-10-13
    相关资源
    最近更新 更多