Ошибка при фильтрации данных. Pandas

Рейтинг: 0Ответов: 2Опубликовано: 27.08.2023

Датафрейм:

import pandas as pd
import numpy as np

data = [['Girev', 'Andrey', 'ВИП', 2815, 29, 58, 6358, 'Moscow', 'Xiaomi'],
       ['Bykin', 'Stas', 'Все за 300', 3634, 37, 78, 602, 'Kazan', 'Samsung'],
       ['Ivanov', 'Alex', 'Всё за 800', 410, 47, 81, 3582, 'Moscow', 'Huawei'],
       ['Andreev', 'Sergey', 'Всё за 500', 1981, 75, 98, 5442, 'Kazan', 'Apple'],
       ['Girev', 'Stas', 'Всё за 800', 4969, 43, 61, 8510, 'Moscow', 'Samsung'],
       ['Bykin', 'Andrey', 'Всё за 500', 4308, 49, 39, 2525, 'Moscow', 'Xiaomi'],
       ['Kozlov', 'Igor', 'Всё за 800', 300, 60, 31, 8543, 'Yakutsk', 'Samsung'],
       ['Girev', 'Alex', 'Промо', 4199, 47, 90, 3925, 'Kazan', 'Apple'],
       ['Petrov', 'Nikolay', 'ВИП', 4810, 72, 88, 7188, 'Moscow', 'Apple'],
       ['Andreev', 'Sergey', 'Всё за 800', 4118, 52, 53, 419, 'Yakutsk', 'Apple'],
       ['Smolov', 'Stas', 'Промо', 1991, 28, 67, 5016, 'Kazan', 'Xiaomi'], 
        ['Girev', 'Igor', 'Корпоративный', 1430, 69, 19, 9520, 'Yakutsk', 'Samsung'],
       ['Kozlov', 'Andrey', 'Корпоративный', 113, 71, 82, 2785, 'Kazan', 'Apple'],
       ['Ivanov', 'Sergey', 'Промо', 3394, 39, 12, 2718, 'Yakutsk', 'Xiaomi'],
       ['Smolov', 'Sergey', 'Всё за 250 (архив)', 3493, 32, 6, 8959, 'Yakutsk', 'Huawei'],
       ['Kozlov', 'Stas', 'Всё за 800', 4565, 59, 82, 3168, 'Moscow', 'Apple'],
       ['Vlasov', 'Andrey', 'Всё за 800', 3192, 29, 74, 2852, 'Yakutsk', 'Xiaomi'],
       ['Smolov', 'Alex', 'Корпоративный', 3764, 71, 22, 2768, 'Moscow', 'Huawei'],
       ['Vlasov', 'Sergey', 'Всё за 800', 3816, 28, 35, 5734, 'Vladivostok', 'Apple'],
       ['Bykin', 'Alex', 'Промо', 817, 65, 34, 2131, 'Vladivostok', 'Samsung'],
       ['Andreev', 'Nikolay', 'Всё за 500', 385, 49, 62, 1815, 'Kazan', 'Xiaomi'],
       ['Bykin', 'Igor', 'Всё за 500', 2642, 38, 11, 3787, 'Moscow', 'Xiaomi'],
       ['Girev', 'Sergey', 'Все за 300', 4230, 62, 68, 5512, 'Vladivostok', 'Samsung'],
       ['Bykin', 'Sergey', 'Всё за 800', 4100, 48, 39, 227, 'Moscow', 'Xiaomi'],
       ['Girev', 'Stas', 'Все за 300', 3371, 53, 24, 7946, 'Kazan', 'Apple'],
       ['Smolov', 'Sergey', 'Корпоративный', 3577, 70, 71, 8847, 'Yakutsk', 'Huawei'],
       ['Mezov', 'Nikolay', 'Всё за 250 (архив)', 2742, 28, 19, 7115, 'Yakutsk', 'Huawei'],
       ['Smolov', 'Stas', 'Всё за 500', 2644, 41, 33, 8341, 'Moscow', 'Xiaomi'],
       ['Vlasov', 'Andrey', 'Всё за 500', 4725, 26, 93, 9441, 'Vladivostok', 'Xiaomi'],
       ['Ivanov', 'Nikolay', 'Всё за 500', 2785, 41, 5, 2901, 'Moscow', 'Samsung']]

df = pd.DataFrame(data, columns = ['surname', 'name', 'tarif', 'balance', 'age', 'sms', 'voice', 'city', 'phone'])

Нужно добавить в список "A" при 'age' меньше 25. Если больше 25 лет, то добавляем "B".

vacant=[]
for i in range(len(df)):
    if df["age"] < 25:
        vacant.append("A")
    elif df["age"] >25:
        vacant.append("B")

ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

Обычно такая ошибка при применении AND или OR, тут же не понимаю в чем причина. Помогите, пожалуйста. Желательно реализовать с использованием циклов

Ответы

▲ 2Принят

Ошибка возникает из-за того, что df["age"] - это целая серия (pd.Series), т.е. в данном случае - колонка значений возраста из фрейма, а условие df["age"]<25 из этой колонки формирует булев массив из 30 значений. Интерпретатор вполне справедливо возражает: "Истинное значение серии неоднозначно" и просит применить какую-либо функцию, с помощью которой можно привести эти 30 значений к одному - Истина или Ложь.
Ошибку спровоцировала также неправильная обработка данных внутри фрейма - в цикле вы не перебираете строки, а каждый раз осуществляете проверку столбца age из исходного фрейма. Вообще в Pandas циклы в явном виде почти не используются, т.к. механика Pandas заточена под векторные вычисления.
Например, в данном случае (и в случае посложнее, например, когда нужно определить не 2, а 5-10 или более категорий), удобно использовать категориальные данные:

print(pd.cut(df.age, (0, 25, 200), labels=('A', 'B'), right=False).tolist())

где мы определяем границы диапазонов и метки. Т.е. диапазону от 0 до 25 (не включая) будет присвоена метка A, диапазону от 25 до 200 - B. Можно сделать больше диапазонов и меток.

Если говорить о том, как сделать работоспособным ваш пример кода (что, повторюсь, неэффективно для Pandas), можно сделать так:

vacant = []
for i in range(len(df)):
    if df.at[i,"age"] < 25:
        vacant.append("A")
    else:
        vacant.append("B")
print(vacant)

или так

vacant = []
for _, row in df.iterrows():
    if row.age < 25:
        vacant.append("A")
    else:
        vacant.append("B")
print(vacant)
▲ 1

Вы напрасно используете цикл и векторные обращение к серии. Видимо, вы не до конца понимаете, как работает обращение к колонкам датафрейма. В вашем случае достаточно сделать просто:

res = np.where(df["age"]<25, "A", "B")

И еще, ваш пример не показателен - вы нем отсутствуют значения age меньше 25. И, как правильно заметили в комментариях, нужно обрабатывать условие, когда age равен 25.