1
votes

Opération de jointure de chaîne dans les objets python numpy ou pandas

Je veux joindre des colonnes de type string, dans un dataframe pandas ou numupy ndarray, dans une dernière colonne comme celle-ci:

# Compose data
a = ['a','b','c']
b = ['d','e','f']
c = ['g','h','i']

pdf = pd.DataFrame([a,b,c], columns=['a','b','c'])


# One option
%%timeit
pdf.loc[:,'d'] = [i for i in map(lambda x: '_'.join([x.a, x.b, x.c]), pdf.itertuples())]
>>>1.08 ms ± 4.11 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

# Another option
%%timeit
tmp=[]
for i in pdf.itertuples():
    tmp.append('_'.join([i.a, i.b, i.c]))

pdf.loc[:,'d'] = tmp
>>>1.08 ms ± 5.54 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
 

Je peux penser à deux options représentatives:

        a   b   c                          a   b   c   d
        ----------         --->            ---------------
        a   b   c                          a   b   c   a_b_c             
        d   e   f                          d   e   f   d_e_f
        g   h   i                          g   h   i   g_h_i

Je comprends qu'il y ait peut-être trop peu de données pour voir une différence entre ces méthodes, mais ma question est: existe-t-il une méthode plus intelligente intégrée à numpy ou pandas que je peux appeler? De plus, y a-t-il un problème avec l'une des deux méthodes auxquelles j'ai pensé?

Merci!


1 commentaires

D'après mon expérience et mes connaissances ... les pandas utilisant numpy en dessous, par conséquent, les pandas ajoutent des frais généraux aux opérations. Presque toutes les opérations sont plus rapides en utilisant directement numpy vs pandas.


3 Réponses :


4
votes

Vous pouvez essayer ces 2 ci-dessous, sans avoir à utiliser de boucles:

df['combined'] = df[['a', 'b', 'c']].agg('_'.join, axis=1)

   a  b  c combined
0  a  b  c    a_b_c
1  d  e  f    d_e_f
2  g  h  i    g_h_i

ou:

df['combined'] = df['a'] + '_' + df['b'] + '_' + df['c']


2 commentaires

Le premier semble bon, mais le dernier (agg) est très peu performant.


Conversion explicite en tableaux numpy (c'est-à-dire pdf ['a']. To_numpy () + '_' + pdf ['b']. To_numpy () + '_' + pdf ['c']. To_numpy () ) donnera de meilleures performances de temps (dans ma machine locale, c'est 20 fois plus rapide)



0
votes

Compte tenu des données que vous fournissez et du peu de colonnes avec lesquelles vous travaillez, vous trouverez peut-être [plus facile (mais pas évolutif) d'utiliser simplement l'opérateur + pour les colonnes que vous souhaitez joindre:

Method 1:  0.041734933853149414
Method 2:  0.04217410087585449
Method 3:  0.011157751083374023

Ce n'est pas évolutif si vous avez 200 colonnes, mais c'est certainement plus rapide que les deux autres méthodes que vous proposez. En l'utilisant dans un dataframe de 30000 lignes, j'obtiens les résultats temporels suivants:

a = ['a','b','c']
b = ['d','e','f']
c = ['g','h','i']

pdf = pd.DataFrame([a,b,c]*10000, columns=['a','b','c'])

Et voici les résultats temporels:

pdf['d'] = pdf['a'] + '_' + pdf['b'] + '_' + pdf['c']

Où les méthodes 1 et 2 sont celles proposées et la troisième est celle ci-dessus.


0 commentaires

1
votes

Je voudrais lancer une autre option:

# Compose data
a = ['a','b','c']
b = ['d','e','f']
c = ['g','h','i']

pdf = pd.DataFrame([a,b,c], columns=['a','b','c'])



def met_add(d):
    return df['a'] + '_' + df['b'] + '_' + df['c']

def met_agg_axis1(d):
    return  df[['a', 'b', 'c']].agg('_'.join, axis=1)

def met_str_cat(d):
    return pdf['a'].str.cat([pdf['b'], pdf['c']], sep='_')

def met_map_join(d):
    return pd.Series( [i for i in map(lambda x: '_'.join([x.a, x.b, x.c]), pdf.itertuples())])

def met_iter_join(d):
    tmp=[]
    for i in pdf.itertuples():
        tmp.append('_'.join([i.a, i.b, i.c]))
    return pd.Series(tmp)    

def met_numpy_add(d):
    return pd.Series(pdf['a'].to_numpy() + '_' + pdf['b'].to_numpy() + '_' + pdf['c'].to_numpy())

res = pd.DataFrame(
    index=[10, 30, 100, 300,1000, 3000, 10000, 30000, 100000, 300000],
    columns='met_add met_agg_axis1 met_str_cat met_map_join met_iter_join met_numpy_add'.split(),
    dtype=float
)

for i in res.index:
    d = pd.concat([pdf]*i).add_prefix('col')
    for j in res.columns:
        print(d.shape)
        stmt = '{}(d)'.format(j)
        setp = 'from __main__ import d, {}'.format(j)
        res.at[i, j] = timeit(stmt, setp, number=100)

res.plot(loglog=True, figsize=(10,8));

Sortie:

0    a_b_c
1    d_e_f
2    g_h_i
Name: a, dtype: object

Timings

pdf['a'].str.cat([pdf['b'], pdf['c']], sep='_')

Résultat du graphique:

entrez la description de l'image ici


0 commentaires