Fonction groupby-transform() de Pandas

Pandas 常用函数Fonctions courantes de Pandas


groupby.transform()C'est une fonction de Pandas permettant de transformer les données après regroupement. Contrairement aux fonctions d'agrégation,l'agrégation renvoie un résultat récapitulatif pour chaque groupe, tandis que la transformation renvoie un résultat de même longueur que les données d'origine.。

En termes simples,transform()il diffuse le résultat du calcul groupé vers chaque ligne des données d'origine. C'est très utile dans des scénarios tels que le calcul de la position relative de chaque membre au sein d'un groupe, la standardisation intra-groupe et les différences par rapport à la moyenne du groupe.


Syntaxe de base et paramètres

transform()C'est une fonction membre de l'objet GroupBy. Vous devez d'abord utilisergroupby()le regroupement avant de l'appeler.

Format de syntaxe

GroupBy.transform(func, axis=0, *args, engine=None, engine_kwargs=None, **kwargs)

Description des paramètres

Paramètre Type Description Valeur par défaut
func str, list, dict ou callable La fonction de transformation. Elle peut être un nom de fonction intégré (tel que 'mean', 'sum', 'std'), une liste de fonctions, un dictionnaire spécifiant différentes fonctions pour chaque colonne, ou une fonction personnalisée. Aucune
axis int La direction de l'axe pour appliquer la transformation. 0 signifie par ligne (dimension de regroupement), 1 signifie par colonne. 0
args tuple Arguments positionnels supplémentaires transmis à la fonction de transformation. ()
engine str Spécifie le moteur de calcul, qui peut être 'cython' ou 'numba'. None signifie que Pandas le sélectionne automatiquement. Aucune
engine_kwargs dict Un dictionnaire de paramètres supplémentaires transmis au moteur sous-jacent. Aucune

Valeur de retour

  • Type de retour:SeriesouDataFrame
  • Description: Renvoie un résultat avec le même nombre de lignes que les données d'origine. Chaque ligne de données d'origine reçoit le résultat de calcul de son groupe correspondant.

Exemples

Maîtrisons à fond, à travers une série d'exemples du simple au complexe,groupby.transform()l'utilisation.

Exemple 1 : Utilisation de base - Calculer la moyenne du groupe

transform()L'utilisation la plus élémentaire consiste à calculer la moyenne de chaque groupe, puis à diffuser le résultat sur chaque ligne.

Exemple

import pandas as pd

# Créer des données de notes d'étudiants
data = {
    'Name': ['Zhang San', 'Li Si', 'Wang Wu', 'Zhao Liu', Sun Qi, Zhou Ba, Wu Jiu, Zheng Shi],
    Classe: ['A', 'A', 'A', 'B', 'B', 'B', 'B', 'A'],
    Chinois: [85, 92, 78, 88, 95, 82, 90, 87],
    Mathématiques: [90, 85, 92, 78, 88, 91, 85, 89]
}

# Créer un DataFrame
df = pd.DataFrame(data)

print("Données de notes d'étudiants :")
print(df)
print()

# Calculer la moyenne en mathématiques pour chaque classe, puis la diffuser sur chaque ligne
df['Class Math Average'] = df.groupby(Class)[Mathematics].transform('mean')

# Calculer la différence entre le score de chaque élève et la moyenne de la classe
df['Difference from average score'] = df[Mathematics] - df['Class Math Average']

print("Données après ajout de la moyenne de la classe et de la différence :")
print(df)
print()

# Calculer la moyenne par classe pour plusieurs colonnes simultanément
df[['Class Chinese Average', 'Class Math Average 2']] = df.groupby(Class)[[Chinese, Mathematics]].transform('mean')

print(Données après l'ajout des moyennes multi-colonnes :)
print(df)

Résultat de l'exécution :

学生成绩数据:
   姓名  班级  语文  数学
0  张三   A   85   90
1  李四   A   92   85
2  王五   A   78   92
3  赵六   B   88   78
4  孙七   B   95   88
5  周八   B   82   91
6  吴九   B   90   85
7  郑十   A   87   89

添加班级平均分和差值后的数据:
   姓名  班级   语文   数学   班级数学平均分   与平均分差值
0  张三   A   85   90  89.000000   1.000000
1  李四   A   92   85  89.000000  -4.000000
2  王五   A   78   92  89.000000   3.000000
3  赵六   B   88   78  85.666667   -7.666667
4  孙七   B   95   88  85.666667   2.333333
5  周八   B   82   91  85.666667   5.333333
6  吴九   B   90   85  85.666667   -0.666667
7  郑十   A   87   89  89.000000   0.000000

添加多列平均值后的数据:
   姓名  班级   语文   数学  班级语文平均分  班级数学平均分2
0  张三   A   85   90  85.500000         89.0
1  李四   A   92   85  85.500000         89.0
2  王五   A   78   92  85.500000         89.0
3  赵六   B   88   78  88.750000         85.5
4  孙七   B   95   88  88.750000         85.5
5  周八   B   82   91  88.750000         85.5
6  吴九   B   90   85  88.750000         85.5
7  郑十   A   87   89  85.500000         89.0

Explication du code :

  1. transform('mean')Calculez la moyenne en mathématiques pour chaque classe.
  2. Puisque Zhang San, Li Si, Wang Wu et Zheng Shi sont tous dans la classe A, la « Class Math Average » qu'ils obtiennent est la moyenne des notes en mathématiques de la classe A.
  3. La longueur de la valeur de retour est la même que le nombre de lignes des données d'origine ; c'est la différence clé entre transform et agg.

Exemple 2 : Standardisation intra-groupe (Z-Score)

transform()Il est souvent utilisé pour calculer des valeurs standardisées intra-groupe, ce qui est très utile pour comparer la position relative des individus au sein d'un groupe.

Exemple

import pandas as pd

# Créer des données salariales d’employés
data = {
    'Name': ['Zhang San', 'Li Si', 'Wang Wu', 'Zhao Liu', Sun Qi, Zhou Ba, Wu Jiu, Zheng Shi],
    'Department': [Sales, Sales, Sales, 'Technology', 'Technology', 'Technology', Administration, Administration],
    'salary': [5000, 8000, 6000, 9000, 12000, 10000, 4500, 7000]
}
df = pd.DataFrame(data)

print("Données de salaire des employés :")
print(df)
print()

# Calculer le Z-Score (score standardisé) du salaire de chaque employé au sein du département
# Z-Score = (valeur d'origine - moyenne intra-groupe) / écart-type intra-groupe
df['Department average salary'] = df.groupby('Department')['salary'].transform('mean')
df['Department Salary Standard Deviation'] = df.groupby('Department')['salary'].transform('std')
df['Z-Score'] = (df['salary'] - df['Department average salary']) / df['Department Salary Standard Deviation']

print(Données après ajout des statistiques de département et du Z-Score :)
print(df)
print()

# Calculer le Z-Score en une seule fois à l'aide d'une fonction personnalisée
def z_score(x):
    """Calculer le Z-Score"""
    return (x - x.mean()) / x.std()

df['Z-Score2'] = df.groupby('Department')['salary'].transform(z_score)

print(Z-Score calculé à l'aide d'une fonction personnalisée :)
print(df[['Name', 'Department', 'salary', 'Z-Score2']])

Résultat de l'exécution :

员工工资数据:
  姓名  部门    工资
0  张三   销售   5000
1  李四   销售   8000
2  王五   销售   6000
3  赵六   技术   9000
4  孙七   技术  12000
5  周八   技术  10000
6  吴九   行政   4500
7  郑十   行政   7000

添加部门统计和Z-Score后的数据:
   姓名   部门    工资    部门平均工资   部门工资标准差    Z-Score
0  张三   销售  5000  6333.333333  1525.755   -0.872871
1  李四   销售  8000  6333.333333  1525.755    1.092091
2  王五   销售  6000  6333.333333  1525.755   -0.218218
3  赵六   技术  9000 10333.333333  1525.755   -0.872871
4  孙七   技术 12000 10333.333333  1525.755    1.092091
5  周八   技术 10000 10333.333333  1525.755   -0.218218
6  吴九   行政   4500  5750.000000  1767.767   -0.707107
7  郑十   行政   7000  5750.000000  1767.767    0.707107

使用自定义函数计算的 Z-Score:
   姓名  部门    工资   Z-Score2
0  张三   销售  5000  -0.872871
1  李四   销售  8000   1.092091
2  王五   销售  6000  -0.218218
3  赵六   技术  9000  -0.872871
4  孙七   技术 12000   1.092091
5  周八   技术 10000  -0.218218
6  吴九   行政  4500  -0.707107
7  郑十   行政  7000   0.707107

Explication du code :

  • Le Z-Score indique de combien d'écarts-types la valeur d'origine s'écarte de la moyenne. Une valeur positive signifie qu'elle est au-dessus de la moyenne, et une valeur négative qu'elle est en dessous de la moyenne.
  • Grâce au Z-Score, l'influence des différences de niveau de salaire entre les services peut être éliminée, ce qui permet de comparer les positions relatives des employés au sein de leur service.
  • Le Z-Score de Zhang San est de -0.87, ce qui indique que son salaire se situe environ 0.87 écart-type en dessous du niveau moyen du service des ventes.

Exemple 3 : classement au sein du groupe et centile

transform()Il peut également être utilisé pour calculer des classements au sein d'un groupe, ce qui est très utile dans le tri et l'analyse concurrentielle.

Exemple

import pandas as pd
import numpy as np

# Créer des données de notes d'étudiants
data = {
    'Name': ['Zhang San', 'Li Si', 'Wang Wu', 'Zhao Liu', Sun Qi, Zhou Ba, Wu Jiu, Zheng Shi],
    Classe: ['A', 'A', 'A', 'B', 'B', 'B', 'B', 'A'],
    Mathématiques: [90, 85, 92, 78, 88, 91, 85, 89]
}
df = pd.DataFrame(data)

print("Données de notes d'étudiants :")
print(df)
print()

# Calculer le classement de chaque étudiant dans sa classe (du plus élevé au plus faible)
df['班levelinside排name'] = df.groupby(Class)[Mathematics].transform(lambda x: x.rank(ascending=False))

# Calculer le centile de chaque étudiant (classement en pourcentage) dans la classe
df['Percentile within class'] = df.groupby(Class)[Mathematics].transform(lambda x: x.rank(pct=True))

print("Données après ajout du classement dans la classe et du centile :")
print(df)
print()

# Une autre façon de remplir les valeurs manquantes : remplir avec la moyenne du groupe
data_with_na = {
    'Name': ['Zhang San', 'Li Si', 'Wang Wu', 'Zhao Liu', Sun Qi, Zhou Ba],
    Classe: ['A', 'A', 'A', 'B', 'B', 'B'],
    'Score': [85, np.nan, 78, 88, np.nan, 82]
}
df_na = pd.DataFrame(data_with_na)

print(Données contenant des valeurs manquantes :)
print(df_na)
print()

# Remplir les valeurs manquantes avec la moyenne du groupe
df_na['Filled score'] = df_na.groupby(Class)['Score'].transform(lambda x: x.fillna(x.mean()))

print(Résultat après remplissage avec la moyenne du groupe :)
print(df_na)

Résultat de l'exécution :

学生成绩数据:
   姓名  班级  数学
0  张三   A   90
1  李四   A   85
2  王五   A   92
3  赵六   B   78
4  孙七   B   88
5  周八   B   91
6  吴九   B   85
7  郑十   A   89

添加班级内排名和百分位后的数据:
   姓名   班级   数学   班级内排名   班级内百分位
0  张三   A   90   2.0   0.666667
1  李四   A   85   3.0   1.000000
2  王五   A   92   1.0   1.000000
3  赵六   B   78   4.0   0.250000
4  孙七   B   88   2.0   0.500000
5  周八   B   91   1.0   0.750000
6  吴九   B   85   3.0   0.500000
7  郑十   A   89   4.0   0.333333

包含缺失值的数据:
   姓名  班级   成绩
0  张三   A   85.0
1  李四   A    NaN
2  王五   A   78.0
3  赵六   B   88.0
4  孙七   B    NaN
5  周八   B   82.0

使用组内均值填充后的结果:
   姓名  班级   成绩  填充后的成绩
0  张三   A   85.0         85.0
1  李四   A    NaN         81.5
2  王五   A   78.0         78.0
3  赵六   B   88.0         88.0
4  孙七   B    NaN         85.0
5  周八   B   82.0         82.0

Explication du code :

  • rank(ascending=False)Calculer le classement, avec les valeurs plus élevées classées en premier.
  • rank(pct=True)Calculer le classement en percentiles, avec des résultats compris entre 0 et 1.
  • transform(lambda x: x.fillna(x.mean()))C'est un modèle courant pour gérer les valeurs manquantes, en utilisant la moyenne de chaque groupe pour remplir les valeurs manquantes au sein de ce groupe.

Exemple 4 : Utilisation d'une fonction de transformation personnalisée

transform()Les fonctions personnalisées sont prises en charge, ce qui permet une logique plus complexe de transformation des données au sein du groupe.

Exemple

import pandas as pd
import numpy as np

# Créer des données de prix des actions
data = {
    'Stock Code': ['AAPL', 'AAPL', 'AAPL', 'AAPL', 'GOOG', 'GOOG', 'GOOG', 'GOOG'],
    'Date': ['2024-01-01', '2024-01-02', '2024-01-03', '2024-01-04'] * 2,
    'Close Price': [100, 105, 102, 110, 80, 85, 82, 90]
}
df = pd.DataFrame(data)

print("Données de prix des actions :")
print(df)
print()

# Fonction personnalisée : calculer le taux de rendement quotidien pour chaque action
def calc_daily_return(prices):
    """Calcule le taux de rendement quotidien : (prix d'aujourd'hui - prix d'hier) / prix d'hier"""
    return prices.pct_change()

# Calculer le taux de rendement quotidien pour chaque action
df['Daily Return'] = df.groupby('Stock Code')['Close Price'].transform(calc_daily_return)

print("Données après l'ajout du rendement quotidien :")
print(df)
print()

# Fonction personnalisée : calculer la valeur normalisée en fonction du max et du min dans le groupe
def normalize(x):
    """Normalisation : (x - min) / (max - min)"""
    return (x - x.min()) / (x.max() - x.min())

# Calculer le prix normalisé pour chaque action
df['Normalized Price'] = df.groupby('Stock Code')['Close Price'].transform(normalize)

print("Données après l'ajout du prix normalisé :")
print(df)

Résultat de l'exécution:

股票价格数据:
  股票代码         日期   收盘价
0  AAPL  2024-01-01   100
1  AAPL  2024-01-02   105
2  AAPL  2024-01-03   102
3  AAPL  2024-01-04   110
4  GOOG  2024-01-01    80
5  GOOG  2024-01-02    85
6  GOOG  2024-01-03    82
7  GOOG  2024-01-04    90

添加日收益率后的数据:
   股票代码         日期  收盘价     日收益率
0  AAPL  2024-01-01   100         NaN
1  AAPL  2024-01-02   105    0.050000
2  AAPL  2024-01-03   102   -0.028571
3  AAPL  2024-01-04   110    0.078431
4  GOOG  2024-01-01    80         NaN
5  GOOG  2024-01-02    85    0.062500
6  GOOG  2024-01-03    82   -0.035294
7  GOOG  2024-01-04    90    0.097561

添加归一化价格后的数据:
   股票代码         日期  收盘价     日收益率   归一化价格
0  AAPL  2024-01-01   100         NaN    0.000000
1  AAPL  2024-01-02   105    0.050000    0.500000
2  AAPL  2024-01-03   102   -0.028571    0.200000
3  AAPL  2024-01-04   110    0.078431    1.000000
4  GOOG  2024-01-01    80         NaN    0.000000
5  GOOG  2024-01-02    85    0.062500    0.500000
6  GOOG  2024-01-03    82   -0.035294    0.200000
7  GOOG  2024-01-04    90    0.097561    1.000000

Explication du code :

  • La fonction de transformation reçoit une Series (les données au sein de chaque groupe).
  • La longueur de la Series renvoyée doit correspondre à la longueur de la Series d'entrée.
  • La première valeur est NaN carpct_change()il calcule une variation relative, et le premier jour n'a pas de données du jour précédent.

Différence principale :agg()ettransform()La différence est :agg()renvoie le résultat agrégé pour chaque groupe (le nombre de lignes est égal au nombre de groupes), tandis quetransform()renvoie un résultat de même longueur que les données d'origine. Moyen mnémotechnique : agg compresse les données, transform préserve la forme des données.


Pandas 常用函数Fonctions courantes de Pandas

Autres extensions