Могу ли я использовать numba для ускорения этого цикла?

#python #numpy #performance #numba

Вопрос:

Я наткнулся на numba, которая является фантастической библиотекой для ускорения кода на python. Мне было интересно, есть ли какой-либо способ преобразовать этот код в код numpy, чтобы использовать его в numba. Мое намерение состоит в том , чтобы для каждого элемента комбинации имени ОС и идентификатора cookie клиента выяснить, в чем заключаются различия в каждом столбце, и записать все столбцы, в которых было показано хотя бы одно различие в словаре.

Я пытался сделать :

 @jit(nopython = True) def gigi(): from tqdm.notebook import trange, tqdm df = df.applymap(str)  df2 = df.copy() del df2['client_cookie_id']   s = [] d = {}  for c in tqdm(range(0, len(df.client_cookie_id.unique().tolist()))):   cid = df.client_cookie_id.unique().tolist()[c]   for OS in df.OS_name.unique().tolist():   ### take the indexes of all the occurrences of a single client_cookie_id   t = df[(df['client_cookie_id'] == cid) amp; (df['OS_name'] == OS)].index.tolist()   if len(t) gt;= 2:   A = t[0]   for i in t[1:]:    B = i   list1 = list(df2.loc[A])  list2 = list(df2.loc[B])   common = list(dict.fromkeys([l1 for l1 in list1 if l1 in list2]))  remaining = list(filter(lambda i: i not in common, list1 list2))   t1 = []   for i in range(0, len(remaining)):   t1.append(remaining[i].split('___')[0])   used = set()  unique = [x for x in t1 if x not in used and (used.add(x) or True)]  unique   for i in range(0, len(unique)):   s.append(unique[i])   s = [x for x in s if x not in used and (used.add(x) or True)]   d[cid] = s   else:   continue  return d  gigi()  d = gigi()  

Но я получаю следующую ошибку

 AssertionError: Failed in nopython mode pipeline (step: inline calls to locally defined closures) key already in dictionary: '$phi28.0'  

Кто-нибудь может мне помочь? Спасибо

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

1. На что это тратит время? Вы измерили его? Бессмысленно пытаться оптимизировать цикл, если вы не знаете, где он проводит большую часть своего времени. Закон Амдала. Помните, что numba это не может помочь тому времени, которое вы проводите в пандах.

2. Вы можете заменить весь for i in range(0,len(unique)): цикл, сказав s.extend(unique) .

3. Вы можете заменить строки used = set() / unique = [x for x...] , сказав unique = list(set(t1)) .

4. Я подозреваю, что многие из ваших tolist звонков не нужны. Вы можете перебирать ряды фреймов данных так же легко, как список.

5. Вы не можете использовать внешний модуль, такой как tqdm, в функциях Numba, и даже если бы вы могли, это не будет быстрее, потому что jit не может работать с внешними типами модулей/вызовами). Numba ускоряет только базовые цифровые коды или коды с вызовами Numpy (и несколькими вызовами Scipy). Списки поддерживаются Numba, но они еще не очень эффективны, и существует несколько ограничений, которые необходимо выполнить. PyPy-это JIT, который поддерживает общие коды python (несмотря на некоторые незначительные изменения/изменения). Однако PyPy еще не поддерживает все модули Python и часто работает не так быстро, как Numba для цифровых кодов на основе Numpy.

Ответ №1:

Это не решает всю вашу проблему, но показывает гораздо более быстрый способ сканирования строк. Обратите внимание, что я печатаю здесь только несоответствия; я их не собираю. Не уверен, что вы хотели получить точный результат:

 import pandas as pd  data = {   'client_cookie_id': [ 111, 111, 111, 222, 222, 222 ],  'OS_name': [ 333, 333, 444, 555, 555, 666 ],  'data1': [ 21, 22, 23, 24, 25, 26 ],  'data2': [ 31, 31, 31, 32, 33, 33 ]  }   def gigi(df):  df = df.applymap(str)  df = df.sort_values( by=['client_cookie_id', 'OS_name'] )   last = None  for index, row in df.iterrows():  if last is not None and row['client_cookie_id'] == last['client_cookie_id'] and row['OS_name'] == last['OS_name']:  # Compare the other columns.  for name,b,c in zip(row.index, row, last):  if name not in ('client_cookie_id', 'OS_name') and b != c:  print("Difference in", name,   "with", row['client_cookie_id'], '/',   row['OS_name'], ": ", b, c )  else:  last = row  df = pd.DataFrame(data) gigi(df)  

Выход:

 Difference in data1 with 111 / 333 : 22 21 Difference in data1 with 222 / 555 : 25 24 Difference in data2 with 222 / 555 : 33 32  

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

1. Это очень полезно, Тим! Большое спасибо. Моя идея состояла в том, чтобы записать разницу в каждой функции в словаре, например: cookie_id_5 : [feat1, feat4, feat6] Может быть, я могу попытаться изменить ваш код, чтобы получить то, что я хочу