L'API DataFrame de PyODPS prend en charge un large éventail d'opérations sur les colonnes, notamment la gestion des valeurs nulles, la logique conditionnelle, les calculs mathématiques, le traitement des chaînes, les dates et heures, les collections et les fonctions personnalisées. Les opérations appliquées à une séquence sont exécutées élément par élément sur chaque valeur de la colonne.
Prérequis
Avant d'exécuter les exemples, initialisez les jeux de données :
from odps.df import DataFrame
iris = DataFrame(o.get_table('pyodps_iris'))
lens = DataFrame(o.get_table('pyodps_ml_100k_lens'))
Fonctions liées aux valeurs nulles
Trois fonctions intégrées permettent de gérer les valeurs nulles : isnull, notnull et fillna.
isnull— renvoieTruesi la valeur du champ est nulle.notnull— renvoieTruesi la valeur du champ n'est pas nulle.fillna— remplace les valeurs nulles par les valeurs spécifiées.
>>> iris.sepallength.isnull().head(5)
sepallength
0 False
1 False
2 False
3 False
4 False
Fonctions logiques
ifelse
La fonction ifelse s'applique aux champs booléens. Lorsque la condition est True, elle renvoie le premier argument ; sinon, elle renvoie le second.
>>> (iris.sepallength > 5).ifelse('gt5', 'lte5').rename('cmp5').head(5)
cmp5
0 gt5
1 lte5
2 lte5
3 lte5
4 lte5
switch
La fonction switch gère plusieurs conditions en comparant chaque valeur à une série de paires condition-résultat, puis renvoie le résultat correspondant. Utilisez le paramètre default pour spécifier la valeur de secours lorsqu'aucune condition ne correspond.
>>> iris.sepallength.switch(4.9, 'eq4.9', 5.0, 'eq5.0', default='noeq').rename('equalness').head(5)
equalness
0 noeq
1 eq4.9
2 noeq
3 noeq
4 eq5.0
Importez switch depuis odps.df pour l'utiliser en tant que fonction autonome sur plusieurs colonnes :
>>> from odps.df import switch
>>> switch(iris.sepallength == 4.9, 'eq4.9', # condition 1: exact match 4.9
... iris.sepallength == 5.0, 'eq5.0', # condition 2: exact match 5.0
... default='noeq').rename('equalness').head(5)
equalness
0 noeq
1 eq4.9
2 noeq
3 noeq
4 eq5.0
Affectation conditionnelle (PyODPS V0.7.8 et versions ultérieures)
Modifiez les valeurs des colonnes selon des conditions à l'aide de la syntaxe d'affectation :
>>> iris[iris.sepallength > 5, 'cmp5'] = 'gt5' # set 'gt5' where sepallength > 5
>>> iris[iris.sepallength <= 5, 'cmp5'] = 'lte5' # set 'lte5' where sepallength <= 5
>>> iris.head(5)
cmp5
0 gt5
1 lte5
2 lte5
3 lte5
4 lte5
Opérations mathématiques
Les séquences numériques prennent en charge les opérateurs arithmétiques standard (+, -, *, /) ainsi qu'un ensemble de fonctions mathématiques.
>>> (iris.sepallength * 10).log().head(5)
sepallength
0 3.931826
1 3.891820
2 3.850148
3 3.828641
4 3.912023
>>> fields = [
... iris.sepallength,
... (iris.sepallength / 2).rename('sepallength divided by 2'),
... (iris.sepallength ** 2).rename('sepallength squared'),
... ]
>>> iris[fields].head(5)
sepallength sepallength divided by 2 sepallength squared
0 5.1 2.55 26.01
1 4.9 2.45 24.01
2 4.7 2.35 22.09
3 4.6 2.30 21.16
4 5.0 2.50 25.00
Le tableau suivant répertorie toutes les fonctions mathématiques prises en charge.
|
Fonction |
Description |
|
|
Renvoie la valeur absolue. |
|
|
Renvoie la racine carrée. |
|
|
Renvoie le sinus. |
|
|
Renvoie le sinus hyperbolique. |
|
|
Renvoie le cosinus. |
|
|
Renvoie le cosinus hyperbolique. |
|
|
Renvoie la tangente. |
|
|
Renvoie la tangente hyperbolique. |
|
|
Renvoie l'arc cosinus. |
|
|
Renvoie le cosinus hyperbolique inverse. |
|
|
Renvoie l'arc sinus. |
|
|
Renvoie le sinus hyperbolique inverse. |
|
|
Renvoie l'arc tangente. |
|
|
Renvoie la tangente hyperbolique inverse. |
|
|
Renvoie e élevé à la puissance indiquée. |
|
|
Renvoie e élevé à la puissance indiquée, moins 1. |
|
|
Renvoie le logarithme dans la base fournie. |
|
|
Renvoie le logarithme en base 2. |
|
|
Renvoie le logarithme en base 10. |
|
|
Renvoie log(1 + x). |
|
|
Convertit les valeurs de radians en degrés. |
|
|
Convertit les valeurs de degrés en radians. |
|
|
Renvoie le plus petit entier supérieur ou égal au nombre donné. |
|
|
Renvoie le plus grand entier inférieur ou égal au nombre donné. |
|
|
Renvoie le nombre tronqué à la décimale spécifiée. |
Comparaisons et vérifications de plage
Comparez une séquence à une autre séquence ou à un scalaire :
>>> (iris.sepallength < 5).head(5)
sepallength
0 False
1 True
2 True
3 True
4 False
Les comparaisons chaînées telles que 3 <= iris.sepallength <= 5 ne sont pas prises en charge. Utilisez plutôt la méthode between :
>>> iris.sepallength.between(3, 5).head(5) # inclusive by default
sepallength
0 False
1 True
2 True
3 True
4 True
Pour exclure les bornes, définissez le paramètre inclusive=False :
>>> iris.sepallength.between(3, 5, inclusive=False).head(5)
sepallength
0 False
1 True
2 True
3 True
4 False
Opérations sur les chaînes de caractères
L'API DataFrame propose plus de 35 fonctions de manipulation des chaînes, applicables aux objets séquentiels et scalaires. Ces fonctions s'appellent directement sur une colonne de type chaîne ; aucune importation d'espace de noms distinct n'est requise. L'exemple ci-dessous illustre l'utilisation de upper et de extract :
>>> fields = [
... iris.name.upper().rename('upper_name'),
... iris.name.extract('Iris(.*)', group=1),
... ]
>>> iris[fields].head(5)
upper_name name
0 IRIS-SETOSA -setosa
1 IRIS-SETOSA -setosa
2 IRIS-SETOSA -setosa
3 IRIS-SETOSA -setosa
4 IRIS-SETOSA -setosa
Le tableau suivant répertorie toutes les fonctions de chaîne prises en charge.
|
Fonction |
description |
|
|
Met la première lettre en majuscule et le reste en minuscules. |
|
|
Indique si la chaîne contient une sous-chaîne. Par défaut, le paramètre |
|
|
Renvoie le nombre d'occurrences de la sous-chaîne spécifiée. |
|
|
Vérifie si la chaîne se termine par le suffixe indiqué. |
|
|
Détermine si la chaîne commence par le préfixe spécifié. |
|
|
Extrait les correspondances d'une expression régulière. En l'absence du paramètre |
|
|
Parcourt la chaîne de gauche à droite et renvoie l'indice de la première occurrence de la sous-chaîne. Renvoie |
|
|
Parcourt la chaîne de droite à gauche et renvoie l'indice de la première occurrence de la sous-chaîne. Renvoie |
|
|
Remplace les sous-chaînes correspondant à un motif d'expression régulière. Utilisez le paramètre |
|
|
Récupère le caractère situé à la position indiquée. |
|
|
Renvoie la longueur de la chaîne. |
|
|
Ajoute des caractères de remplissage à droite via |
|
|
Ajoute des caractères de remplissage à gauche via |
|
|
Convertit la chaîne en minuscules. |
|
|
Convertit la chaîne en majuscules. |
|
|
Supprime les espaces de début, y compris les lignes vides. |
|
|
Supprime les espaces de fin, y compris les lignes vides. |
|
|
Supprime les espaces de début et de fin, y compris les lignes vides. |
|
|
Découpe la chaîne selon le délimiteur spécifié et renvoie une valeur de |
|
|
Ajoute des caractères de remplissage via |
|
|
Répète la chaîne n fois. |
|
|
Effectue une opération de découpage (slice) sur la chaîne. |
|
|
Inverse la casse de tous les caractères : les majuscules deviennent des minuscules et inversement. |
|
|
Convertit la chaîne en format « titre », où chaque mot commence par une majuscule. Équivalent à |
|
|
Ajoute des zéros |
|
|
Renvoie |
|
|
Renvoie |
|
|
Renvoie |
|
|
Renvoie |
|
|
Renvoie |
|
|
Renvoie |
|
|
Renvoie |
|
|
Renvoie |
|
|
Renvoie |
|
|
Transforme la chaîne en une valeur de |
|
|
Analyse une chaîne pour la convertir en datetime en utilisant les mêmes codes de format que la bibliothèque standard Python. Consultez la documentation Basic date and time types. |
Opérations sur les dates et heures
Les fonctions de date et d'heure s'appliquent aux objets séquentiels et scalaires de type DATETIME.
L'exemple suivant extrait l'année, le mois, le jour et l'heure d'une colonne contenant un horodatage Unix :
>>> df = lens[[lens.unix_timestamp.astype('datetime').rename('dt')]]
>>> df[df.dt,
... df.dt.year.rename('year'),
... df.dt.month.rename('month'),
... df.dt.day.rename('day'),
... df.dt.hour.rename('hour')].head(5)
dt year month day hour
0 1998-04-08 11:02:00 1998 4 8 11
1 1998-04-08 10:57:55 1998 4 8 10
2 1998-04-08 10:45:26 1998 4 8 10
3 1998-04-08 10:25:52 1998 4 8 10
4 1998-04-08 10:44:19 1998 4 8 10
Le tableau ci-dessous décrit les attributs de date et d'heure pris en charge.
Attribute | Description |
| Renvoie la composante année de la date et de l'heure. |
| Renvoie la composante mois (1-12). |
| Renvoie le jour du mois. |
| Renvoie la composante heure (0-23). |
| Renvoie la composante minute (0-59). |
| Renvoie la composante seconde (0-59). |
| Renvoie le numéro de semaine ISO de l'année. Le lundi est le premier jour de la semaine. |
| Renvoie un nombre représentant le jour de la semaine correspondant à la date fournie. |
| Renvoie un nombre représentant le jour de la semaine correspondant à la date fournie. |
| Met en forme la date et l'heure sous forme de chaîne en utilisant les mêmes codes de format que la bibliothèque standard Python. Consultez Types de date et d'heure de base. Convertit la chaîne donnée représentant une heure au format spécifié. Le format horaire est identique à celui de la bibliothèque Python standard. Pour plus d'informations sur les formats horaires en Python, consultez Types de date et d'heure de base. Convertit la chaîne donnée représentant une heure au format spécifié. Le format horaire est identique à celui de la bibliothèque Python standard. Pour plus d'informations sur les formats horaires en Python, consultez Types de date et d'heure de base. |
Arithmétique des dates et heures
PyODPS prend en charge l'arithmétique des dates. Utilisez les types d'unités de date et d'heure de odps.df pour ajouter ou soustraire des intervalles de temps. La soustraction de deux colonnes de type datetime renvoie la différence en millisecondes sous forme de int64.
>>> from odps.df import day
>>> df
a b
0 2016-12-06 16:43:12.460001 2016-12-06 17:43:12.460018
1 2016-12-06 16:43:12.460012 2016-12-06 17:43:12.460021
2 2016-12-06 16:43:12.460015 2016-12-06 17:43:12.460022
>>> df.a - day(3) # subtract 3 days from column a
a
0 2016-12-03 16:43:12.460001
1 2016-12-03 16:43:12.460012
2 2016-12-03 16:43:12.460015
>>> (df.b - df.a).dtype # difference between two datetime columns
int64
>>> (df.b - df.a).rename('a') # result is in milliseconds
a
0 3600000
1 3600000
2 3600000
Le tableau ci-dessous répertorie les types d'unités de date et d'heure disponibles pour les opérations arithmétiques.
|
Type |
Description |
|
|
Intervalle au niveau de l'année. |
|
|
Intervalle au niveau du mois. |
|
|
Intervalle au niveau du jour. |
|
|
Intervalle au niveau de l'heure. |
|
|
Intervalle au niveau de la minute. |
|
|
Intervalle au niveau de la seconde. |
|
|
Intervalle au niveau de la milliseconde. |
Opérations sur les collections
PyODPS prend en charge les types de collection LIST et DICT. Utilisez les indices pour récupérer des éléments individuels et len pour obtenir le nombre d'éléments.
>>> df
id a b
0 1 [a1, b1] {'a2': 0, 'b2': 1, 'c2': 2}
1 2 [c1] {'d2': 3, 'e2': 4}
>>> df[df.id, df.a[0], df.b['b2']] # access by subscript
id a b
0 1 a1 1
1 2 c1 NaN
>>> df[df.id, df.a.len(), df.b.len()] # get collection size
id a b
0 1 2 3
1 2 1 2
explode
Utilisez explode pour développer une colonne de collection en lignes individuelles, soit une ligne par élément. Cette approche s'avère utile pour les agrégations ou jointures en aval qui nécessitent des données aplaties au niveau des lignes.
Pour les colonnes LIST, explode renvoie une seule colonne par défaut. Définissez pos=True afin d'inclure également l'indice de position de l'élément (similaire à la fonction enumerate de Python) :
>>> df.a.explode()
a
0 a1
1 b1
2 c1
>>> df.a.explode(pos=True) # include position index
a_pos a
0 0 a1
1 1 b1
2 0 c1
>>> df.a.explode(['pos', 'value'], pos=True) # specify column names
pos value
0 0 a1
1 1 b1
2 0 c1
Pour les colonnes DICT, explode renvoie deux colonnes : les clés et les valeurs.
>>> df.b.explode()
b_key b_value
0 a2 0
1 b2 1
2 c2 2
3 d2 3
4 e2 4
>>> df.b.explode(['key', 'value']) # specify column names
key value
0 a2 0
1 b2 1
2 c2 2
3 d2 3
4 e2 4
Combinez explode avec la sélection de colonnes pour associer les colonnes développées aux colonnes d'origine :
>>> df[df.id, df.a.explode()]
id a
0 1 a1
1 1 b1
2 2 c1
>>> df[df.id, df.a.explode(), df.b.explode()] # cross-product of both collections
id a b_key b_value
0 1 a1 a2 0
1 1 a1 b2 1
2 1 a1 c2 2
3 1 b1 a2 0
4 1 b1 b2 1
5 1 b1 c2 2
6 2 c1 d2 3
7 2 c1 e2 4
Méthodes spécifiques aux LIST
Outre len et explode, les colonnes LIST prennent en charge les méthodes suivantes.
|
Method |
Description |
|
|
Renvoie |
|
|
Trie la liste et renvoie une valeur LIST. |
Méthodes spécifiques aux DICT
En plus de len et explode, les colonnes DICT prennent en charge les méthodes suivantes.
|
Method |
Description |
|
|
Renvoie toutes les clés sous forme de valeur LIST. |
|
|
Renvoie toutes les valeurs sous forme de valeur LIST. |
Autres opérations
isin et notin
La méthode isin vérifie si chaque élément existe dans une collection spécifiée. La méthode notin effectue la vérification inverse.
>>> iris.sepallength.isin([4.9, 5.1]).rename('sepallength').head(5)
sepallength
0 True
1 True
2 False
3 False
4 False
cut
La méthode cut divise les valeurs séquentielles en segments discrets (bins).
>>> iris.sepallength.cut(range(6), labels=['0-1', '1-2', '2-3', '3-4', '4-5']).rename('sepallength_cut').head(5)
sepallength_cut
0 None
1 4-5
2 4-5
3 4-5
4 4-5
Vous pouvez utiliser les opérations include_under et include_over pour spécifier respectivement les valeurs minimales et maximales.
>>> labels = ['0-1', '1-2', '2-3', '3-4', '4-5', '5-']
>>> iris.sepallength.cut(range(6), labels=labels, include_over=True).rename('sepallength_cut').head(5)
sepallength_cut
0 5-
1 4-5
2 4-5
3 4-5
4 4-5
Appeler des fonctions intégrées ou des UDF dans MaxCompute
Utilisez la fonction func pour appeler des fonctions intégrées MaxCompute ou des fonctions définies par l'utilisateur (UDF) afin de créer des colonnes. Le type de retour est STRING par défaut ; utilisez le paramètre rtype pour le remplacer.
from odps.df import func
iris[iris.name, func.rand(rtype='float').rename('rand')][:4]
iris[iris.name, func.rand(10, rtype='float').rename('rand')][:4]
# Call a UDF defined in MaxCompute. Specify the column name if it cannot be inferred automatically.
iris[iris.name, func.your_udf(iris.sepalwidth, iris.sepallength, rtype='float').rename('new_col')]
# Call a UDF from another project using the project parameter.
iris[iris.name, func.your_udf(iris.sepalwidth, iris.sepallength, rtype='float', project='udf_project', name='new_col')]
Le backend Pandas ne prend pas en charge les expressions contenant la fonction func.