【问题标题】:Find identical groups in python data frames pandas在 python 数据帧 pandas 中查找相同的组
【发布时间】:2021-07-20 00:06:42
【问题描述】:

我正在尝试在我的数据框中找到相同的订单,看起来与此类似 -

Order_ID |SKU |Qty |

123 | A | 1 |

123 | B | 2 |

345 | A | 1 |

345 | B | 2 |

678 | A | 1 |

678 | C | 3 |

一个订单可以有多个 SKU,即 1 个订单可以有多行。 所以包含确切 SKU 和数量的 order_ID 是相同的。这里是 123 和 345。 我需要与 SKU 和数量相同的订单。

如何在 pandas 数据框中使用分组来实现这一点?

示例输出类似于 -

Order_ID     |   SKU    | Qty        |Unique_Orders
[123] , [345]| [A],[B]  | [1],[2]    |2
[678]        | [A],[C]  | [1],[3]    |1

感谢您的帮助。

【问题讨论】:

  • 有很多方法可以找到这样的组,但这取决于你想用它们做什么。任何想要的输出?例如,您可以对qty 求和、计算行数、计算不同的 sku 等。
  • 如果您只想要什么是唯一的 order_id,您可以使用 df['order_id'].unique() 列出它们,但同样取决于您列出 @PierreD 所说的那些唯一的 order_id 跨度>

标签: python pandas dataframe pandas-groupby


【解决方案1】:

更新

根据问题中的更新,这是一个更新的答案,没有任何 Python 级循环:

skuqty = df.groupby('Order_ID')[['SKU', 'Qty']].agg(tuple).reset_index()
skuqty.groupby(['SKU', 'Qty'])['Order_ID'].unique().reset_index()

这给出了:

      SKU     Qty    Order_ID
0  (A, B)  (1, 2)  [123, 345]
1  (A, C)  (1, 3)       [678]

或者,如果您想完全匹配您的规格,您可以进一步这样做:

z = skuqty.groupby(['SKU', 'Qty'])['Order_ID'].unique().reset_index()
z = z.assign(SKU=z['SKU'].apply(list)).assign(Qty=z['Qty'].apply(list)).assign(Unique_Orders=z['Order_ID'].apply(len))
z = z[['Order_ID', 'SKU', 'Qty', 'Unique_Orders']]

这给出了:

>>> z
     Order_Id     SKU     Qty  Unique_Orders
0  [123, 345]  [A, B]  [1, 2]              2
1       [678]  [A, C]  [1, 3]              1

速度

这个比较快:

n = 1_000_000
df = pd.DataFrame({
    'Order_ID': np.random.randint(0, 999, n),
    'SKU': np.random.choice(list('ABCDEFGHIJKLMNOPQRSTUVWXYZ'), n),
    'Qty': np.random.randint(1, 100, n),
})

%timeit proc(df)  # which is the (first) code above
# 405 ms ± 407 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)

原答案

这取决于您想对这些组做什么。这是一个总结Qty的例子:

df.groupby('Order_ID')['Qty'].sum()

给予:

Order_ID
123    3
345    3
678    4
Name: Qty, dtype: int64

或者,如果您想同时查看 Qty 总数和不同的 SKU

>>> df.groupby('Order_ID').agg({'Qty':sum, 'SKU':'unique'})
          Qty     SKU
Order_ID             
123         3  [A, B]
345         3  [A, B]
678         4  [A, C]

最后,有一个为每个Order_ID 提供dict{SKU: Qty}

>>> df.groupby('Order_ID').apply(lambda g: dict(g[['SKU', 'Qty']].values))
Order_ID
123    {'A': 1, 'B': 2}
345    {'A': 1, 'B': 2}
678    {'A': 1, 'C': 3}

【讨论】:

  • 谢谢你,皮埃尔!你非常乐于助人。
【解决方案2】:

另一个版本:

x = df.groupby("Order_ID")[["SKU", "Qty"]].apply(
    lambda x: frozenset(zip(x.SKU, x.Qty))
)

df_out = pd.DataFrame(
    [
        {
            "Order_ID": v.to_list(),
            "SKU": [sku for sku, _ in k],
            "Qty": [qty for _, qty in k],
            "Unique_Orders": len(v),
        }
        for k, v in x.index.groupby(x).items()
    ]
)
print(df_out)

打印:

     Order_ID     SKU     Qty  Unique_Orders
0  [123, 345]  [A, B]  [1, 2]              2
1       [678]  [C, A]  [3, 1]              1

【讨论】:

  • 仅供参考,使用显式 Python 循环会使大型 DataFrame 变慢。
【解决方案3】:

我们可以使用groupby + unique 来获取每个SKUQty 的唯一订单

df.groupby(['SKU', 'Qty'])['Order_ID'].unique()

如果你也想countunique的数量那么我们可以另外使用nunique

df.groupby(['SKU', 'Qty'])['Order_ID'].agg(['unique', 'nunique'])

                  unique  nunique
SKU Qty                          
A   1    [123, 345, 678]        3
B   2         [123, 345]        2
C   3              [678]        1

【讨论】:

    【解决方案4】:

    在这种情况下,您不需要使用组。只需使用 pandas 中的 duplicated() 函数即可。

    df.duplicated()
    

    这将返回一个布尔系列,其中第一个重复值显示为 True,其他类似的值在第一个重复值之后显示为 False。

    因此,如果您想检索重复的 ID,只需遵循正常的 pandas 条件即可。

    df['Order_ID'].loc[df.duplicated()].values.unique()
    

    假设 Order_ID 是 DataFrame 中的一个列,并且默认的 id 列仍然存在。

    【讨论】:

    • AttributeError: 'numpy.ndarray' 对象没有属性 'unique'
    • @KrishangiGoswami 我的错,只需删除 unique()。试试这个:df['Order_ID'].loc[df.duplicated()].values.tolist()
    【解决方案5】:
    df.groupby(['SKU', 'Qty'])['Order_ID'].apply(list)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-16
      • 2020-04-13
      • 2018-07-16
      • 2021-02-03
      • 2013-07-24
      • 2017-08-29
      • 2021-02-22
      • 1970-01-01
      相关资源
      最近更新 更多