Group By
Objectifs
L'opération GroupBy que vous connaissez bien en R (Tidyverse) ou en Python (Panda) répond à un pattern très courant en Data Science, à savoir la stratégie du split apply combine
Warning
Attention, ici l'objectif c'est de ne pas utiliser les fonctions groupby déjà existante en Python, en Panda, ou en Numpy.
Minimun
- Reprendre l'algorithme vu en cours pour compter le nombre d'occurences et l'adapter pour gérer une liste de chiffres ou de lettres.
- En faire une fonction
groupby(...)qui pour une liste passée en paramètre renvoie une liste qui contient pour chaque occurence unique, la clef, et le nombre d'occurences. Ex :["A","A","B","C","A","B"]renverra[["A",3], ["B",2],["C",1]] - La liste passé en paramètre devient la liste contenant les clefs, auquel on associe une deuxième liste qui contient les valeurs. La fonction
group_by(... , ...)prend donc deux entrées. Ex: la liste clef["A", "A", "B", "C", "A", "B"]et la liste de valeurs associées[2,3,5,1,7,4]. La fonction renvoie pour chaque clef la liste des valeurs associées[["A",[2,3,7]], ["B", [5,4]], ["C", [1]]] - Créer une autre fonction
compute_sum (...)qui prend cette liste renvoyée par votre première fonction (ex :[["A",[2,3,7]], ["B", [5,4]], ["C", [1]]]) et renvoie une somme (ex:[["A",12], ["B", 9], ["C", "1"]])
Bonus
- Simplifier/Revoir cette fonction en changeant de type de structure de données : les
Dictionnaires(voir ici) permettent de gérer beaucoup plus facilement les couples{clef: valeurs} - Passer une fonction existante en python (ex:
sum,mean, etc. ) comme troisième entrée de la fonctiongroupby(..., ... , ... ). Celle-ci sera appliqué pour l'aggrégation des termes de la liste, par clef. Le retour sera fonction de l'opération appliquée.
Correction
Version avec des listes
def simple_groupby(tabKeyOriginal,tabData):
tabKey = tabKeyOriginal[:]
tabKey.sort()
tabUniqueKey = []
tabGrouped = []
tabUniqueKey.append(tabKey[0])
for i in range(1,len(tabKey) ):
if (tabKey[i] != tabKey[i - 1]):
tabUniqueKey.append(tabKey[i])
tabOccurence = []
for sd in range (len(tabUniqueKey)):
tabOccurence.append([])
for ad in range(len(tabKeyOriginal)):
if (tabUniqueKey[sd] == tabKeyOriginal[ad]):
tabOccurence[sd].append(tabData[ad])
for i in range(len(tabUniqueKey)):
tabGrouped.append([tabUniqueKey[i], tabOccurence[i]])
return (tabGrouped)
def compute_sum(groupedData):
tabSummed = []
for i in range(len(groupedData)):
tabTransformed = []
tabTransformed.append(groupedData[i][0])
sommeElement = 0
for e in groupedData[i][1]:
sommeElement += int(e)
tabTransformed.append(sommeElement)
tabSummed.append(tabTransformed)
return tabSummed
L'appel à ces deux fonctions :
myList = ["A","B","A","C","D","B","D","A","A","D","C","C","E","D","C"]
myData = [ 2, 8, 3, 5, 2, 3, 7, 10, 5, 2, 4, 3, 8, 5, 7]
# => ["A",[2,3,10,5]]
result = simple_groupby(myList,myData)
print("list only = ", result)
resultsummed = compute_sum(result)
print("list only summed = ", resultsummed)
Version avec des dictionnaires
def dict_groupby(some_keys,some_data):
group_list = {}
for i, k in enumerate(some_keys):
if k in group_list.keys():
group_list[k].append(some_data[i])
else:
group_list.update({k: [some_data[i]]})
return group_list
def dict_groupby_sum(some_keys, some_data):
result = {}
for key, val in zip(some_keys, some_data):
if key not in result:
result[key] = 0
result[key] += val
return result
L'appel aux deux fonctions :