Поиск значения в DataFrame на основе нескольких столбцов - PullRequest
2 голосов
/ 04 октября 2019

Проблема: извлечь значение определенного столбца (в данном случае «рейтинг») для нескольких ограничений значений столбца.

Начиная с фрейма данных, выглядящего следующим образом

Мои данныеследующим образом:

    userID  movieID rating
0   196 242 3
1   186 302 3
2   22  377 1

Теперь я хочу извлечь оценку для следующего случая:

userID == 196
movieID == 242

Результат должен быть 3.

Я решилэто, используя следующий код: Однако это не очень эффективно. У кого-нибудь есть лучший подход?

df.loc[df['userID'] == 196].where(df['movieID'] == 242).dropna()['rating']

Что дает мне рейтинг фильма с идентификатором 242 и идентификатором пользователя 196.

1 Ответ

2 голосов
/ 04 октября 2019

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

df = df.set_index(['userID', 'movieID'])
df.at[(196, 242), 'rating']
#3

Некоторые моменты времени. Как только индекс установлен, поиск выполняется очень быстро.

%timeit df.at[(userID, movieID), 'rating']
#19.9 µs ± 405 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

df1 = df.reset_index()
%timeit df1.loc[df1['userID'].eq(196) & df1['movieID'].eq(242), 'rating']
#1.2 ms ± 6.98 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Требуется время, чтобы установить MultiIndex так, чтобы это могло быть дорогостоящим для одного запроса. Но для многих это быстро окупится, особенно с большим DataFrame. Вот пример времени, когда мы можем использовать уникальный MulitIndex (после установки индекса).

import perfplot
import pandas as pd
import numpy as np

perfplot.show(
    setup=lambda n: pd.DataFrame({'userID': range(n),
                                  'movieID': range(n),
                                  'rating': range(n)}).set_index(['userID', 'movieID']), 
    kernels=[
        lambda df: df.at[(4 ,4), 'rating'],
        lambda df: df.loc[(df.index.get_level_values('userID') == 4) 
                          & (df.index.get_level_values('movieID') == 4), 'rating']
    ],
    labels=["MultiIndex", "Boolean Slice"],
    n_range=[2 ** k for k in range(5, 25)],
    equality_check=np.allclose,  
    xlabel="len(df)"
)

enter image description here

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