Панды Python: Удаленные строки На основе значения Повторения Из предыдущих строк

#python #pandas #dataframe

Вопрос:

Я тут совсем растерялся. Любая помощь была бы очень признательна!

Это мои текущие данные. Продукт изменился с A. 1 на A. 2. Я хочу, чтобы, когда A. 1 превратится в A. 2, я хочу, чтобы остальные мои данные начинали отсчет времени цикла только для A. 2. То же самое для B. 1 и B. 3.

Вот текущие данные.

  --------- ----------- -- 
| Product | CycleTime |  |
 --------- ----------- -- 
| A.1     | 10        |  |
 --------- ----------- -- 
| A.1     | 5         |  |
 --------- ----------- -- 
| A.1     | 1         |  |
 --------- ----------- -- 
| A.1     | 2         |  |
 --------- ----------- -- 
| A.1     | 1         |  |
 --------- ----------- -- 
| A.2     | 5         |  |
 --------- ----------- -- 
| A.2     | 1         |  |
 --------- ----------- -- 
| A.1     | 2         |  |
 --------- ----------- -- 
| A.1     | 10        |  |
 --------- ----------- -- 
| A.2     | 10        |  |
 --------- ----------- -- 
| B.1     | 1         |  |
 --------- ----------- -- 
| B.1     | 2         |  |
 --------- ----------- -- 
| B.1     | 1         |  |
 --------- ----------- -- 
| B.3     | 5         |  |
 --------- ----------- -- 
| B.1     | 1         |  |
 --------- ----------- -- 
| B.3     | 2         |  |
 --------- ----------- -- 
| B.1     | 10        |  |
 --------- ----------- -- 
 

Вот что я пытаюсь создать.

  --------- ----------- -- 
| Product | CycleTime |  |
 --------- ----------- -- 
| A.1     | 10        |  |
 --------- ----------- -- 
| A.1     | 5         |  |
 --------- ----------- -- 
| A.1     | 1         |  |
 --------- ----------- -- 
| A.1     | 2         |  |
 --------- ----------- -- 
| A.1     | 1         |  |
 --------- ----------- -- 
| A.2     | 5         |  |
 --------- ----------- -- 
| A.2     | 1         |  |
 --------- ----------- -- 
| A.2     | 10        |  |
 --------- ----------- -- 
| B.1     | 1         |  |
 --------- ----------- -- 
| B.1     | 2         |  |
 --------- ----------- -- 
| B.1     | 1         |  |
 --------- ----------- -- 
| B.3     | 5         |  |
 --------- ----------- -- 
| B.3     | 2         |  |
 --------- ----------- -- 
 

Ответ №1:

Если вы отбросите дубликаты и сохраните первые значения, индекс следующего продукта покажет, откуда больше невозможно найти текущий продукт:

 find_pos = lambda x: x.drop_duplicates('Product')['Product'].shift().dropna() 
          .rename_axis('not_valid_after').reset_index()

conds = df.groupby(df['Product'].str.split('.').str[0]) 
          .apply(find_pos).reset_index(drop=True)

print(conds)

# Output:
   not_valid_after Product
0                5     A.1  # 5 is the first index of A.2
1               13     B.1  # 13 is the first index of B.3
 

Теперь вы можете отфильтровать свой фрейм данных:

 out = df.drop(conds.apply(lambda x: df.loc[df['Product'] == x['Product']]
                                      .loc[x['not_valid_after']:].index.tolist(),
                           axis=1).explode().dropna().tolist())
 

Выход:

 >>> out
   Product  CycleTime
0      A.1         10
1      A.1          5
2      A.1          1
3      A.1          2
4      A.1          1
5      A.2          5
6      A.2          1
9      A.2         10
10     B.1          1
11     B.1          2
12     B.1          1
13     B.3          5
15     B.3          2
 

Комментарии:

1. Очень умно!!!!

Ответ №2:

установка:

 df = pd.DataFrame(
    {
        "ProductType":["A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "B", "B", "B", "A", "B", "B", "B"],
        "Product":["A.1", "A.1", "A.1", "A.1", "A.1", "A.2", "A.2", "A.1", "A.1", "A.2", "B.1", "B.1", "B.1", "B.3", "B.1", "B.3", "B.1"],
        "CycleTime":[10,5,1,2,1,5,1,2,10,10,1,2,1,5,1,2,10],
    }
)
 

Создайте заказ между продуктами. Порядок между различными типами продуктов не имеет значения, только внутри каждого типа продукта. Т. е. возьмите несколько частичных заказов и соедините их вместе, чтобы создать общий заказ. Возможно, вам придется сделать это вручную, возможно, вы сможете сделать это программно, это зависит от вашей проблемы.

 order = ["A.1", "A.2", "B.1", "B.2", "B.3"]
 

Создайте карту и ее инверсию, которые свяжут каждый продукт с его позицией в заказе.

 mapping = dict(enumerate(order))
inversemapping= {v:k for k,v in mapping.items()}
 

Идея состоит в том, чтобы для каждого типа продукта сопоставить продукт со значением его заказа и рассчитать совокупный максимум этих значений заказа, прежде чем сопоставлять их с продуктами.

 df.groupby("ProductType").apply(lambda d: d["Product"].map(inversemapping).cummax().map(mapping)).values
 

Вы получите следующий массив numpy:

  array(['A.1', 'A.1', 'A.1', 'A.1', 'A.1', 'A.2', 'A.2', 'A.2', 'A.2',
   'A.2', 'B.1', 'B.1', 'B.1', 'B.3', 'B.3', 'B.3', 'B.3'],
  dtype=object)