J'ai une trame de données comme celle-ci:

>>> df1
                         overall
0  class1-10/class2-11/class3-13
1  class3-31/class2-22/class1-23
2                abc/def/xyz/prq

Je veux calculer 3 colonnes class1, class2 et class3 si elles se trouvent dans 'global'. o / p souhaité

          overall                 class1  class2  class3
0  class1-10/class2-11/class3-13    10    11      13
1  class3-31/class2-22/class1-23    23    22      32
2                abc/def/xyz/prq     NaN  NaN     NaN

Comment cela peut-il être fait de manière pythonienne? Merci

4
Bharat Sharma 23 mai 2018 à 13:04

3 réponses

Meilleure réponse

Une façon sans regex est d'utiliser try / except:

def splitter(x):
    try:
        return [int(i.split('-')[1]) for i in sorted(x.split('/'))]
    except IndexError:
        return [np.nan] * 3

df[['class1', 'class2', 'class3']] = df['overall'].apply(splitter).apply(pd.Series)

print(df)

                         overall  class1  class2  class3
0  class1-10/class2-11/class3-13    10.0    11.0    13.0
1  class3-31/class2-22/class1-23    23.0    22.0    31.0
2                abc/def/xyz/prq     NaN     NaN     NaN
1
jpp 23 mai 2018 à 10:51

Utilisation -

def split_cols(x):
    for item in x['overall'].split('/'):
        if item.startswith('class'):
            pairs = item.split('-')
            x[pairs[0]] = pairs[1]
    return x
df.apply(split_cols, axis=1)

Sortie

    class1  class2  class3  overall
0   10  11  13  class1-10/class2-11/class3-13
1   23  22  31  class3-31/class2-22/class1-23
2   NaN NaN NaN abc/def/xyz/prq

Explication

La fonction split_cols() s'occupe de créer les colonnes supplémentaires.

Il se divise d'abord par /, vérifie la présence de class dans les divisions

Il se divise ensuite à nouveau avec -, crée une colonne avec le premier fractionnement et la valeur de cette colonne comme deuxième fractionnement.

Le tout est ensuite mis à travers la fonction apply

1
Vivek Kalyanarangan 23 mai 2018 à 10:46

Il peut être tentant d'utiliser str.extract mais il ne correspond qu'à la première correspondance selon les documents. D'un autre côté, str.extractall génère une trame de données un peu trop complexe pour fonctionner. Nous recourrons à df.apply.

import re

regex = re.compile(r'(class\d+)-(\d+)')

def func(x):
    data = regex.findall(x[0])
    for class_name, value in data:
        df.loc[x.name, class_name] = value

df.apply(func, axis=1)
print(df)

#                           overall class1 class2 class3
#  0  class1-10/class2-11/class3-13     10     11     13
#  1  class3-31/class2-22/class1-23     23     22     31
#  2                abc/def/xyz/prq    NaN    NaN    NaN
3
DeepSpace 23 mai 2018 à 11:03