Разбить и изменить значения панд 'groupby' элементов в зависимости от длины групп - PullRequest
1 голос
/ 26 марта 2019

У меня есть объект DataFrame pandas со столбцом с именем 'order_id' . Строки с одинаковым идентификатором принадлежат одному и тому же порядку (размер может быть любым от 1 до 1000), например ::100100

sales_orders = {
    'order_id': [1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4],
    # multiple other fields 
}
df = pd.DataFrame(sales_orders)

Мне нужно разделить группы на более мелкие куски, основываясь на отсеченном значении, как, например, в 3. В идеале, ничто иное не изменится, кроме суффикса столбца, т.е.

'order_id': [1-0, 1-0, 1-0, 1-1, 1-1, 1-1, 1-2, 2, 2, 2, 3-0, 3-0, 3-0, 3-1, 3-1, 3-1, 3-2, 3-2, 3-2, 4]

Я предполагаю, что можно просто пройти по группам и прикоснуться к каждой группе индивидуально в цикле for следующим образом:

for order_id, group in df.groupby(by=['order_id']):
    if group.shape[0] > 2:
        # change column line by line

Но это выглядит невероятно непандарно и ужасно медленно. Таким образом, я был бы признателен за разумное, производительное и читаемое решение;) Заранее спасибо за помощь!

1 Ответ

1 голос
/ 26 марта 2019

Используйте groupby и cumcount для получения суффиксов, затем используйте np.where для их условной установки.

c = df.groupby('order_id').cumcount() // 3
m = (c == 0).groupby(df.order_id).transform('all')

df['order_id2'] = (
    np.where(m, df.order_id, df.order_id.astype(str) + '-' + c.astype(str))
      .astype(str))

df.head(10)

   order_id order_id2
0         1       1-0
1         1       1-0
2         1       1-0
3         1       1-1
4         1       1-1
5         1       1-1
6         1       1-2
7         2         2
8         2         2
9         2         2

Несколько более простое решение, если вы хорошо справляетесь с 2 и 4также имеет суффиксы;вы можете использовать groupby и cumcount для генерации суффиксов, а затем использовать str.cat для их присоединения.

c = (df.groupby('order_id').cumcount() // 3).astype(str)
df['order_id3'] = df['order_id'].astype(str).str.cat(c, sep='-')

df.head(10)

   order_id order_id2 order_id3
0         1       1-0       1-0
1         1       1-0       1-0
2         1       1-0       1-0
3         1       1-1       1-1
4         1       1-1       1-1
5         1       1-1       1-1
6         1       1-2       1-2
7         2         2       2-0
8         2         2       2-0
9         2         2       2-0
...