1
votes

Concaténer les valeurs de colonne dans un DataFrame pandas tout en ignorant les NaN

J'ai le tableau pandas suivant

df:

df['new_column'] = df[~df.EVNT_ID].apply(lambda x: '|'.join(x.dropna().astype(str).values), axis=1)

Maintenant, j'essaye de concater toutes les colonnes sauf la première colonne et je veux que mon bloc de données regardez de la manière suivante

new_df:

 EVNT_ID col1 col2 col3 col4 new_col
 123454   1    Nan   4    5   1|4|5
 628392   Nan   3   Nan   7    3|7
 293899   2    Nan  Nan   6    2|6
 127820   9    11    12   19  9|11|12|19

J'utilise le code suivant

 EVNT_ID col1 col2 col3 col4
 123454   1    Nan   4    5
 628392   Nan   3   Nan   7
 293899   2    Nan  Nan   6
 127820   9    11    12   19

mais cela me donne l'erreur suivante

ufunc 'invert' non pris en charge pour les types d'entrée, et les entrées ne peuvent pas être forcées en toute sécurité à des types pris en charge selon la règle de conversion '' safe '' '

J'apprécierais vraiment que quelqu'un puisse me dire où je me trompe. J'apprécierais vraiment cela.


0 commentaires

3 Réponses :


1
votes

Vous pouvez le faire avec filter et agg:

df = pd.concat([df] * 1000, ignore_index=True)

# In this post.
%%timeit
[
     '|'.join([str(int(x)) for x in r if pd.notna(x)]) 
     for r in df.iloc[:,1:].values.tolist()
]
# RafaelC's answer.
%%timeit
[
    '|'.join([k for k in a if k])
    for a in zip(*df.fillna('').astype(str).iloc[:, 1:].values.tolist())
]    

31.9 ms ± 800 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
23.7 ms ± 409 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

Ou,

joined = [
    '|'.join([str(int(x)) for x in r if pd.notna(x)]) 
    for r in df.iloc[:,1:].values.tolist()
]
joined
# ['1|4|5', '3|7', '2|6', '9|11|12|19']

df.assign(new_col=joined)   

   EVNT_ID  col1  col2  col3  col4     new_col
0   123454   1.0   NaN   4.0     5       1|4|5
1   628392   NaN   3.0   NaN     7         3|7
2   293899   2.0   NaN   NaN     6         2|6
3   127820   9.0  11.0  12.0    19  9|11|12|19


0 commentaires

1
votes

Utilisation de la compréhension de liste et de zip

df = pd.concat([df]*1000)

%timeit [['|'.join([k for k in a if k])] for a in zip(*df.fillna('').astype(str).iloc[:, 1:].values)]
10.8 ms ± 568 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit df.filter(like='col').agg(lambda x: x.dropna().astype(int).astype(str).str.cat(sep='|'), axis=1)
1.68 s ± 91.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit df.iloc[:, 1:].apply(lambda x: '|'.join(str(el) for el in x if str(el) != 'nan'), axis=1)
87.8 ms ± 5.01 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit df.assign(new_col=['|'.join([str(int(x)) for x in r if ~np.isnan(x)]) for r in df.iloc[:,1:].values])
45.1 ms ± 1.38 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

Le timing semble correct

>>> [['|'.join([k for k in a if k])] for a in zip(*df.fillna('').astype(str).iloc[:, 1:].values)]


6 commentaires

Merci pour les horaires! Bien que ce ne soit pas une comparaison particulièrement juste à moins que la première composition de liste ne soit également attribuée, car cela entraîne une surcharge.


C'est vrai, mais n'ajoutera probablement pas beaucoup de frais généraux;)


Il suffit de faire la différence! J'ai également reflété vos horaires dans ma réponse.


Oui. vu ça. Merci pour les contributions! :}


Nos réponses ne sont pas non plus identiques. Votre code produit des flottants: ['1.0 | 2.0 | 9.0', '3.0 | 11.0', '4.0 | 12.0', '5 | 7 | 6 | 19']


@coldspeed Je vois, je dois str (int (float (k))) ou quelque chose dans la boucle! Nous aurons le même temps, je crois:



2
votes

Essayez le code suivant:

df['new_col'] = df.iloc[:, 1:].apply(lambda x:
    '|'.join(str(el) for el in x if str(el) != 'nan'), axis=1)

Au départ, j'ai pensé à x.dropna () au lieu de x if str (el)! = 'nan ', mais % timeit a montré que dropna () fonctionne beaucoup plus lentement.


0 commentaires