Программа для запуска цикла 900 тыс. раз, чтобы выбрать 30 случайных чисел для каждой записи 900 тыс. клиентов

#python #pandas #dataframe #optimization #random

#python #pandas #фрейм данных #оптимизация #Случайный

Вопрос:

Я работаю над логикой … но это занимает больше времени, чем ожидалось…

Проблема:

  • Набор данных (A) с 60 идентификаторами продуктов

  • В наборе данных (B) около 90 тыс. клиентов

Мне нужно назначить 30 случайных уникальных идентификаторов продукта для каждого клиента…но повторения продуктов cam происходят для разных клиентов. Ниже приведен мой код:

 #List of 90K customers

web_cust_temp = web_cust['prsn_code'].tolist()
default_nom_ids['key']=1
    

#Allocating num_default ids to each customers
num_default=30    
 
#Create empty dataframe
final_df=pd.DataFrame()
for x in web_cust_temp:
    default_nom_temp=default_nom_ids.sample(n=num_default)
    prsn_df=pd.DataFrame([x])
    prsn_df['key']=1    
    interim=prsn_df.merge(default_nom_temp, how='inner', on=['key'])
    final_df=pd.concat([final_df,interim],axis=0) 
  

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

1. Пожалуйста, объясните свой код. Что такое web_cust_temp ? Что такое default_nom_keys ?

2. @RubenHelsloot web_cust_temp: список из 90 тыс. клиентов, default_nomination_ids : фрейм данных содержит 60 идентификаторов, из которых мне нужно назначить 30 каждому из клиентов в списке web_cust_temp

3. Ключ @RubenHelsloot — это столбец, который я создал как в default_nom_ids, так и в dataframe внутри цикла (prsn_df) . Надеюсь, это устранит путаницу

4. С повторением или без повторения?

5. @wildplasser для каждого клиента …. необходимо выбрать уникальные идентификаторы…..

Ответ №1:

Одна из идей здесь заключается в использовании argsort случайного массива для случайного выбора ровно 30 индексов для каждой строки:

 m,n = 60, 90_000

# remove seed for randomization
np.random.seed(42)
seeds = np.random.rand(m,n)

idx = np.argsort(seeds, axis=0)

out = web_cust['prsn_code'].values[idx[:,:30]]
  

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

1. Спасибо, позвольте мне попробовать это и вернусь к вам.

Ответ №2:

Я изменил «начальный» код для создания обоих исходных фреймов данных на:

 nProd = 60
idx = range(nProd)
default_nom_ids = pd.DataFrame({'Name': ['Product_'   str(i) for i in idx]}, index=idx)
default_nom_ids['key'] = 1
nCust = 1000
idx = range(nCust)
# Customer list, used in your code
web_cust_temp = ['Customer_'   str(i) for i in idx]
# DataFrame version of customer list, used in my code
cust = pd.DataFrame({'Name': web_cust_temp}, index=idx)
num_default = 30
  

Чтобы сравнить время выполнения, я преобразовал ваш код в функцию:

 def f1(num_default):
    final_df = pd.DataFrame()
    for x in web_cust_temp:
        default_nom_temp = default_nom_ids.sample(n=num_default)
        prsn_df = pd.DataFrame([x])
        prsn_df['key'] = 1    
        interim = prsn_df.merge(default_nom_temp, how='inner', on=['key'])
        final_df = pd.concat([final_df,interim], axis=0, ignore_index=True)
    return final_df
  

И мой код я определил как другую функцию:

 def f2(num_default):
    tbl = []
    for idxC in cust.index:
        idxP = default_nom_ids.sample(n=num_default, replace=False).index
        tbl.append(np.vstack([np.full(num_default, idxC), idxP]))
    idx = np.hstack(tbl)
    result = pd.DataFrame({'dummy': 1}, index=pd.MultiIndex.from_arrays(idx, names=['Cust', 'Prod']))
    return result.join(cust, on='Cust').join(default_nom_ids, on='Prod',
        lsuffix='_Cust', rsuffix='_Prod').drop(columns=['dummy', 'key'])
  

Используя%timeit, я сравнил время выполнения:

  • ваш код: 19,6 с,
  • мой код: 1.31 с.

Обратите внимание, что приведенный выше результат относится к 1000 клиентам. Если количество клиентов больше, разница во времени должна быть еще более заметной.