Ускорение UDF в xlwings

Я попытался поэкспериментировать с некоторыми функциями Xlwings. Я хотел бы использовать общую функцию из numpy, которая позволяла быстро интерполировать (numpy.interp).

@xlfunc
def interp(x, xp,yp):
    """Interpolate vector x on vector (xp,yp)"""
    y=np.interp(x,xp,yp)
    return y

@xlfunc
def random():
    """Returns a random number between 0 and 1"""
    x=np.random.randn()
    return x   

Например, я создаю два вектора (xp, yp) вот так (в Excel) 800 строк

First Column Second Column
0    =random()
1    =random()
2    =random()
3    =random()
4    =random()
5    =random()
[...]

В третьем столбце я создаю еще один вектор (60 строк) со случайным числом от 0 до 800 (в порядке возрастания), что дает мне что-то вроде этого:

Third Column    
17.2    
52.6    
75.8    
[...]

Я хотел бы интерполировать третий столбец в первый столбец. Так

Fourth Column    
=interp(C1,A1:A800,B1:B800)    
=interp(C2,A1:A800,B1:B800)    
=interp(C3,A1:A800,B1:B800)    
[...]

Это легко сделать. Но если у меня есть 10 или более столбцов для интерполяции, это может занять слишком много времени. Я уверен, что есть лучший способ сделать это. Идея ?

Спасибо за вашу помощь !

изменить :

Я пробовал это, но не работает в "xw.Range[...].value=y"

@xw.xlfunc
def interpbis(x, xp,yp):
    """Interpolate scalar x on vector (xp,yp)"""
    thisWB=xw.Workbook.active()
    thisSlctn=thisWB.get_selection(asarray=True)
    sheet=thisSlctn.xl_sheet.name
    r = thisSlctn.row
    c = thisSlctn.column
    y=np.interp(x,xp,yp)
    xw.Range(sheet,(r,c)).value=y
    return None

person Coolpix    schedule 02.01.2016    source источник
comment
Вы пробовали это и обнаружили некоторые реальные проблемы с производительностью?   -  person Felix Zumstein    schedule 04.01.2016
comment
Да, в самом деле. На самом деле, когда я запускаю все вычисления, это занимает столько же времени, сколько в VBA (я думаю, это потому, что UDF построен для запуска на каждой ячейке по отдельности). Может быть, если бы я мог работать с диапазоном, это было бы быстрее, но я не знаю, как это сделать легко.   -  person Coolpix    schedule 05.01.2016
comment
Изменить. Если бы я мог получить адрес активной ячейки, я мог бы сделать что-то вроде Range(ActiveCell).table=ar с массивом ar с результатом?   -  person Coolpix    schedule 05.01.2016


Ответы (1)


Короткий ответ: используйте функции массива Excel.

Длинный ответ: во-первых, обновите xlwings до версии 0.6.4 (иначе то, что я собираюсь показать для random(), не будет работать). Затем измените свои функции следующим образом:

from xlwings import Application, Workbook, xlfunc
import numpy as np

@xlfunc
def interp(x, xp, yp):
    """Interpolate vector x on vector (xp,yp)"""
    y = np.interp(x, xp, yp)
    return y[:, np.newaxis]  # column orientation

@xlfunc
def random():
    """Returns a random number between 0 and 1"""
    app = Application(Workbook.caller())
    # We shall make this easier in a future release (getting the array dimensions)
    r = app.xl_app.Caller.Rows.Count
    c = app.xl_app.Caller.Columns.Count
    x = np.random.randn(r, c)
    return x

Теперь используйте формулы массива в Excel, как описано здесь (Ctrl+Shift+Enter ).

person Felix Zumstein    schedule 06.01.2016
comment
Большое спасибо, отличная работа :) И это очень быстро - person Coolpix; 06.01.2016
comment
Я также пробовал что-то подобное, но я получаю автоматизацию Erreur в строке Range.Value. Если у вас есть идеи `xw.xlfunc def interpbis(x, xp,yp): Интерполировать скаляр x по вектору (xp,yp) thisWB=xw.Workbook.active() thisSlctn=thisWB.get_selection(asarray=True) y= np.interp(x,xp,yp) thisSlctn.value=y - person Coolpix; 06.01.2016
comment
thisSlctn.xl_sheet.name возвращает объект из pywin32 или appscript (в зависимости от вашей платформы). вам придется заменить его чем-то вроде thisWB.name в вашем образце. - person Felix Zumstein; 06.01.2016
comment
Извините, это должно читаться как thisWB.active_sheet.name, но вы также можете использовать thisWB.active_sheet непосредственно в Range(). - person Felix Zumstein; 07.01.2016
comment
Спасибо за Ваш ответ. К сожалению, это все еще блок в строке 'xw.Range() = y:/ - person Coolpix; 07.01.2016
comment
Привет, не знаешь есть ли решение? В очередной раз благодарим за помощь. - person Coolpix; 12.01.2016