Почему Fillna не работает, как ожидалось для режима - PullRequest
0 голосов
/ 05 февраля 2019

Я работаю над набором данных по продажам автомобилей, имеющим столбцы: «автомобиль», «цена», «кузов», «пробег», «engV», «engType», «регистрация», «год», «модель»,'drive'

столбец 'drive' и 'engType' имеют пропущенные значения NaN, я хочу рассчитать режим, скажем, для 'drive' на основе группировки по ['car', 'model'], а затемгде эта группа попадает, я хочу заменить значение NaN там на основе этой группы

Я пробовал эти методы:

  • для числовых данных

    carsale ['engV2'] = (carsale.groupby (['car', 'body', 'model'])) ['engV'].transform (лямбда x: x.fillna (x.median ()))

    • все работает нормально, заполняя / заменяя данные точно
  • для категориальных данных

    carsale ['driveT'] = (carsale.groupby (['car', 'model'])) ['drive']. Transform (lambda x: x.fillna (x.mode ())) carsale ['driveT'] = (carsale.groupby (['car', 'model'])) ['drive']. transform (лямбда x: x.fillna (pd.Series.mode (х)))

оба дают одинаковые результаты

enter image description here


  • Вот полный код:

# carsale['price2'] = (carsale.groupby(['car','model','year']))['price'].transform(lambda x: x.fillna(x.median()))

# carsale['engV2'] = (carsale.groupby(['car','body','model']))['engV'].transform(lambda x: x.fillna(x.median()))
# carsale['mileage2'] = (carsale.groupby(['car','model','year']))['mileage'].transform(lambda x: x.fillna(x.median()))
# mode = carsale.filter(['car','drive']).mode()
# carsale[['test1','test2']] = carsale[['car','engType']].fillna(carsale.mode().iloc[0])

**carsale.groupby(['car', 'model'])['engType'].apply(pd.Series.mode)**

# carsale.apply()
# carsale
# carsale['engType2'] = carsale.groupby('car').engType.transform(lambda x: x.fillna(x.mode()))

**carsale['driveT'] = carsale.groupby(['car', 'model'])['drive'
        ].transform(lambda x: x.fillna(x.mode()))
carsale['driveT'] = carsale.groupby(['car', 'model'])['drive'
        ].transform(lambda x: x.fillna(pd.Series.mode(x)))**

# carsale[carsale.car == 'Mercedes-Benz'].sort_values(['body','engType','model','mileage']).tail(50)
# carsale[carsale.engV.isnull()]
# carsale.sort_values(['car','body','model'])

**carsale**

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

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

Так что дело в том, что на самом деле он не рассчитывает режим на основе группы ['car', 'model'], вместо этого он выполняет режим для отдельных значений в 'drive', но если вы выполните эту команду

**carsale.groupby(['car','model'])['engType'].apply(pd.Series.mode)**

это правильно рассчитанный режим, основанный на групповом режиме (автомобиль, модель)

enter image description here

Кто-нибудь может помочь в этом вопросе?

1 Ответ

0 голосов
/ 06 февраля 2019

Мой подход заключался в следующем:

  1. Используйте .groupby () для создания справочного фрейма данных, который содержит режим функции drive для каждой комбинации car / model.
  2. Напишите метод, который ищет режим в этом кадре данных и возвращает его для данного автомобиля / модели, когда значение этого автомобиля / модели в drive равно нулю.

ОднакоОказалось, что есть два ключевых угловых случая, специфичных для набора данных OP, которые необходимо обработать:

  • Когда у конкретного автомобиля / модели нет режима (потому что все записи в столбце drive для этогокомбо были NaN).
  • Когда у конкретной марки автомобиля нет режима.

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

carsale = pd.DataFrame({'car': ['Ford', 'Mercedes-Benz', 'Mercedes-Benz', 'Mercedes-Benz', 'Mercedes-Benz', 'Nissan', 'Honda','Renault', 'Mercedes-Benz', 'Mercedes-Benz', 'Toyota', 'Toyota', 'Ferrari'],
                   'price': [15500.000, 20500.000, 35000.000, 17800.000, 33000.000, 16600.000, 6500.000, 10500.000, 21500.000, 21500.000, 1280.000, 2005.00, 300000.000],
                   'body': ['crossover', 'sedan', 'other', 'van', 'vagon', 'crossover', 'sedan', 'vagon', 'sedan', 'sedan', 'compact', 'compact', 'sport'],
                   'mileage': [68.0, 173.0, 135.0, 162.0, 91.0, 83.0, 199.0, 185.0, 146.0, 146.0, 200.0, 134, 123.0],
                   'engType': ['Gas', 'Gas', 'Petrol', 'Diesel', np.nan, 'Petrol', 'Petrol', 'Diesel', 'Gas', 'Gas', 'Hybrid', 'Gas', 'Gas'],
                   'registration':['yes', 'yes', 'yes', 'yes', 'yes', 'yes', 'yes', 'yes', 'yes', 'yes', 'yes', 'yes', 'yes'],
                   'year': [2010, 2011, 2008, 2012, 2013, 2013, 2003, 2011, 2012, 2012, 2009, 2003, 1988],
                   'model': ['Kuga', 'E-Class', 'CL 550', 'B 180', 'E-Class', 'X-Trail', 'Accord', 'Megane', 'E-Class', 'E-Class', 'Prius', 'Corolla', 'Testarossa'],
                   'drive': ['full', 'rear', 'rear', 'front', np.nan, 'full', 'front', 'front', 'rear', np.nan, np.nan, 'front', np.nan],
                  })
carsale

    car               price  body       mileage   engType   registration  year  model       drive
0   Ford            15500.0  crossover     68.0   Gas       yes           2010  Kuga        full
1   Mercedes-Benz   20500.0  sedan        173.0   Gas       yes           2011  E-Class     rear
2   Mercedes-Benz   35000.0  other        135.0   Petrol    yes           2008  CL 550      rear
3   Mercedes-Benz   17800.0  van          162.0   Diesel    yes           2012  B 180       front
4   Mercedes-Benz   33000.0  vagon         91.0   NaN       yes           2013  E-Class     NaN
5   Nissan          16600.0  crossover     83.0   Petrol    yes           2013  X-Trail     full
6   Honda            6500.0  sedan        199.0   Petrol    yes           2003  Accord      front
7   Renault         10500.0  vagon        185.0   Diesel    yes           2011  Megane      front
8   Mercedes-Benz   21500.0  sedan        146.0   Gas       yes           2012  E-Class     rear
9   Mercedes-Benz   21500.0  sedan        146.0   Gas       yes           2012  E-Class     NaN
10  Toyota           1280.0  compact      200.0   Hybrid    yes           2009  Prius       NaN
11  Toyota           2005.0  compact      134.0   Gas       yes           2003  Corolla     front
12  Ferrari        300000.0  sport        123.0   Gas       yes           1988  Testarossa  NaN
  1. Создайте фрейм данных, который отображает режим функции drive для каждогоcar / model комбинация.

    Если у комбинации автомобиля / модели нет режима (например, ряда с Toyota Prius), я заполняю режим этой конкретной марки автомобиля (Toyota).

    Однако, если автомобильСам по себе бренд (например, Ferrari в моем примере) не имеет режима, я заполняю режим набора данных для функции drive.

def get_drive_mode(x):
    brand = x.name[0]
    if x.count() > 0:
        return x.mode() # Return mode for a brand/model if the mode exists.
    elif carsale.groupby(['car'])['drive'].count()[brand] > 0:
        brand_mode = carsale.groupby(['car'])['drive'].apply(lambda x: x.mode())[brand]
        return brand_mode # Return mode of brand if particular brand/model combo has no mode,
    else:                 # but brand itself has a mode for the 'drive' feature. 
        return carsale['drive'].mode() # Otherwise return dataset's mode for the 'drive' feature.

drive_modes = carsale.groupby(['car','model'])['drive'].apply(get_drive_mode).reset_index().drop('level_2', axis=1)
drive_modes.rename(columns={'drive': 'drive_mode'}, inplace=True)
drive_modes

    car             model        drive_mode
0   Ferrari         Testarossa   front
1   Ford            Kuga         full
2   Honda           Accord       front
3   Mercedes-Benz   B 180        front
4   Mercedes-Benz   CL 550       rear
5   Mercedes-Benz   E-Class      rear
6   Nissan          X-Trail      full
7   Renault         Megane       front
8   Toyota          Corolla      front
9   Toyota          Prius        front
Напишите метод, который ищет значение режима drive для данного автомобиля / модели в данной строке, если значение этой строки для drive равно NaN:
def fill_with_mode(x):
    if pd.isnull(x['drive']):
        return drive_modes[(drive_modes['car'] == x['car']) & (drive_modes['model'] == x['model'])]['drive_mode'].values[0]
    else:
        return x['drive']
Примените вышеуказанный метод к строкам в фрейме данных carsale, чтобы создать элемент driveT:
carsale['driveT'] = carsale.apply(fill_with_mode, axis=1)
del(drive_modes)

, что приведет к следующему фрейму данных:

carsale

    car               price  body       mileage   engType   registration  year  model       drive   driveT
0   Ford            15500.0  crossover     68.0   Gas       yes           2010  Kuga        full    full
1   Mercedes-Benz   20500.0  sedan        173.0   Gas       yes           2011  E-Class     rear    rear
2   Mercedes-Benz   35000.0  other        135.0   Petrol    yes           2008  CL 550      rear    rear
3   Mercedes-Benz   17800.0  van          162.0   Diesel    yes           2012  B 180       front   front
4   Mercedes-Benz   33000.0  vagon         91.0   NaN       yes           2013  E-Class     NaN     rear
5   Nissan          16600.0  crossover     83.0   Petrol    yes           2013  X-Trail     full    full
6   Honda            6500.0  sedan        199.0   Petrol    yes           2003  Accord      front   front
7   Renault         10500.0  vagon        185.0   Diesel    yes           2011  Megane      front   front
8   Mercedes-Benz   21500.0  sedan        146.0   Gas       yes           2012  E-Class     rear    rear
9   Mercedes-Benz   21500.0  sedan        146.0   Gas       yes           2012  E-Class     NaN     rear
10  Toyota           1280.0  compact      200.0   Hybrid    yes           2009  Prius       NaN     front
11  Toyota           2005.0  compact      134.0   Gas       yes           2003  Corolla     front   front
12  Ferrari        300000.0  sport        123.0   Gas       yes           1988  Testarossa  NaN     front

Обратите внимание, что в строках 4 и 9 столбца driveT значение NaN, которое было в столбце drive, было заменено строкой rear, которая, как и следовало ожидать, является режимом drive для Mercedes E-Class.

Кроме того, в строке 11, так как отсутствует режим для комбинированного автомобиля / модели Toyota Prius, мы заполняем режим для марки Toyota, который равен front.

Наконец, в строке 12, поскольку для марки автомобиля Ferrari нет режима, мы заполняем режим столбца drive всего набора данных, который также равен front.

.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...