Utilisez les index df1 d'origine pour créer la série:
df1['e'] = pd.Series(np.random.randn(sLength), index=df1.index)
Edit 2015
Certains ont rapporté avoir obtenu SettingWithCopyWarning
ce code.
Cependant, le code fonctionne toujours parfaitement avec la version actuelle 0.16.1 des pandas.
>>> sLength = len(df1['a'])
>>> df1
a b c d
6 -0.269221 -0.026476 0.997517 1.294385
8 0.917438 0.847941 0.034235 -0.448948
>>> df1['e'] = pd.Series(np.random.randn(sLength), index=df1.index)
>>> df1
a b c d e
6 -0.269221 -0.026476 0.997517 1.294385 1.757167
8 0.917438 0.847941 0.034235 -0.448948 2.228131
>>> p.version.short_version
'0.16.1'
L' SettingWithCopyWarning
objectif est d'informer d'une cession éventuellement invalide sur une copie du Dataframe. Cela ne signifie pas nécessairement que vous l'avez mal fait (cela peut déclencher de faux positifs) mais à partir de la version 0.13.0, il vous indique qu'il existe des méthodes plus adéquates pour le même objectif. Ensuite, si vous recevez l'avertissement, suivez simplement son conseil: Essayez d'utiliser .loc [row_index, col_indexer] = value à la place
>>> df1.loc[:,'f'] = pd.Series(np.random.randn(sLength), index=df1.index)
>>> df1
a b c d e f
6 -0.269221 -0.026476 0.997517 1.294385 1.757167 -0.050927
8 0.917438 0.847941 0.034235 -0.448948 2.228131 0.006109
>>>
En fait, c'est actuellement la méthode la plus efficace décrite dans les documents pandas
Modifier 2017
Comme indiqué dans les commentaires et par @Alexander, actuellement la meilleure méthode pour ajouter les valeurs d'une série en tant que nouvelle colonne d'un DataFrame pourrait utiliser assign
:
df1 = df1.assign(e=pd.Series(np.random.randn(sLength)).values)
SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_index,col_indexer] = value instead
kwargs
dictionnaire, comme ceci:df1 = df1.assign(**{'e': p.Series(np.random.randn(sLength)).values})
Voici le moyen simple d'ajouter une nouvelle colonne:
df['e'] = e
la source
e
(Series(np.random.randn(sLength))
) génère une série 0-n indexée. Si vous attribuez cela à df1, vous obtenez des cellules NaN.my_dataframe = pd.DataFrame(columns=('foo', 'bar'))
. Annulation de votre montageJe suppose que les valeurs d'index
e
correspondent à celles dedf1
.La façon la plus simple de lancer une nouvelle colonne nommée
e
et de lui affecter les valeurs de votre sériee
:assigner (Pandas 0.16.0+)
Depuis Pandas 0.16.0, vous pouvez également utiliser
assign
, qui attribue de nouvelles colonnes à un DataFrame et renvoie un nouvel objet (une copie) avec toutes les colonnes d'origine en plus des nouvelles.Selon cet exemple (qui inclut également le code source de la
assign
fonction), vous pouvez également inclure plusieurs colonnes:Dans le contexte de votre exemple:
La description de cette nouvelle fonctionnalité lors de son introduction peut être trouvée ici .
la source
df['e'] = e.values
) ne crée pas de copie de la trame de données, tandis que la deuxième option (en utilisantdf.assign
) le fait? Dans le cas de nombreuses nouvelles colonnes ajoutées séquentiellement et de grandes trames de données, je m'attendrais à de bien meilleures performances de la première méthode.assign
est de chaîner vos opérations.df.assign(**df.mean().add_prefix('mean_'))
df_new = pd.concat([df1, df2], axis=1)
, en notant celaignore_index=False
par défaut.Il semble que dans les versions récentes de Pandas, la voie à suivre consiste à utiliser df.assign :
df1 = df1.assign(e=np.random.randn(sLength))
Ça ne produit pas
SettingWithCopyWarning
.la source
Faire cela directement via NumPy sera le plus efficace:
Notez que ma suggestion originale (très ancienne) était d'utiliser
map
(qui est beaucoup plus lente):la source
.map
d'utiliser des séries existantes à la place delambda
? J'essayedf1['e'] = df1['a'].map(lambda x: e)
oudf1['e'] = df1['a'].map(e)
mais ce n'est pas ce dont j'ai besoin. (Je suis nouveau sur pyhon et votre réponse précédente m'a déjà aidé)e
une série, vous n'avez pas besoin d'utilisermap
, utilisezdf['e']=e
(réponse @joaquins).Affectation de colonne super simple
Une trame de données pandas est implémentée en tant que dictée ordonnée de colonnes.
Cela signifie que le
__getitem__
[]
peut non seulement être utilisé pour obtenir une certaine colonne, mais__setitem__
[] =
peut également être utilisé pour affecter une nouvelle colonne.Par exemple, cette trame de données peut avoir une colonne ajoutée en utilisant simplement l'
[]
accesseurNotez que cela fonctionne même si l'index de la trame de données est désactivé.
[] = est le chemin à parcourir, mais attention!
Cependant, si vous en avez un
pd.Series
et essayez de l'attribuer à une trame de données où les index sont désactivés, vous rencontrerez des problèmes. Voir l'exemple:En effet, un
pd.Series
par défaut a un index énuméré de 0 à n. Et la[] =
méthode des pandas essaie d'être "intelligente"Qu'est-ce qui se passe réellement.
Lorsque vous utilisez la
[] =
méthode pandas effectue discrètement une jointure externe ou une fusion externe à l'aide de l'index de la trame de données de gauche et de l'index de la série de droite.df['column'] = series
Note de côté
Cela provoque rapidement une dissonance cognitive, car la
[]=
méthode essaie de faire beaucoup de choses différentes en fonction de l'entrée, et le résultat ne peut être prédit que si vous savez simplement comment les pandas fonctionnent. Je déconseille donc les[]=
bases de code, mais lors de l'exploration de données dans un ordinateur portable, c'est très bien.Contourner le problème
Si tu as un
pd.Series
et que vous voulez l'attribuer de haut en bas, ou si vous codez du code productif et que vous n'êtes pas sûr de l'ordre des index, cela vaut la peine de le protéger pour ce type de problème.Vous pouvez abaisser le
pd.Series
à unnp.ndarray
ou unlist
, cela fera l'affaire.ou
Mais ce n'est pas très explicite.
Un codeur peut venir et dire "Hé, ça a l'air redondant, je vais juste l'optimiser".
Manière explicite
Définir l'index de la
pd.Series
pour être l'index de ladf
est explicite.Ou plus réaliste, vous en avez probablement
pd.Series
déjà un disponible.Peut maintenant être attribué
Moyen alternatif avec
df.reset_index()
Puisque la dissonance d'index est le problème, si vous sentez que l'indice de la trame de données ne doit pas dicter les choses, vous pouvez simplement supprimer l'index, cela devrait être plus rapide, mais ce n'est pas très propre, car votre fonction fait maintenant probablement deux choses.
Remarque sur
df.assign
Bien
df.assign
que ce soit plus explicite ce que vous faites, il a en fait tous les mêmes problèmes que ci-dessus[]=
Attention juste à ce
df.assign
que votre colonne ne soit pas appeléeself
. Cela entraînera des erreurs. Cela renddf.assign
malodorant , car il existe ce type d'artefacts dans la fonction.Vous pouvez dire: «Eh bien, je n'utiliserai tout simplement pas
self
alors». Mais qui sait comment cette fonction évoluera à l'avenir pour prendre en charge de nouveaux arguments. Peut-être que le nom de votre colonne sera un argument dans une nouvelle mise à jour de pandas, provoquant des problèmes de mise à niveau.la source
[] =
méthode pandas effectue tranquillement une jointure externe ou une fusion externe ". Il s'agit de l'information la plus importante de tout le sujet. Mais pourriez-vous fournir un lien vers la documentation officielle sur le fonctionnement de l'[]=
opérateur?Façons les plus simples: -
De cette façon, vous évitez ce qu'on appelle l'indexation chaînée lors de la définition de nouvelles valeurs dans un objet pandas. Cliquez ici pour lire plus loin .
la source
Si vous souhaitez définir la nouvelle colonne entière sur une valeur de base initiale (par exemple,
None
), vous pouvez le faire:df1['e'] = None
Cela attribuerait en fait le type "objet" à la cellule. Donc, plus tard, vous êtes libre de mettre des types de données complexes, comme la liste, dans des cellules individuelles.
la source
J'ai été redouté
SettingWithCopyWarning
, et il n'a pas été corrigé en utilisant la syntaxe iloc. Mon DataFrame a été créé par read_sql à partir d'une source ODBC. En utilisant une suggestion de lowtech ci-dessus, ce qui suit a fonctionné pour moi:Cela a bien fonctionné pour insérer la colonne à la fin. Je ne sais pas si c'est le plus efficace, mais je n'aime pas les messages d'avertissement. Je pense qu'il y a une meilleure solution, mais je ne la trouve pas, et je pense que cela dépend d'un certain aspect de l'index.
Remarque . Que cela ne fonctionne qu'une seule fois et donnera un message d'erreur si vous essayez d'écraser la colonne existante.
Remarque Comme ci-dessus et à partir de 0.16.0, assign est la meilleure solution. Voir la documentation http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.assign.html#pandas.DataFrame.assign Fonctionne bien pour le type de flux de données où vous n'écrasez pas vos valeurs intermédiaires.
la source
list_of_e
des données pertinentes.df['e'] = list_of_e
la source
tolist()
commande peut être utile.Si la colonne que vous essayez d'ajouter est une variable série, alors:
Cela fonctionne bien même si vous remplacez une colonne existante. Tapez simplement le nouveau_nom_colonnes de la même manière que la colonne que vous souhaitez remplacer. Il écrasera simplement les données de colonne existantes par les nouvelles données de série.
la source
Si le bloc de données et l'objet Series ont le même index ,
pandas.concat
fonctionne également ici:Au cas où ils n'auraient pas le même indice:
la source
Infaillible:
Exemple:
la source
Permettez-moi d'ajouter que, tout comme pour hum3 , cela
.loc
n'a pas résolu le problèmeSettingWithCopyWarning
et j'ai dû y recourirdf.insert()
. Dans mon cas, un faux positif a été généré par une "fausse" indexation de chaînedict['a']['e']
, où se'e'
trouve la nouvelle colonne, etdict['a']
est un DataFrame provenant du dictionnaire.Notez également que si vous savez ce que vous faites, vous pouvez désactiver l'avertissement en utilisant
pd.options.mode.chained_assignment = None
et en utilisant l'une des autres solutions données ici.la source
pour insérer une nouvelle colonne à un emplacement donné (0 <= loc <= quantité de colonnes) dans un bloc de données, utilisez simplement Dataframe.insert:
Par conséquent, si vous souhaitez ajouter la colonne e à la fin d'une trame de données appelée df , vous pouvez utiliser:
La valeur peut être une série, un entier (auquel cas toutes les cellules sont remplies avec cette seule valeur) ou une structure de type tableau
https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.insert.html
la source
Avant d'affecter une nouvelle colonne, si vous avez indexé des données, vous devez trier l'index. Au moins dans mon cas, j'ai dû:
la source
Une chose à noter, cependant, est que si vous le faites
ce sera effectivement une jointure gauche sur le df1.index. Donc, si vous souhaitez avoir un effet de jointure externe , ma solution probablement imparfaite consiste à créer un cadre de données avec des valeurs d'index couvrant l'univers de vos données, puis à utiliser le code ci-dessus. Par exemple,
la source
Je cherchais un moyen général d'ajouter une colonne de
numpy.nan
s à une trame de données sans obtenir le stupideSettingWithCopyWarning
.Parmi les éléments suivants:
numpy
tableau de NaN en ligneJe suis venu avec ceci:
la source
Pour ajouter une nouvelle colonne, «e», au bloc de données existant
la source
Par souci d'exhaustivité - encore une autre solution utilisant la méthode DataFrame.eval () :
Les données:
Solution:
la source
Pour créer une colonne vide
la source
Ce qui suit est ce que j'ai fait ... Mais je suis assez nouveau pour les pandas et vraiment Python en général, donc pas de promesses.
la source
Si vous obtenez le
SettingWithCopyWarning
, une solution simple consiste à copier le DataFrame auquel vous essayez d'ajouter une colonne.la source