Dask: преобразование фрейма данных отношения «многие ко многим»

#python #dataframe #dask

#python #фрейм данных #dask

Вопрос:

У меня есть фрейм данных dask, подобный приведенному ниже.

 > print(df_user_preferences)
       user_id  food_id
int64  int64    int64
...
  

Этот фрейм данных представляет отношение «Многие ко многим» между user и food .
Существуют также два фрейма данных, df_users и df_foods , и это основные данные пользователей и продуктов питания.

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

 # index is user_id.
> print(df_spread_user_preferences)
       food_1   food_2   food_3   food_4  ...
int64  boolean  boolean  boolean  boolean ...
...
  

Эти столбцы с префиксом, food_ заканчивающимся на food_id , и их значения представляют отношение между user и food .

Я пробовал приведенный ниже код, но это слишком медленно. Как я могу улучшить этот код для более эффективной работы?

 df_spread_user_preferences = df_users.assign(**{
    f"food_{food_id}": lambda df, food_id: df.apply(
      lambda row, food_id: len(df_user_preferences[(
          df_user_preferences.food_id == food_id
      ) amp; (
          df_user_preferences.user_id == row.name
      )]) > 0,
      axis=1,
      meta='boolean',
      food_id=food_id
    ) for _, food_id in df_foods.index.to_series().iteritems()
}).drop(df_users.columns)
  

Ответ №1:

 df_users = pd.DataFrame({'user_id': [1,2]})
df_foods = pd.DataFrame({'food_id': [11,22,33,44]})
df_user_preferences = pd.DataFrame({'user_id' : [1,1], 'food_id' : [11,22]})

# Create a dataframe with columns user_ids and all food_ids.
# All food_ids of all the users are assigned False
df_spread_user_preferences = pd.DataFrame({
        **{'user_id': df_users['user_id']}, 
        **{"food_{0}".format(i):False for i in df_foods['food_id']}})
# Find the food preference of the users and create a list 
foods = df_user_preferences.groupby(['user_id'])['food_id'].apply(list).apply(
    lambda x: ["food_{0}".format(i) for i in x]).reset_index()
# For each user get the preference list and reset them to True 
for _, r in foods.iterrows():
     df_spread_user_preferences.loc[
df_spread_user_preferences['user_id'] == r['user_id'], r['food_id']] = True

print (df_spread_user_preferences)
  


food_11 food_22 food_33 food_44 user_id
0 True True False False 1
1 False False False False 2

Вы можете присвоить индексу значение user_id с помощью df_spread_user_preferences.set_index('user_id')