Как эффективно присваивать значения ячейкам информационного блока итерируя по другому объекту - PullRequest
0 голосов
/ 20 сентября 2018

Я получил объект генератора, который в основном состоит из вложенных списков.Он содержит около 20 000 списков, структура выглядит следующим образом:

cases = [[0,36,12],[64,28,1],....

Каждый список в этом объекте представляет строки, принадлежащие одному процессу.Теперь я хочу назначить ProcessID соответствующим строкам кадра данных.В данный момент я достигаю этого с помощью цикла for:

moc = df.iloc
processID = 0 
for process in cases:
  for step in process:
    moc[process,-1] = processID
  processID += 1

Несмотря на то, что это работает, итерация цикла for занимает много времени, поэтому я заинтересован в более эффективном способе назначения processID.

Поскольку мне нужно перебирать объект case и поскольку длина вложенных списков различается, я не знаю, как реализовать более эффективные процессы, такие как df.apply () или np.where ().

Любая помощь приветствуется.

Пример:

import pandas as pd
import numpy as np

cases = [[1,4,2],[3,5,0],[9,6],[7,8]]


d = {'col1': ["some_information", "some_information","some_information",
              "some_information","some_information","some_information", 
              "some_information","some_information","some_information",
              "some_information"],
    'processID':np.empty}

df = pd.DataFrame(data=d)

print(df)
               col1                  processID
0  some_information  <built-in function empty>
1  some_information  <built-in function empty>
2  some_information  <built-in function empty>
3  some_information  <built-in function empty>
4  some_information  <built-in function empty>
5  some_information  <built-in function empty>
6  some_information  <built-in function empty>
7  some_information  <built-in function empty>
8  some_information  <built-in function empty>
9  some_information  <built-in function empty>

moc = df.iloc
processID = 1
for case in cases:
    for idx in case:
        moc[idx,-1] = processID

    processID += 1


print(df)
               col1 processID
0  some_information         2
1  some_information         1
2  some_information         1
3  some_information         2
4  some_information         1
5  some_information         2
6  some_information         3
7  some_information         4
8  some_information         4
9  some_information         3

1 Ответ

0 голосов
/ 20 сентября 2018

IIUC, вот решение, использующее понимание dict с Index.repeat и numpy.hstack для создания pandas.Series, которое вы можете использовать для обновления DataFrame.Преимущество этого в том, что циклов нет.

s = pd.Series({(i+1):x for i, x in enumerate(cases)})
processes = pd.Series(s.index.repeat(s.str.len()), index=np.hstack(s))

На основе вашего примера cases это создаст Series 'процессов', таких как:

1    1
4    1
2    1
3    2
5    2
0    2
9    3
6    3
7    4
8    4

Тогда вызатем можно назначить в ваш DataFrame:

df['processID'] = processes

Производительность тестирования

setup - создание DataFrame из len 100 000 и случайного cases списка:

idx = pd.Series(np.arange(100000)).sample(frac=1).values.tolist()
cases = [idx[i:i + 3] for i in range(0, len(idx), 3)]

df=pd.DataFrame({'col1':np.arange(100000),
                 'col2':['some_data']*100000})

Сроки

%%timeit

s = pd.Series({(i+1):x for i, x in enumerate(cases)}).to_frame()
processes = pd.Series(s.index.repeat(s[0].str.len()), index=np.hstack(s[0]))
df['processID'] = processes

92.2 ms ± 1.79 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
...