2017-07-05 4 views
1

Ich versuche, Cython zu verwenden, um die Leistung einer Schleife zu verbessern, aber ich renne in einige Probleme, die die Typen der Eingaben deklarieren.Cython Typing-Liste der Strings

Wie füge ich ein Feld in meiner typisierten Struktur, die eine Zeichenfolge, die entweder ‚Front‘ oder ‚Zurück‘

Ich habe sein kann ein np.recarray, die wie folgt aussieht (beachten Sie die Länge der recarray ist nicht bekannt, wie die Kompilierung)

import numpy as np 
weights = np.recarray(4, dtype=[('a', np.int64), ('b', np.str_, 5), ('c', np.float64)]) 
weights[0] = (0, "front", 0.5) 
weights[1] = (0, "back", 0.5) 
weights[2] = (1, "front", 1.0) 
weights[3] = (1, "back", 0.0) 

sowie Eingänge einer Liste von Strings und ein pandas.Timestamp

import pandas as pd 
ts = pd.Timestamp("2015-01-01") 
contracts = ["CLX16", "CLZ16"] 

Ich versuche, die folgende Schleife cythonize

def ploop(weights, contracts, timestamp): 
    cwts = [] 
    for gen_num, position, weighting in weights: 
     if weighting != 0: 
      if position == "front": 
       cntrct_idx = gen_num 
      elif position == "back": 
       cntrct_idx = gen_num + 1 
      else: 
       raise ValueError("transition.columns must contain " 
           "'front' or 'back'") 
      cwts.append((gen_num, contracts[cntrct_idx], weighting, timestamp)) 
    return cwts 

Mein Versuch umfasste die weights Eingang als Struktur in cython eingeben, in einer Datei struct_test.pyx als

import numpy as np 
cimport numpy as np 


cdef packed struct tstruct: 
    np.int64_t gen_num 
    char[5] position 
    np.float64_t weighting 


def cloop(tstruct[:] weights_array, contracts, timestamp): 
    cdef tstruct weights 
    cdef int i 
    cdef int cntrct_idx 

    cwts = [] 
    for k in xrange(len(weights_array)): 
     w = weights_array[k] 
     if w.weighting != 0: 
      if w.position == "front": 
       cntrct_idx = w.gen_num 
      elif w.position == "back": 
       cntrct_idx = w.gen_num + 1 
      else: 
       raise ValueError("transition.columns must contain " 
           "'front' or 'back'") 
      cwts.append((w.gen_num, contracts[cntrct_idx], w.weighting, 
         timestamp)) 
    return cwts 

folgt Aber ich empfange Laufzeitfehler, von denen ich glaube, dass sie mit der char[5] position zusammenhängen.

import pyximport 
pyximport.install() 
import struct_test 

struct_test.cloop(weights, contracts, ts) 

ValueError: Does not understand character buffer dtype format string ('w') 

Außerdem bin ich ein wenig unklar, wie ich über die Eingabe contracts auch als timestamp gehen würde.

+0

Meine begrenzte Erfahrung ist, dass Verbindung Dtype und Strings sind hart in 'Cython' zu verwenden und bieten begrenzte Geschwindigkeit Verbesserung. Aber auf den ersten Blick sieht es so aus, als könnte Ihr "Ploop" mit "numpy" Array-Methoden geschrieben werden, die auf allen "Gewichten" gleichzeitig funktionieren. Ich werde das später versuchen. – hpaulj

+1

Ich denke, Sie verwenden Python3, und es interpretiert 'np.str_' als Unicode. Wenn Sie stattdessen "np.bytes_" verwenden, funktioniert eine vereinfachte Version Ihres Codes für mich. (Ich schreibe das nicht als Antwort, da ich nicht wirklich auf den zweiten Teil Ihrer Frage zu Verträgen und Zeitstempel eingehen möchte) – DavidW

Antwort

1

Ihre ploop (ohne timestamp Variable) erzeugt:

In [226]: ploop(weights, contracts) 
Out[226]: [(0, 'CLX16', 0.5), (0, 'CLZ16', 0.5), (1, 'CLZ16', 1.0)] 

Equivalent Funktion ohne Schleife:

def ploopless(weights, contracts): 
    arr_contracts = np.array(contracts) # to allow array indexing 
    wgts1 = weights[weights['c']!=0] 
    mask = wgts1['b']=='front' 
    wgts1['b'][mask] = arr_contracts[wgts1['a'][mask]] 
    mask = wgts1['b']=='back' 
    wgts1['b'][mask] = arr_contracts[wgts1['a'][mask]+1] 
    return wgts1.tolist() 

In [250]: ploopless(weights, contracts) 
Out[250]: [(0, 'CLX16', 0.5), (0, 'CLZ16', 0.5), (1, 'CLZ16', 1.0)] 

ich die Tatsache zunutze, nehme mir die Liste von Tupeln zurück gleiche hat (int, str, int) Layout als Eingabe weight Array. Ich mache also nur eine Kopie von weights und ersetze ausgewählte Werte des Feldes b.

Beachten Sie, dass ich den Feldauswahlindex vor dem mask einen. Der boolesche Wert mask erzeugt eine Kopie, daher müssen wir bei der Indexreihenfolge vorsichtig sein.

Ich vermute, dass loop-less-Array-Version im Wettbewerb mit der cloop (auf realistischen Arrays) konkurrieren wird. Die Zeichenfolgen- und Listenoperationen in cloop begrenzen wahrscheinlich ihre Beschleunigung.