Как оптимизировать итерацию фрейма данных в панд?

#python #pandas #dataframe

Вопрос:

Мне нужно повторить кадр данных, для каждой строки мне нужно создать идентификатор на основе двух существующих столбцов: имя и пол. В конце концов я добавляю эту новую колонку в df.

 df = pd.read_csv(file, sep='t', dtype=str, na_values="", low_memory=False)
   row_ids = []
   for index, row in df.iterrows():
       if (index % 1000) == 0:
          print("Row node index: {}".format(str(index)))
     
     caculated_id = get_id(row['name', row['sex']])
     row_ids.append(caculated_id)

   df['id'] = row_ids
 

Есть ли способ сделать это намного быстрее, не переходя ряд за рядом?

Добавьте дополнительную информацию на основе предложенных решений:

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

1. Не могли бы вы включить функцию get_id и образец df?

2. Это обычная функция, принимающая ввод и возвращающая все, что угодно. Просто для примера.

3. Как создается идентификатор? Включите небольшой образец фрейма данных. Я не уверен, что get_id(row['name', row['sex']]) должен делать.

4. идентификатор=хэш(имя пол)

5. @marlon — pandas позволяет выполнять операции массово. Предположим id , это просто объединение name и sex . Ты мог бы это сделать df['id'] = df['name'] df['sex'] . Вместо функции, которая что-то делает с отдельными ячейками, посмотрите, можете ли вы что-то делать с целыми столбцами.

Ответ №1:

Используйте apply вместо этого:

 def func(x):
    if (x.name % 1000) == 0:
        print("Row node index: {}".format(str(x.name)))
 
    caculated_id = get_id(row['name', row['sex']])
    return caculated_id

df['id'] = df.apply(func, axis=1)
 

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

1. Возвращает ли приложение здесь список новых идентификаторов?

2. @марлон Да. Конечно.

3. Я проверю скорость на большом csv-файле.

4. Если моя функция get_xxx() возвращает несколько списков для более общих случаев, она также должна работать?

5. @marlon Да, apply возвращает серию всех результатов.

Ответ №2:

Если вы работаете с большим набором данных, это np.vectorize() должно помочь обойти apply() накладные расходы, что должно быть немного быстрее.

 import numpy as np

v = np.vectorize(lambda x: get_id(x['name'], x['sex']))
df['id'] = v(df)
 

Редактировать:

Чтобы получить еще большую скорость, вы также можете просто передать функцию get_id вместо использования лямбда-функции и передать df.*.values вместо df.* .

 v = np.vectorize(get_id)
df['id'] = v(df['name'].values, df['sex'].values)
 

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

 import numpy as np 
from tqdm import tqdm

@np.vectorize
def get_id(name, sex):
    global pbar
    ...
    pbar.update(1)
    ...
    return 


global pbar
with tqdm(total=len(df)) as pbar:
    df['id'] = get_id(df['name'].values, df['sex'].values)
 

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

1. Если get_id возвращает несколько списков, v{df} относится к списку списка? get_id может быть переименован в get_new_columns.

2. @marlon да, так и должно быть, в основном это работает так же, как apply() . Пожалуйста, попробуйте и дайте мне знать, если это быстрее для вас.

3. я буду стараться для скорости.

4. В вашем коде » df » отсутствует во 2-й строке?

5. @marlon нет, это не нужно df , чтобы его передавали v . Также я добавил в улучшение, не могли бы вы проверить, работает ли это?