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.

6voto

johnDanger Points 725

series.str.cat est la manière la plus souple d'aborder ce problème :

Pour df = pd.DataFrame({'foo':['a','b','c'], 'bar':[1, 2, 3]})

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

>>>  0    a is 1
     1    b is 2
     2    c is 3
     Name: foo, dtype: object

OU

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

>>>  0    1 is a
     1    2 is b
     2    3 is c
     Name: bar, dtype: object

Contrairement à .join() (qui permet de joindre des listes contenues dans une seule série), cette méthode permet de joindre 2 séries ensemble. Elle vous permet également d'ignorer ou de remplacer NaN comme vous le souhaitez.

4voto

erickfis Points 162

La réponse de @DanielVelkov est la bonne MAIS l'utilisation des chaînes littérales est plus rapide :

# Daniel's
%timeit df.apply(lambda x:'%s is %s' % (x['bar'],x['foo']),axis=1)
## 963 µs ± 157 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

# String literals - python 3
%timeit df.apply(lambda x: f"{x['bar']} is {x['foo']}", axis=1)
## 849 µs ± 4.28 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

0voto

robin girard Points 207

J'ai rencontré un cas spécifique de mon côté avec 10^11 lignes dans mon cadre de données, et dans ce cas aucune des solutions proposées n'est appropriée. J'ai utilisé des catégories, et cela devrait fonctionner correctement dans tous les cas où le nombre de chaînes uniques n'est pas trop grand. Ceci est facilement réalisable dans le logiciel R avec XxY avec des facteurs mais je n'ai pas trouvé d'autre moyen de le faire en python (je suis nouveau en python). Si quelqu'un connaît un endroit où cela est implémenté, je serais heureux de le savoir.

def Create_Interaction_var(df,Varnames):
    '''
    :df data frame
    :list of 2 column names, say "X" and "Y". 
    The two columns should be strings or categories
    convert strings columns to categories
    Add a column with the "interaction of X and Y" : X x Y, with name 
    "Interaction-X_Y"
    '''
    df.loc[:, Varnames[0]] = df.loc[:, Varnames[0]].astype("category")
    df.loc[:, Varnames[1]] = df.loc[:, Varnames[1]].astype("category")
    CatVar = "Interaction-" + "-".join(Varnames)
    Var0Levels = pd.DataFrame(enumerate(df.loc[:,Varnames[0]].cat.categories)).rename(columns={0 : "code0",1 : "name0"})
    Var1Levels = pd.DataFrame(enumerate(df.loc[:,Varnames[1]].cat.categories)).rename(columns={0 : "code1",1 : "name1"})
    NbLevels=len(Var0Levels)

    names = pd.DataFrame(list(itertools.product(dict(enumerate(df.loc[:,Varnames[0]].cat.categories)),
                                                dict(enumerate(df.loc[:,Varnames[1]].cat.categories)))),
                         columns=['code0', 'code1']).merge(Var0Levels,on="code0").merge(Var1Levels,on="code1")
    names=names.assign(Interaction=[str(x) + '_' + y for x, y in zip(names["name0"], names["name1"])])
    names["code01"]=names["code0"] + NbLevels*names["code1"]
    df.loc[:,CatVar]=df.loc[:,Varnames[0]].cat.codes+NbLevels*df.loc[:,Varnames[1]].cat.codes
    df.loc[:, CatVar]=  df[[CatVar]].replace(names.set_index("code01")[["Interaction"]].to_dict()['Interaction'])[CatVar]
    df.loc[:, CatVar] = df.loc[:, CatVar].astype("category")
    return df

0voto

1'' Points 5044

Je pense que la solution la plus concise pour un nombre arbitraire de colonnes est une version abrégée de cette réponse :

df.astype(str).apply(' is '.join, axis=1)

Vous pouvez réduire de deux caractères supplémentaires avec df.agg() mais c'est plus lent :

df.astype(str).agg(' is '.join, axis=1)

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