【问题标题】:Iterating over Dataframes to generate new Dataframes in Python with Power BI使用 Power BI 在 Python 中迭代数据框以生成新的数据框
【发布时间】:2019-12-07 05:56:36
【问题描述】:

在 Power BI 中使用 python 在报表中输入视觉对象之前处理数据。

我在做什么的例子:

采购订单数据库来自oracle。 供应数据库来自多个 loc (SQL/csv)。

采购订单 X 需要 20 个单位的 a / 30 个单位的 b(例如)

我已经让它与下面的代码一起工作——但我还没有在一个完整的数据集上运行它——我访问过的所有线程基本上都说我这样做的方式并不理想——我很好奇是否有一种更简单、内存效率更高的方法来完成此操作。

I/o 源是 PBI 中的 pandas 数据帧 - 据我所知,它还支持 numpy 和其他几个。

下面的代码显示了我目前的工作方式 - 它在 500 行左右的样本大小上运行非常迅速 - 希望确保我可以扩大规模。

以下示例使用 2 个数据框:(df1 是需求表,df2 是供应表)将供应材料分配给订单)df3 是用于存储计算的临时数组。

进一步澄清 - 主要关注的是 iterrows() 并且该关注纯粹基于我所阅读的内容(主要是在这个网站上)

编辑:非常感谢您花时间阅读并帮助我! https://stackoverflow.com/users/10239974/eva-vw

不确定如何添加输出,但这是数据的样子(在图片中)df1

df2

我不认为我可以合并它们,因为 df1 中的合金标签是一个需求值,而 df2 中的合金标签是一个库存值 - 如果可以的话,那就太棒了 - 我会试试你的代码并让你懂的!再次感谢。

哦,最后一个细节 - 我制作的“计数器”列只是为了将索引保持在要求的位置 - 当我在没有它的情况下执行相同的代码时,我最终结合起来制作最终 df4 的 df3 只是一样多行与我分配的订单一样长 - 我希望它与 df1 保持对齐,以便我可以在最后将它们放在一起 - 当我为每次迭代添加一个值时,它保持正确的位置。 Df3 以 Counter:, Allocated 的形式结束,然后将其添加到 DF1,以便 Lbs(Required) 和 Allocated 与订单一起。

编辑:切换到 df1 合并后的最终输出:df1 with merge https://stackoverflow.com/users/10239974/eva-vw

编辑:使用原始代码 iterrows() 的最终输出:df4:df4 https://stackoverflow.com/users/10239974/eva-vw

编辑:调整功能的最终输出: https://stackoverflow.com/users/10239974/eva-vw

为了解释更多 - 库存中有 53000 磅这个组件 - 所以一旦它用 iterrows 耗尽库存就会停止分配 - 但我想我现在可以弄清楚这部分,因为我理解了你的逻辑。

顺便说一句 - 您的代码会立即执行 - 当 iterrows 加载大约一秒钟时 - 所以从缩放的角度来看,我对此感到非常兴奋!

import pandas as pd
df1 = pd.DataFrame.from_dict({'Name': ['a','b','c'], 'Alloy': ['R80','R80','R80'], 'Lbs': [6400,6400,6400]})
df2 = pd.DataFrame.from_dict({'ITEM': ['R80'], 'Inv': [50000]})
df3 = pd.DataFrame()
df3["Allocated"] = ""
df3["Counter"] = ""
for i, row in df2.iterrows():
    x = df2.at[i, 'ITEM']
    y = df2.at[i, 'Inv']
    g = 0
    for j, row in df1.iterrows():
        g+=1
        df3.at[j, 'Counter'] = g
        if df1.at[j, 'Alloy'] == x:
            z = df1.at[j, 'Lbs']
            if y >= z:
                df3.at[j, 'Allocated'] = z
                y = y - z
            else:
                break

df4 = pd.concat([df1,df3],axis=1)

【问题讨论】:

  • 如果您提供输入数据、预期输出和逻辑解释会很有帮助。
  • 输入数据示例:df1:项目:A,数量(磅):5,000 - 项目列表和现有库存。 df2: PO #:, A required:, B required:, C required: 预期的输出是用完订单上每个项目的所有库存,直到它消失 - 所以在订单之间分配库存 - 然后将添加到主订单数组(df1)

标签: python pandas dataframe iteration


【解决方案1】:

如果能获得输入数据的样本(只需 df.head() 即可)并使用列名对计算进行更详细的解释,那就太好了。

这是否复制了您的逻辑?这会切断您的一个循环。如果您确认这是您想要做的,我们可以更多地考虑如何加快速度。

# merge ITEM and Inv info from df2 into df1 based on overlap between Alloy and ITEM
df1 = df1.merge(df2[['ITEM', 'Inv']], how='left', left_on=['Alloy'], right_on=['ITEM'])
# set base allocation to Inv
df1['Allocated'] = df1['Inv']

def subtract_lbs(row):
    item = row['ITEM']
    allocated = row['Allocated']
    lbs = row['Lbs']
    if allocated >= lbs:
        remaining = allocated-lbs
        df1.loc[df1['ITEM'] == item, 'Allocated'] = remaining
        return remaining
    else:
        return allocated

# iteratively subtract lbs from allocated
df1['Allocated'] = df1.apply(subtract_lbs, axis=1)

编辑:上述方法确实更新了 df1['Allocated'] ,因为 df1.loc 在 df1.apply 执行时不会产生预期的行为。使用临时 df。

# merge ITEM and Inv info from df2 into df1 based on overlap between Alloy and ITEM
df1 = df1.merge(df2[['ITEM', 'Inv']], how='left', left_on=['Alloy'], right_on=['ITEM'])
# create temporary dataframe for the calculation
temp_df = df1.copy()
# set base allocation to Inv
temp_df['Allocated'] = temp_df['Inv']

def subtract_lbs(row):
    item = row['ITEM']
    lbs = row['Lbs']
    allocated = temp_df.loc[temp_df['ITEM'] == item, 'Allocated'].values[0]
    if allocated >= lbs:
        remaining = allocated-lbs
        temp_df.loc[df1['ITEM'] == item, 'Allocated'] = remaining
        return remaining
    else:
        return allocated

# iteratively subtract lbs from allocated
df1['Allocated'] = df1.apply(subtract_lbs, axis=1)

【讨论】:

  • 您好!我在 OP 中添加了一个编辑,其中包含 df1 / df2 前 5 行的图片。 Df3 只是一个空的 df,用于存储我为每个需求分配的值。我正在做的是从我的第一个项目(在这种情况下是合金)开始,然后遍历需求并分配它 - 如果我有更多或 = 需求 - 我添加它 - 直到我没有然后我打破下一个合金。 Alloy 和 ITEM 确实重叠 - 所以我认为这应该可行!我将尝试一下并回帖 - 再次感谢您抽出宝贵时间。
  • 嘿,这里有一个更新——请原谅我对合并不太熟悉,但我遇到了一个语法错误:我将它作为链接添加到 OP 中——它指向 how = 'left ' 在 df1 之后,
  • 是的,是一个错字。 merge(df1) 应该是 merge(df2[['ITEM', 'Inv']]。做了一个编辑。
  • 如果您可以在问题中添加一些代码来创建示例输入数据,那就太好了。你可以做类似 df1 = pd.DataFrame.from_dict({'col1': [0,1,2], 'col2': [3,4,5]})
  • 更新了!希望有帮助 - 保持名称相同,这样会更容易 - 另外 - 使用您提供的更新代码重新运行 - 合并有效 - inv 列保持不变,分配的列减少 lbs 数量!所以最后 Inv 列会希望减少每个订单的磅数,而分配的列会希望匹配每个订单的磅数 - 我想我可以完成这两件事!这太棒了,帮助我学到了很多东西!我将详细了解合并的工作原理。再次感谢您。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多