Supposons que j'aie un df
qui a des colonnes de 'ID', 'col_1', 'col_2'
. Et je définis une fonction:
f = lambda x, y : my_function_expression
.
Maintenant , je veux appliquer la f
à df
deux colonnes » 'col_1', 'col_2'
pour calculer élément par élément une nouvelle colonne 'col_3'
, un peu comme:
df['col_3'] = df[['col_1','col_2']].apply(f)
# Pandas gives : TypeError: ('<lambda>() takes exactly 2 arguments (1 given)'
Comment faire ?
** Ajouter un échantillon détaillé comme ci-dessous ***
import pandas as pd
df = pd.DataFrame({'ID':['1','2','3'], 'col_1': [0,2,3], 'col_2':[1,4,5]})
mylist = ['a','b','c','d','e','f']
def get_sublist(sta,end):
return mylist[sta:end+1]
#df['col_3'] = df[['col_1','col_2']].apply(get_sublist,axis=1)
# expect above to output df as below
ID col_1 col_2 col_3
0 1 0 1 ['a', 'b']
1 2 2 4 ['c', 'd', 'e']
2 3 3 5 ['d', 'e', 'f']
f
se passeRéponses:
Voici un exemple d'utilisation
apply
sur le dataframe, avec lequel j'appelleaxis = 1
.Notez que la différence est qu'au lieu d'essayer de passer deux valeurs à la fonction
f
, réécrivez la fonction pour accepter un objet Pandas Series, puis indexez la série pour obtenir les valeurs nécessaires.Selon votre cas d'utilisation, il est parfois utile de créer un
group
objet pandas , puis de l'utiliserapply
sur le groupe.la source
sum
est résolu avec succès par l'une des méthodes suggérées jusqu'à présent.df
objet que vous avez défini, une autre approche (avec des résultats équivalents) estdf.apply(lambda x: x[0] + x[1], axis = 1)
.Il existe un moyen propre et unique de le faire dans Pandas:
Cela permet
f
d'être une fonction définie par l'utilisateur avec plusieurs valeurs d'entrée, et utilise des noms de colonne (sûrs) plutôt que des indices numériques (dangereux) pour accéder aux colonnes.Exemple avec des données (basé sur la question d'origine):
Sortie de
print(df)
:Si les noms de vos colonnes contiennent des espaces ou partagent un nom avec un attribut de trame de données existant, vous pouvez indexer entre crochets:
la source
axis=1
et que votre colonne est appelée,name
elle ne renverra pas réellement vos données de colonne mais leindex
. Similaire à la misename
en agroupby()
. J'ai résolu cela en renommant ma colonne..loc
dans l'exemple. Il peut être nécessaire de l'adapter à un autre paramètre de problème (par exemple, travailler avec des tranches).Une solution simple est:
la source
Une question intéressante! ma réponse comme ci-dessous:
Production:
J'ai changé le nom de la colonne en ID, J1, J2, J3 pour garantir l'ID <J1 <J2 <J3, afin que la colonne s'affiche dans le bon ordre.
Une autre version brève:
la source
La méthode que vous recherchez est Series.combine. Cependant, il semble que certains types de données doivent être pris en compte. Dans votre exemple, vous appelleriez (comme je l'ai fait lors du test de la réponse) naïvement
Cependant, cela jette l'erreur:
Ma meilleure supposition est qu'il semble s'attendre à ce que le résultat soit du même type que la série appelant la méthode (df.col_1 ici). Cependant, les travaux suivants:
la source
La façon dont vous avez écrit f nécessite deux entrées. Si vous regardez le message d'erreur, il indique que vous ne fournissez pas deux entrées à f, une seule. Le message d'erreur est correct.
La non-concordance est due au fait que df [['col1', 'col2']] renvoie une seule trame de données avec deux colonnes, pas deux colonnes distinctes.
Vous devez modifier votre f pour qu'il prenne une seule entrée, conserver le bloc de données ci-dessus en entrée, puis le décomposer en x, y à l' intérieur du corps de la fonction. Faites ensuite tout ce dont vous avez besoin et renvoyez une seule valeur.
Vous avez besoin de cette signature de fonction car la syntaxe est .apply (f) Donc, f doit prendre la seule chose = dataframe et non deux choses, ce qui est ce que votre f actuel attend.
Puisque vous n'avez pas fourni le corps de f, je ne peux pas vous aider plus en détail - mais cela devrait fournir la sortie sans changer fondamentalement votre code ou utiliser d'autres méthodes plutôt que d'appliquer
la source
Je vais voter pour np.vectorize. Il vous permet de simplement tirer sur x nombre de colonnes et de ne pas traiter le cadre de données dans la fonction, il est donc idéal pour les fonctions que vous ne contrôlez pas ou faire quelque chose comme l'envoi de 2 colonnes et une constante dans une fonction (par exemple col_1, col_2, 'foo').
la source
Renvoyer une liste
apply
est une opération dangereuse car l'objet résultant n'est pas garanti d'être une série ou un DataFrame. Et des exceptions pourraient être soulevées dans certains cas. Passons en revue un exemple simple:Il y a trois résultats possibles en renvoyant une liste de
apply
1) Si la longueur de la liste renvoyée n'est pas égale au nombre de colonnes, une série de listes est renvoyée.
2) Lorsque la longueur de la liste retournée est égale au nombre de colonnes, un DataFrame est renvoyé et chaque colonne obtient la valeur correspondante dans la liste.
3) Si la longueur de la liste retournée est égale au nombre de colonnes pour la première ligne mais a au moins une ligne où la liste a un nombre d'éléments différent du nombre de colonnes, une ValueError est levée.
Répondre au problème sans appliquer
L'utilisation
apply
avec axe = 1 est très lente. Il est possible d'obtenir de bien meilleures performances (en particulier sur des ensembles de données plus importants) avec des méthodes itératives de base.Créer une trame de données plus grande
Timings
@Thomas répond
la source
Je suis sûr que ce n'est pas aussi rapide que les solutions utilisant des opérations Pandas ou Numpy, mais si vous ne voulez pas réécrire votre fonction, vous pouvez utiliser la carte. Utilisation des données d'exemple d'origine -
Nous pourrions passer autant d'arguments que nous le voulions dans la fonction de cette façon. La sortie est ce que nous voulions
la source
apply
avecaxis=1
Mon exemple à vos questions:
la source
Si vous avez un énorme ensemble de données, vous pouvez utiliser une méthode simple mais plus rapide (temps d'exécution) à l'aide de swifter:
la source
Je suppose que vous ne voulez pas changer de
get_sublist
fonction et que vous voulez simplement utiliser laapply
méthode DataFrame pour faire le travail. Pour obtenir le résultat souhaité, j'ai écrit deux fonctions d'aide:get_sublist_list
etunlist
. Comme le nom de la fonction le suggère, obtenez d'abord la liste des sous-listes, puis extrayez la deuxième sous-liste de cette liste. Enfin, nous devons appeler laapply
fonction pour appliquer ces deux fonctions audf[['col_1','col_2']]
DataFrame par la suite.Si vous n'utilisez pas
[]
pour entourer laget_sublist
fonction, laget_sublist_list
fonction renverra une liste simple, elle augmenteraValueError: could not broadcast input array from shape (3) into shape (2)
, comme l'a mentionné @Ted Petrou.la source