2017-10-13 4 views
1

Je suis nouveau pour les pandas. J'ai écrit un code que je voudrais optimiser, mais je ne sais pas comment. Je suis conscient du fait que la vectorisation des 'apply' et des pandas est plus rapide que celle des 'iterrows', mais je ne sais pas comment les utiliser pour atteindre le même but. Iterrows est facile pour moi car c'est similaire à la boucle 'for', donc je suis habitué. Voici mon code:optimiser le code pandas: remplacer 'iterrows' et d'autres idées

import numpy as np 
import pandas as pd 
import matplotlib.pyplot as plt 
from sklearn.metrics import mean_squared_error 
from scipy.spatial.distance import euclidean 
data = pd.read_csv(r'C:\temp\train.txt') 

def group_df(df,num): 
    ln = len(df) 
    rang = np.arange(ln) 
    splt = np.array_split(rang,num) 
    lst = [] 
    finel_lst = [] 
    for i,x in enumerate(splt): 
     lst.append([i for x in range(len(x))]) 
    for k in lst: 
     for j in k: 
      finel_lst.append(j) 
    df['group'] = finel_lst 
    return df 
def KNN(dafra,folds,K,fi,target):   
    df = group_df(dafra,folds) 
    avarge_e = [] 
    for i in range(folds): 
     train = pd.DataFrame(df.loc[df['group'] != i]) 
     test = pd.DataFrame(df.loc[df['group'] == i]) 
     test.loc[:,'pred_price'] = np.nan 
     test.loc[:,'rmse'] = np.nan 
     train.loc[:,'dis'] = np.nan 
     train = train.reset_index() 
     test = test.reset_index() 
     for index,row in test.iterrows(): 
      for index2,row2 in train.iterrows(): 
       train.loc[index2]['dis'] = euclidean(row2[fi],row[fi]) 

Comme vous pouvez le voir, il y a 2 boucles imbriquées 'iterrows'. il y a aussi 1 petite boucle 'for' en haut. L'idée de ce code est d'assigner la distance euclidienne entre chaque ligne de test à chaque ligne de train. Mais, puisque le test est modifié par la boucle 'for', il finira par s'ajouter à l'ensemble du DataFrame original.

Voici beggining des données:

Id MSSubClass MSZoning LotFrontage LotArea Street Alley LotShape \ 
0 1   60  RL   65.0  8450 Pave NaN  Reg 
1 2   20  RL   80.0  9600 Pave NaN  Reg 
2 3   60  RL   68.0 11250 Pave NaN  IR1 

    LandContour Utilities ...  PoolArea PoolQC Fence MiscFeature MiscVal 
\ 
0   Lvl AllPub ...   0 NaN NaN   NaN  0 

1   Lvl AllPub ...   0 NaN NaN   NaN  0 

2   Lvl AllPub ...   0 NaN NaN   NaN  0 

    MoSold YrSold SaleType SaleCondition SalePrice 
0  2 2008  WD   Normal  208500 
1  5 2007  WD   Normal  181500 
2  9 2008  WD   Normal  223500 

[3 lignes x 81 colonnes]

Toutes les idées pour optimaing ce code seront les bienvenus. Je vous remercie.

+0

Pouvez-vous fournir des données de test ? –

+0

Voulez-vous dire: les premières lignes fue de mon DataFrame? –

+0

Oui, et ce que vous souhaitez archiver –

Répondre

0

Je suggère deux solutions possibles à votre problème:

scipys -Utiliser distance_matrix

-Rédaction votre propre fonction numpy

La solution est scipy avant droite:

import scipy 
import numpy as np 

point_vector_1 = np.random.random((10000,2)) 
point_vector_2 = np.random.random((1000,2)) 
distance_matrix = scipy.spatial.distance_matrix(point_vector_1, point_vector_2) 

En numpy nous pouvons utiliser l'ufunc externe pour coder notre propre fonction. np.subtract.outer donnera comme matrice de deux vecteurs similaires au produit scalaire externe donnerait comme multiplication.

def euclidean_distance_matrix(vector_1, vector_2): 
    dis_dim_1 = np.subtract.outer(vector_1.T[0], vector_2.T[0])**2 
    dis_dim_2 = np.subtract.outer(vector_1.T[1], vector_2.T[1])**2 
    euclidean = np.sqrt(dis_dim_1+dis_dim_2) 
    return euclidean 

distance_matrix_2 = euclidean_distance_matrix(point_vector_1, point_vector_2) 

synchronisations:

%timeit scipy.spatial.distance_matrix(point_vector_1, point_vector_2) 
382 ms ± 8.56 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) 
%timeit euclidean_distance_matrix(point_vector_1, point_vector_2) 
150 ms ± 1.33 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) 

Edit: Pour garder l'index d'origine, vous pouvez passer dans l'index de la source df à la nouvelle dataframe:

dist_array = euclidean_distance_matrix([df1['lat'], df1['long']], [df2['lat'], df2['long']]) 
df_dist = pd.DataFrame(dist_array, index=df1.index, columns=df2.index) 
+0

Nous vous remercions de votre suggestion. C'est une bonne solution. execpt que l'écriture de ma propre fonction perd l'index et les lables du DataFrame, donc je ne peux pas dire quel vecteur dans la nouvelle matrice était quelle colonne ou ligne dans les vecteurs d'origine. Y a-t-il un moyen de l'empêcher? –