2016-07-13 1 views
3

У меня есть dataframe вроде этого:панды получить индекс высшей точки продукта

df1 = pd.DataFrame({'a':[1,2,3,4],'b':[5,6,7,8],'c':[9,10,11,12]}) 
    a b c 
0 1 5 9 
1 2 6 10 
2 3 7 11 
3 4 8 12 

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

Например для первой строки мы вычислим точечные продукты от других строк:

df1.drop(0).dot(df1.loc[0]).idxmax() 
output: 3 

Поэтому я могу создать функцию:

def get_highest(dataframe): 
    lis = [] 
    for row in dataframe.index: 
     temp = dataframe.drop(row).dot(dataframe.loc[row]) 
     lis.append(temp.idxmax()) 
    return lis 

И я получаю то, что я хочу с :

df1['highest'] = get_highest(df1) 
output: 
    a b c highest 
0 1 5 9 3 
1 2 6 10 3 
2 3 7 11 3 
3 4 8 12 2 

Хорошо, это работает, но проблема в том, что он не масштабируется на ВСЕ. Вот выходы timeit для различного количества строк:

4 rows: 2.87 ms 
40 rows: 77.1 ms 
400 rows: 700 ms 
4000 rows: 10.4s 

И я должен выполнить это на dataframe, который имеет примерно 240k строк и столбцов 3.3K. Поэтому вот мой вопрос: есть ли способ оптимизировать этот расчет? (вероятно, обратившись к нему по-другому)

Заранее спасибо.

+0

Я добавил Numpy тег, потому что, вероятно, NumPy решение на базе будет работать быстрее, так Numpy люди могут также иметь вид на него. – ayhan

+0

@ayhan Хорошая идея, спасибо – ysearka

+0

Это может быть полезно. http://stackoverflow.com/q/38177464/2336654 – piRSquared

ответ

2

Выполните умножение матриц с транспонированным:

mat_mul = np.dot(df.values, df.values.T) 

Заполните диагонали с небольшим числом, поэтому они не могут быть максимума (я предполагал, все положительные, так заполнены -1, но вы можете изменить это):

np.fill_diagonal(mat_mul, -1) 

Теперь возьмите Argmax массива:

df['highest'] = mat_mul.argmax(axis=1) 

Timings на 10к по 4 ДФ:

%%timeit 
mat_mul = np.dot(df.values, df.values.T) 
np.fill_diagonal(mat_mul, -1) 
df['highest'] = mat_mul.argmax(axis=1) 

1 loop, best of 3: 782 ms per loop 

%timeit df['highest'] = get_highest(df) 
1 loop, best of 3: 9.8 s per loop 
+0

Спасибо за ваш ответ, на самом деле я уже пробовал это, но проблема в том, что 'np.dot' на больших dataframes занимает много памяти, поэтому я мгновенно получаю 'MemoryError'. Может быть, есть способ блокировать DataFrame? Я не очень разбираюсь в деталях. – ysearka

+0

Честно говоря, я также не знаю, как эффективно выполнять умножение матрицы по частям. Позвольте мне попробовать несколько вещей. – ayhan

2

Поскольку точка-продукты будет повторяться для пар, когда они перевернуты, окончательный массив дота-продукт для каждой строки в отношении каждой другой строки был бы симметричен один. Таким образом, мы можем вычислить либо элементы верхнего или верхнего треугольника, а затем получить полную форму, используя scipy's squareform. Таким образом, мы имели бы реализацию как так -

from scipy.spatial.distance import squareform 

arr = df1.values 
R,C = np.triu_indices(arr.shape[0],1) 
df1['highest'] = squareform(np.einsum('ij,ij->i',arr[R],arr[C])).argmax(1) 

Выход для образца случае -

In [145]: df1 
Out[145]: 
    a b c highest 
0 1 5 9  3 
1 2 6 10  3 
2 3 7 11  3 
3 4 8 12  2 
+0

Это хорошая идея, она превосходит мой код до 4k строк, но когда я пробую 40k строк, кажется, что они совпадают, поэтому я склонен думать, что это будет хорошо на моем основном фреймворке, к сожалению – ysearka

+0

@ysearka Позвольте мне спросить вы - У вас есть отрицательные числа в dataframe? Кроме того, замените 'np.einsum ('ij, ij-> i', arr [R], arr [C])' с '(arr [R] * arr [C]). Sum (1)' и посмотрим, все еще есть несоответствие? – Divakar

+0

Глубоко извините за задержку, я сосредоточился на еще одной неотложной задаче. У меня нет отрицательного числа в моем кадре данных, они на самом деле являются количествами (количествами или томами). И, к сожалению, попытка заменить вас не улучшает время вычисления. – ysearka

Смежные вопросы