Je dispose d'un grand fichier CSV rempli de données relatives aux actions et formaté comme tel :
Symbole du téléscripteur, date, [quelques variables...].
Chaque ligne commence donc par le symbole (comme "AMZN"), puis la date, et enfin 12 variables liées au prix ou au volume à la date sélectionnée. Il y a environ 10 000 titres différents représentés dans ce fichier et j'ai une ligne pour chaque jour où l'action a été échangée publiquement pour chacun d'entre eux. Le fichier est d'abord classé par ordre alphabétique de symbole de téléscripteur, puis par ordre chronologique de date. L'ensemble du fichier pèse environ 3,3 Go.
Le type de tâche que je veux résoudre serait d'être capable d'extraire le plus récent n lignes de données pour un symbole de téléscripteur donné par rapport à la date actuelle. J'ai du code qui fait cela, mais d'après mes observations, cela semble prendre, en moyenne, environ 8-10 secondes par extraction (tous les tests ont extrait 100 lignes).
J'ai des fonctions que j'aimerais exécuter et qui me demandent de saisir de tels morceaux pour des centaines ou des milliers de symboles, et j'aimerais vraiment réduire ce temps. Mon code est inefficace, mais je ne sais pas comment le rendre plus rapide.
D'abord, j'ai une fonction appelée getData :
def getData(symbol, filename):
out = ["Symbol","Date","Open","High","Low","Close","Volume","Dividend",
"Split","Adj_Open","Adj_High","Adj_Low","Adj_Close","Adj_Volume"]
l = len(symbol)
beforeMatch = True
with open(filename, 'r') as f:
for line in f:
match = checkMatch(symbol, l, line)
if beforeMatch and match:
beforeMatch = False
out.append(formatLineData(line[:-1].split(",")))
elif not beforeMatch and match:
out.append(formatLineData(line[:-1].split(",")))
elif not beforeMatch and not match:
break
return out
(Ce code comporte quelques fonctions d'aide, checkMatch et formatLineData, que je montrerai ci-dessous). Ensuite, il y a une autre fonction appelée getDataColumn qui obtient la colonne que je veux avec le nombre correct de jours représentés :
def getDataColumn(symbol, col=12, numDays=100, changeRateTransform=False):
dataset = getData(symbol)
if not changeRateTransform:
column = [day[col] for day in dataset[-numDays:]]
else:
n = len(dataset)
column = [(dataset[i][col] - dataset[i-1][col])/dataset[i-1][col] for i in range(n - numDays, n)]
return column
(changeRateTransform convertit les nombres bruts en nombres de taux de changement quotidien si c'est vrai). Les fonctions d'aide :
def checkMatch(symbol, symbolLength, line):
out = False
if line[:symbolLength+1] == symbol + ",":
out = True
return out
def formatLineData(lineData):
out = [lineData[0]]
out.append(datetime.strptime(lineData[1], '%Y-%m-%d').date())
out += [float(d) for d in lineData[2:6]]
out += [int(float(d)) for d in lineData[6:9]]
out += [float(d) for d in lineData[9:13]]
out.append(int(float(lineData[13])))
return out
Quelqu'un a-t-il une idée des parties de mon code qui sont lentes et de la façon dont je peux améliorer les performances ? Je ne peux pas faire le genre d'analyse que je veux faire sans accélérer le processus.
EDIT : En réponse aux commentaires, j'ai apporté quelques modifications au code afin d'utiliser les méthodes existantes dans le module csv :
def getData(symbol, database):
out = ["Symbol","Date","Open","High","Low","Close","Volume","Dividend",
"Split","Adj_Open","Adj_High","Adj_Low","Adj_Close","Adj_Volume"]
l = len(symbol)
beforeMatch = True
with open(database, 'r') as f:
databaseReader = csv.reader(f, delimiter=",")
for row in databaseReader:
match = (row[0] == symbol)
if beforeMatch and match:
beforeMatch = False
out.append(formatLineData(row))
elif not beforeMatch and match:
out.append(formatLineData(row))
elif not beforeMatch and not match:
break
return out
def getDataColumn(dataset, col=12, numDays=100, changeRateTransform=False):
if not changeRateTransform:
out = [day[col] for day in dataset[-numDays:]]
else:
n = len(dataset)
out = [(dataset[i][col] - dataset[i-1][col])/dataset[i-1][col] for i in range(n - numDays, n)]
return out
Les performances étaient moins bonnes en utilisant la classe csv.reader. J'ai testé sur deux actions, AMZN (en haut du fichier) et ZNGA (en bas du fichier). Avec la méthode originale, les temps d'exécution étaient de 0,99 seconde et 18,37 secondes, respectivement. Avec la nouvelle méthode utilisant le module csv, les temps d'exécution étaient respectivement de 3,04 secondes et 64,94 secondes. Les deux méthodes donnent des résultats corrects.
Je pense que le temps est davantage consacré à la recherche du stock qu'à l'analyse. Si j'essaie ces méthodes sur la première action du fichier, A, les deux méthodes s'exécutent en 0,12 seconde environ.