121 votes

Concaténation de chaînes de caractères de deux colonnes pandas

J'ai les éléments suivants DataFrame :

from pandas import *
df = DataFrame({'foo':['a','b','c'], 'bar':[1, 2, 3]})

Ça ressemble à ça :

    bar foo
0    1   a
1    2   b
2    3   c

Maintenant, je veux avoir quelque chose comme :

     bar
0    1 is a
1    2 is b
2    3 is c

Comment puis-je y parvenir ? J'ai essayé ce qui suit :

df['foo'] = '%s is %s' % (df['bar'], df['foo'])

mais cela me donne un résultat erroné :

>>>print df.ix[0]

bar                                                    a
foo    0    a
1    b
2    c
Name: bar is 0    1
1    2
2
Name: 0

Désolé pour la question stupide, mais celle-ci pandas : combiner deux colonnes dans un DataFrame n'a pas été utile pour moi.

157voto

BrenBarn Points 63718
df['bar'] = df.bar.map(str) + " is " + df.foo

127voto

coldspeed Points 111053

Cette question a déjà reçu une réponse, mais je pense qu'il serait bon d'ajouter quelques méthodes utiles qui n'ont pas encore été abordées, et de comparer toutes les méthodes proposées jusqu'à présent en termes de performances.

Voici quelques solutions utiles à ce problème, par ordre croissant de performance.


DataFrame.agg

Il s'agit d'un simple str.format -L'approche est basée sur l'expérience.

df['baz'] = df.agg('{0[bar]} is {0[foo]}'.format, axis=1)
df
  foo  bar     baz
0   a    1  1 is a
1   b    2  2 is b
2   c    3  3 is c

Vous pouvez également utiliser le formatage f-string ici :

df['baz'] = df.agg(lambda x: f"{x['bar']} is {x['foo']}", axis=1)
df
  foo  bar     baz
0   a    1  1 is a
1   b    2  2 is b
2   c    3  3 is c

char.array -Concaténation à base de

Convertir les colonnes à concaténer comme chararrays puis ajoutez-les ensemble.

a = np.char.array(df['bar'].values)
b = np.char.array(df['foo'].values)

df['baz'] = (a + b' is ' + b).astype(str)
df
  foo  bar     baz
0   a    1  1 is a
1   b    2  2 is b
2   c    3  3 is c

Compréhension des listes con zip

Je ne saurais trop insister sur le fait que les compréhensions de listes sont sous-estimées dans les pandas.

df['baz'] = [str(x) + ' is ' + y for x, y in zip(df['bar'], df['foo'])]

On peut aussi utiliser str.join pour concaténer (ce qui permettra également une meilleure mise à l'échelle) :

df['baz'] = [
    ' '.join([str(x), 'is', y]) for x, y in zip(df['bar'], df['foo'])]

df
  foo  bar     baz
0   a    1  1 is a
1   b    2  2 is b
2   c    3  3 is c

Les compréhensions de listes excellent dans la manipulation des chaînes de caractères, car les opérations sur les chaînes de caractères sont par nature difficiles à vectoriser, et la plupart des fonctions "vectorisées" de pandas sont essentiellement des enveloppes autour des boucles. J'ai beaucoup écrit sur ce sujet dans Boucles For avec les pandas - Quand faut-il s'en préoccuper ? . En général, si vous n'avez pas à vous soucier de l'alignement de l'index, utilisez une compréhension de liste pour les opérations sur les chaînes de caractères et les regex.

La liste comp ci-dessus par défaut ne gère pas les NaNs. Cependant, vous pouvez toujours écrire une fonction enveloppant un try-except si vous avez besoin de les gérer.

def try_concat(x, y):
    try:
        return str(x) + ' is ' + y
    except (ValueError, TypeError):
        return np.nan

df['baz'] = [try_concat(x, y) for x, y in zip(df['bar'], df['foo'])]

perfplot Mesures de la performance

enter image description here

Graphique généré à l'aide de perfplot . Voici le liste complète des codes .

Fonctions

def brenbarn(df):
    return df.assign(baz=df.bar.map(str) + " is " + df.foo)

def danielvelkov(df):
    return df.assign(baz=df.apply(
        lambda x:'%s is %s' % (x['bar'],x['foo']),axis=1))

def chrimuelle(df):
    return df.assign(
        baz=df['bar'].astype(str).str.cat(df['foo'].values, sep=' is '))

def vladimiryashin(df):
    return df.assign(baz=df.astype(str).apply(lambda x: ' is '.join(x), axis=1))

def erickfis(df):
    return df.assign(
        baz=df.apply(lambda x: f"{x['bar']} is {x['foo']}", axis=1))

def cs1_format(df):
    return df.assign(baz=df.agg('{0[bar]} is {0[foo]}'.format, axis=1))

def cs1_fstrings(df):
    return df.assign(baz=df.agg(lambda x: f"{x['bar']} is {x['foo']}", axis=1))

def cs2(df):
    a = np.char.array(df['bar'].values)
    b = np.char.array(df['foo'].values)

    return df.assign(baz=(a + b' is ' + b).astype(str))

def cs3(df):
    return df.assign(
        baz=[str(x) + ' is ' + y for x, y in zip(df['bar'], df['foo'])])

45voto

Daniel Velkov Points 9244

Le problème dans votre code est que vous voulez appliquer l'opération sur chaque ligne. La façon dont vous l'avez écrit prend toutes les colonnes 'bar' et 'foo', les convertit en chaînes de caractères et vous rend une seule grande chaîne. Vous pouvez l'écrire comme suit :

df.apply(lambda x:'%s is %s' % (x['bar'],x['foo']),axis=1)

Elle est plus longue que l'autre réponse mais est plus générique (peut être utilisée avec des valeurs qui ne sont pas des chaînes de caractères).

13voto

chrimuelle Points 26

Vous pouvez également utiliser

df['bar'] = df['bar'].str.cat(df['foo'].values.astype(str), sep=' is ')

11voto

Vladimir Yashin Points 334
df.astype(str).apply(lambda x: ' is '.join(x), axis=1)

0    1 is a
1    2 is b
2    3 is c
dtype: object

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X