Как я могу отфильтровать каждое подмножество фрейма данных по 2 условиям?

#python #pandas #date

#python #панды #Дата

Вопрос:

Мне нужно проверить 2 условия для данных о продажах:

  1. был продан в определенные годы
  2. было продано за определенное количество дней с количеством> 0

Dataframe df:

 date       | id  | qual | amount
2020-09-01 | 123 | A    | 100
2020-09-02 | 123 | A    | 0
2020-09-03 | 123 | A    | 90
2020-09-04 | 123 | A    | 80
2020-09-01 | 123 | B    | 8
2020-09-02 | 123 | B    | 6
2020-09-03 | 123 | B    | 4
2020-09-04 | 123 | B    | 2
2021-02-01 | 123 | B    | 18
2020-02-01 | 456 | A    | 96
2021-02-02 | 456 | A    | 90
2021-01-01 | 789 | A    | 30
2021-01-02 | 789 | A    | 31
2021-01-03 | 789 | A    | 32
2021-01-04 | 789 | A    | 29
 

Фрейм данных имеет 10_000 идентификаторов с ~ 1000 датами для каждого идентификатора и 1 или 2 уровня качества (qual) на идентификатор.

Проверка должна выполняться для каждой комбинации ID уровень качества.

После проверки каждого ID Qual я хочу отфильтровать свой фрейм данных так, чтобы он содержал только комбинации IDs Qual, которые прошли эту проверку.

ИДЕНТИФИКАТОР: 123 с качеством: A

  • в продаже есть 2020 и 2021 год ❌
  • имеет не менее 4 строк с количеством> 0 ❌
  • -> не проходит

ИДЕНТИФИКАТОР: 123 с качеством: B

  • в продаже есть 2020 и 2021 год ✅
  • имеет не менее 4 строк с количеством> 0 ✅
  • -> проходит

ИДЕНТИФИКАТОР: 456 с качеством: A

  • в продаже есть 2020 и 2021 год ✅
  • имеет не менее 4 строк с количеством> 0 ❌
  • -> не проходит

ИДЕНТИФИКАТОР: 789 с качеством: A

  • в продаже есть 2020 и 2021 год ❌
  • имеет не менее 4 строк с количеством> 0 ✅
  • -> не проходит

Результат должен выглядеть следующим образом:

 date       | id  | qual | amount
2020-09-01 | 123 | B    | 8
2020-09-02 | 123 | B    | 6
2020-09-03 | 123 | B    | 4
2020-09-04 | 123 | B    | 2
2021-02-01 | 123 | B    | 18
 

Мой код до сих пор:

 required_sales_years= [2020, 2021]
required_sales_days = 4

has_required_sales = []
for id in df["id"].unique().tolist():
    for qual in df["qual"].unique().tolist():
        temp = df.query(
            "id== @id and qual == @qual and amount > 0"
        )
        sales_years = temp["date"].dt.year.unique().tolist()
        check_sales_year = all(item in sales_years for item in required_sales_years)
        check_sales_days = len(temp.index) >= required_sales_days
        if check_sales_year and check_sales_days:
            has_required_sales.append((id, qual))
 

Как я могу это сделать?

Ответ №1:

Используется groupby().transform для подсчета действительных продаж:

 required_sale_years = [2020, 2021]
required_sales_days = 4

# intermediate variables
df['year'] = df.date.dt.year
df['valid'] = df['year'].isin(required_sales_years) amp; df['amount'].gt(0)

# groupby
groups = df.groupby(['id','qual'])

has_years = groups['year'].transform(lambda x: set(required_sales_years).issubset(set(x)))
valid_sales = groups['valid'].transform('sum') >= required_sales_days

output = df[has_years amp; valid_sales]
 

Вывод:

         date   id qual  amount  year  valid
4 2020-09-01  123    B       8  2020   True
5 2020-09-02  123    B       6  2020   True
6 2020-09-03  123    B       4  2020   True
7 2020-09-04  123    B       2  2020   True
8 2021-02-01  123    B      18  2021   True
 

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

1. Это хорошо, но вам не хватает условия в поле даты, чтобы проверить, что год 2020

2. Я думаю, вам нужно каким-то образом включить год в группу и вернуть исходную дату в индекс

3. @Robert Я вижу, пропустил эту часть. Обновлен ответ. Спасибо.

4. Спасибо, но вы проверяете только, есть ли test[«date»].dt.year.isin(required_sale_years), который пройдет, если продажи будут только в 2020 году.

5. Я не понимаю вашу точку зрения? Разве вы не считаете только (положительные) продажи за эти годы? Или положительные продажи в другие годы также учитываются?