Ajout d'une nouvelle colonne à la base de données existante dans les pandas de Python

j'ai la base de données indexée suivante avec des colonnes nommées et des lignes non - continues:

          a         b         c         d
2  0.671399  0.101208 -0.181532  0.241273
3  0.446172 -0.243316  0.051767  1.577318
5  0.614758  0.075793 -0.451460 -0.012493

j'aimerais ajouter une nouvelle colonne, 'e' , à la base de données existante et je ne veux rien changer dans la base de données (c.-à-d., la nouvelle colonne a toujours la même longueur que la base de données).

0   -0.335485
1   -1.166658
2   -0.385571
dtype: float64

j'ai essayé différentes versions de join , append , merge , mais je n'ai pas eu le résultat voulu, seulement des erreurs au plus. Comment puis-je ajouter la colonne e à l'exemple ci-dessus?

616
demandé sur Brad Solomon 2012-09-23 23:00:01

21 réponses

utiliser les index df1 originaux pour créer la série:

df1['e'] = Series(np.random.randn(sLength), index=df1.index)


modifier 2015

Certains ont rapporté avoir le SettingWithCopyWarning avec ce code.

Cependant, le code fonctionne toujours parfaitement avec la version actuelle de pandas 0.16.1.

>>> 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'] = p.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'

le SettingWithCopyWarning vise à informer d'une cession éventuellement invalide sur une copie de la Dataframe. Il ne dit pas nécessairement que vous l'avez mal fait (il peut déclencher des faux positifs) mais de 0.13.0 il vous fait savoir qu'il existe des méthodes plus adéquates pour le même but. Ensuite, si vous obtenez l'avertissement, il suffit de suivre son conseil: essayer d'utiliser .loc[row_index, col_indexer] = valeur à la place de

>>> df1.loc[:,'f'] = p.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 comme décrit dans pandas docs



Edit 2017

comme indiqué dans les commentaires et par @Alexander, actuellement la meilleure méthode pour ajouter les valeurs d'une série comme une nouvelle colonne d'une base de données pourrait être en utilisant assign :

df1 = df1.assign(e=p.Series(np.random.randn(sLength)).values)
702
répondu joaquin 2017-01-07 12:07:59

c'est la façon simple d'ajouter une nouvelle colonne: df['e'] = e

151
répondu Kathirmani Sukumar 2016-12-10 06:53:58

je voudrais ajouter une nouvelle colonne, "e", à la base de données existante et ne rien changer dans la base de données. (La série a toujours la même longueur qu'une base de données.)

je suppose que les valeurs de l'indice de e correspondent à celles de df1 .

la façon la plus facile de lancer une nouvelle colonne appelée e , et lui attribuer les valeurs de votre série e :

df['e'] = e.values

assign (Pandas 0.16.0+)

à partir de Pandas 0.16.0, vous pouvez également utiliser assign , qui assigne de nouvelles colonnes à une base de données et renvoie un nouvel objet (une copie) avec toutes les colonnes originales en plus des nouvelles.

df1 = df1.assign(e=e.values)

comme dans cet exemple (qui inclut aussi le code source de la fonction assign ), vous pouvez aussi inclure plus d'une seule colonne:

df = pd.DataFrame({'a': [1, 2], 'b': [3, 4]})
>>> df.assign(mean_a=df.a.mean(), mean_b=df.b.mean())
   a  b  mean_a  mean_b
0  1  3     1.5     3.5
1  2  4     1.5     3.5

dans le contexte de votre exemple:

np.random.seed(0)
df1 = pd.DataFrame(np.random.randn(10, 4), columns=['a', 'b', 'c', 'd'])
mask = df1.applymap(lambda x: x <-0.7)
df1 = df1[-mask.any(axis=1)]
sLength = len(df1['a'])
e = pd.Series(np.random.randn(sLength))

>>> df1
          a         b         c         d
0  1.764052  0.400157  0.978738  2.240893
2 -0.103219  0.410599  0.144044  1.454274
3  0.761038  0.121675  0.443863  0.333674
7  1.532779  1.469359  0.154947  0.378163
9  1.230291  1.202380 -0.387327 -0.302303

>>> e
0   -1.048553
1   -1.420018
2   -1.706270
3    1.950775
4   -0.509652
dtype: float64

df1 = df1.assign(e=e.values)

>>> df1
          a         b         c         d         e
0  1.764052  0.400157  0.978738  2.240893 -1.048553
2 -0.103219  0.410599  0.144044  1.454274 -1.420018
3  0.761038  0.121675  0.443863  0.333674 -1.706270
7  1.532779  1.469359  0.154947  0.378163  1.950775
9  1.230291  1.202380 -0.387327 -0.302303 -0.509652

la description de cette nouvelle caractéristique au moment de son introduction se trouve ici .

97
répondu Alexander 2017-05-23 12:18:32

faire ceci directement via NumPy sera le plus efficace:

df1['e'] = np.random.randn(sLength)

Remarque que mon ancien (très ancien) suggestion a été d'utiliser des map (ce qui est beaucoup plus lent):

df1['e'] = df1['a'].map(lambda x: np.random.random())
35
répondu Andy Hayden 2015-10-20 13:05:01

Il semble que ces derniers Pandas versions de la façon est d'utiliser df.attribuer :

df1 = df1.assign(e=np.random.randn(sLength))

il ne produit pas SettingWithCopyWarning .

29
répondu Mikhail Korobov 2018-10-03 07:39:25

assignation de colonne Super simple

une base de données pandas est implémentée comme un dict ordonné de colonnes.

cela signifie que le __getitem__ [] peut non seulement être utilisé pour obtenir une certaine colonne, mais __setitem__ [] = peut être utilisé pour assigner une nouvelle colonne.

par exemple, cette base de données peut avoir une colonne ajoutée en utilisant simplement le [] accessor

    size      name color
0    big      rose   red
1  small    violet  blue
2  small     tulip   red
3  small  harebell  blue

df['protected'] = ['no', 'no', 'no', 'yes']

    size      name color protected
0    big      rose   red        no
1  small    violet  blue        no
2  small     tulip   red        no
3  small  harebell  blue       yes

Notez que cela fonctionne même si l'index du dataframe est éteint.

df.index = [3,2,1,0]
df['protected'] = ['no', 'no', 'no', 'yes']
    size      name color protected
3    big      rose   red        no
2  small    violet  blue        no
1  small     tulip   red        no
0  small  harebell  blue       yes

[]= est le chemin à parcourir, mais attention!

cependant, si vous avez un pd.Series et que vous essayez de l'affecter à une base de données où les index sont désactivés, vous allez avoir des problèmes. Voir Exemple:

df['protected'] = pd.Series(['no', 'no', 'no', 'yes'])
    size      name color protected
3    big      rose   red       yes
2  small    violet  blue        no
1  small     tulip   red        no
0  small  harebell  blue        no

c'est parce qu'un pd.Series par défaut a un index énuméré de 0 à N. Et la méthode pandas [] = tente être "smart"

Ce qui se passe.

lorsque vous utilisez la méthode pandas [] = effectue tranquillement une jointure externe ou une fusion externe en utilisant l'index du dataframe de la main gauche et l'index de la main droite série. df['column'] = series

note

cela provoque rapidement la dissonance cognitive, depuis la méthode []= est d'essayer de faire beaucoup de choses différentes selon l'entrée, et le résultat ne peut pas être prédit à moins que vous juste savoir comment fonctionne pandas. Je conseillerais donc de ne pas utiliser le []= dans les bases de code, mais lors de l'exploration de données dans un carnet, c'est très bien.

contourner le problème

si vous avez un pd.Series et que vous voulez qu'il soit assigné de haut en bas, ou si vous codez le code productif et vous n'êtes pas sûr de l'ordre d'index, il vaut la peine de sauvegarder pour ce genre de problème.

, Vous pouvez abattu le pd.Series à un np.ndarray ou un list , cela fera l'affaire.

df['protected'] = pd.Series(['no', 'no', 'no', 'yes']).values

ou

df['protected'] = list(pd.Series(['no', 'no', 'no', 'yes']))

Mais ce n'est pas très explicite.

un codeur peut venir et dire"hé, ça a l'air redondant, je vais juste optimiser ça".

voie explicite

définir l'index du pd.Series comme étant l'index du df est explicite.

df['protected'] = pd.Series(['no', 'no', 'no', 'yes'], index=df.index)

ou plus réaliste, vous avez probablement un pd.Series déjà disponible.

protected_series = pd.Series(['no', 'no', 'no', 'yes'])
protected_series.index = df.index

3     no
2     no
1     no
0    yes

peut maintenant être attribué

df['protected'] = protected_series

    size      name color protected
3    big      rose   red        no
2  small    violet  blue        no
1  small     tulip   red        no
0  small  harebell  blue       yes

Alternative avec df.reset_index()

puisque la dissonance de l'index est le problème, si vous sentez que l'indice de la dataframe devrait dictent pas les choses, vous pouvez simplement supprimer l'index, cela devrait être plus rapide, mais il n'est pas très propre, depuis votre fonction probablement fait deux choses.

df.reset_index(drop=True)
protected_series.reset_index(drop=True)
df['protected'] = protected_series

    size      name color protected
0    big      rose   red        no
1  small    violet  blue        no
2  small     tulip   red        no
3  small  harebell  blue       yes

Note sur df.assign

alors que df.assign rend plus explicite ce que vous faites, il a en fait tous les mêmes problèmes que le ci-dessus []=

df.assign(protected=pd.Series(['no', 'no', 'no', 'yes']))
    size      name color protected
3    big      rose   red       yes
2  small    violet  blue        no
1  small     tulip   red        no
0  small  harebell  blue        no

faites juste attention avec df.assign que votre colonne ne s'appelle pas self . Il va provoquer des erreurs. Cela fait df.assign odeur , car il ya ce genre d'artefacts dans la fonction.

df.assign(self=pd.Series(['no', 'no', 'no', 'yes'])
TypeError: assign() got multiple values for keyword argument 'self'

vous pouvez dire, "Eh bien, je ne vais pas utiliser self alors". Mais qui sait comment cette fonction change à l'avenir pour soutenir de nouveaux arguments. Peut-être que votre nom de colonne sera un argument dans une nouvelle mise à jour de pandas, à l'origine des problèmes avec la mise à niveau.

20
répondu firelynx 2017-04-03 08:59:22

si vous voulez définir la nouvelle colonne entière à une valeur de base initiale (par exemple None ), vous pouvez faire ceci: df1['e'] = None

cela assignerait en fait le type" object " à la cellule. Donc plus tard, vous êtes libre de mettre des types de données complexes, comme list, dans des cellules individuelles.

16
répondu digdug 2017-12-18 20:51:00

j'ai eu le redoutable 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:

df.insert(len(df.columns), 'e', pd.Series(np.random.randn(sLength),  index=df.index))

cela fonctionnait très bien pour insérer la colonne à la fin. Je ne sais pas si c'est la 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 aspect de l'index.

Note . Que cela ne fonctionne qu'une fois et donnera un message d'erreur si vous essayez d'écraser et la colonne existante.

Note Comme ci-dessus et de 0.16.0 attribuer 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 votre intermédiaire valeur.

15
répondu hum3 2016-10-21 11:32:43

infaillible:

df.loc[:, 'NewCol'] = 'New_Val'

exemple:

df = pd.DataFrame(data=np.random.randn(20, 4), columns=['A', 'B', 'C', 'D'])

df

           A         B         C         D
0  -0.761269  0.477348  1.170614  0.752714
1   1.217250 -0.930860 -0.769324 -0.408642
2  -0.619679 -1.227659 -0.259135  1.700294
3  -0.147354  0.778707  0.479145  2.284143
4  -0.529529  0.000571  0.913779  1.395894
5   2.592400  0.637253  1.441096 -0.631468
6   0.757178  0.240012 -0.553820  1.177202
7  -0.986128 -1.313843  0.788589 -0.707836
8   0.606985 -2.232903 -1.358107 -2.855494
9  -0.692013  0.671866  1.179466 -1.180351
10 -1.093707 -0.530600  0.182926 -1.296494
11 -0.143273 -0.503199 -1.328728  0.610552
12 -0.923110 -1.365890 -1.366202 -1.185999
13 -2.026832  0.273593 -0.440426 -0.627423
14 -0.054503 -0.788866 -0.228088 -0.404783
15  0.955298 -1.430019  1.434071 -0.088215
16 -0.227946  0.047462  0.373573 -0.111675
17  1.627912  0.043611  1.743403 -0.012714
18  0.693458  0.144327  0.329500 -0.655045
19  0.104425  0.037412  0.450598 -0.923387


df.drop([3, 5, 8, 10, 18], inplace=True)

df

           A         B         C         D
0  -0.761269  0.477348  1.170614  0.752714
1   1.217250 -0.930860 -0.769324 -0.408642
2  -0.619679 -1.227659 -0.259135  1.700294
4  -0.529529  0.000571  0.913779  1.395894
6   0.757178  0.240012 -0.553820  1.177202
7  -0.986128 -1.313843  0.788589 -0.707836
9  -0.692013  0.671866  1.179466 -1.180351
11 -0.143273 -0.503199 -1.328728  0.610552
12 -0.923110 -1.365890 -1.366202 -1.185999
13 -2.026832  0.273593 -0.440426 -0.627423
14 -0.054503 -0.788866 -0.228088 -0.404783
15  0.955298 -1.430019  1.434071 -0.088215
16 -0.227946  0.047462  0.373573 -0.111675
17  1.627912  0.043611  1.743403 -0.012714
19  0.104425  0.037412  0.450598 -0.923387

df.loc[:, 'NewCol'] = 0

df
           A         B         C         D  NewCol
0  -0.761269  0.477348  1.170614  0.752714       0
1   1.217250 -0.930860 -0.769324 -0.408642       0
2  -0.619679 -1.227659 -0.259135  1.700294       0
4  -0.529529  0.000571  0.913779  1.395894       0
6   0.757178  0.240012 -0.553820  1.177202       0
7  -0.986128 -1.313843  0.788589 -0.707836       0
9  -0.692013  0.671866  1.179466 -1.180351       0
11 -0.143273 -0.503199 -1.328728  0.610552       0
12 -0.923110 -1.365890 -1.366202 -1.185999       0
13 -2.026832  0.273593 -0.440426 -0.627423       0
14 -0.054503 -0.788866 -0.228088 -0.404783       0
15  0.955298 -1.430019  1.434071 -0.088215       0
16 -0.227946  0.047462  0.373573 -0.111675       0
17  1.627912  0.043611  1.743403 -0.012714       0
19  0.104425  0.037412  0.450598 -0.923387       0
7
répondu K88 2017-04-12 11:22:03

si la colonne que vous essayez d'ajouter est une variable de série alors juste:

df["new_columns_name"]=series_variable_name #this will do it for you

Cela fonctionne bien, même si vous remplacez une colonne existante.il suffit de taper new_columns_name de la même façon que la colonne que vous voulez remplacer.Il va juste écraser les données de colonne existantes avec les nouvelles données de série.

7
répondu Akshay Singhvi 2017-11-03 10:44:11

permettez-moi juste d'ajouter que, tout comme pour hum3 , .loc n'a pas résolu le SettingWithCopyWarning et j'ai dû recourir à df.insert() . Dans mon cas, false positive a été généré par "faux" Chaîne d'indexation dict['a']['e'] , où 'e' est la nouvelle colonne, et dict['a'] est une base de données provenant du dictionnaire.

notez aussi que si vous savez ce que vous faites, vous pouvez changer l'avertissement en utilisant pd.options.mode.chained_assignment = None et que d'utiliser l'un de l'autre les solutions données ici.

6
répondu kkumer 2017-05-23 11:47:36

si le cadre de données et L'objet de série ont le même index , pandas.concat travaille aussi ici:

import pandas as pd
df
#          a            b           c           d
#0  0.671399     0.101208   -0.181532    0.241273
#1  0.446172    -0.243316    0.051767    1.577318
#2  0.614758     0.075793   -0.451460   -0.012493

e = pd.Series([-0.335485, -1.166658, -0.385571])    
e
#0   -0.335485
#1   -1.166658
#2   -0.385571
#dtype: float64

# here we need to give the series object a name which converts to the new  column name 
# in the result
df = pd.concat([df, e.rename("e")], axis=1)
df

#          a            b           c           d           e
#0  0.671399     0.101208   -0.181532    0.241273   -0.335485
#1  0.446172    -0.243316    0.051767    1.577318   -1.166658
#2  0.614758     0.075793   -0.451460   -0.012493   -0.385571

dans le cas où ils n'ont pas le même index:

e.index = df.index
df = pd.concat([df, e.rename("e")], axis=1)
6
répondu Psidom 2017-04-07 01:46:08
  1. créez D'abord la liste_of_e d'un python qui contient des données pertinentes.
  2. utilisez ceci: DF['e'] = list_of_f
6
répondu Sumit Pokhrel 2018-07-22 11:54:49

avant d'attribuer une nouvelle colonne, si vous avez des données indexées, vous devez trier l'index. Au moins dans mon cas j'ai dû:

data.set_index(['index_column'], inplace=True)
"if index is unsorted, assignment of a new column will fail"        
data.sort_index(inplace = True)
data.loc['index_value1', 'column_y'] = np.random.randn(data.loc['index_value1', 'column_x'].shape[0])
5
répondu Dima Lituiev 2015-06-16 20:27:15

une chose à noter, cependant ,est que si vous faites

df1['e'] = Series(np.random.randn(sLength), index=df1.index)

ce sera effectivement un gauche rejoindre sur le df1.index. Donc, si vous voulez avoir un externe join effect, ma solution probablement imparfaite est de créer une base de données avec des valeurs d'index couvrant l'univers de vos données, et puis utiliser le code ci-dessus. Par exemple,

data = pd.DataFrame(index=all_possible_values)
df1['e'] = Series(np.random.randn(sLength), index=df1.index)
5
répondu WillZ 2015-10-20 13:05:50

pour ajouter une nouvelle colonne, "e", à la base de données existante

 df1.loc[:,'e'] = Series(np.random.randn(sLength))
4
répondu Chirag 2016-12-04 21:50:29

je cherchais un moyen général d'ajouter une colonne de numpy.nan s à une base de données sans obtenir le muet SettingWithCopyWarning .

de ce qui suit:

  • les réponses ici
  • cette question sur la transmission d'une variable comme argument mot-clé
  • cette méthode pour la génération d'un numpy tableau de NaNs-ligne

j'ai trouvé ceci:

col = 'column_name'
df = df.assign(**{col:numpy.full(len(df), numpy.nan)})
4
répondu ryanjdillon 2017-05-23 12:26:42

pour des raisons d'exhaustivité - encore une autre solution utilisant DataFrame.eval() la méthode:

Data:

In [44]: e
Out[44]:
0    1.225506
1   -1.033944
2   -0.498953
3   -0.373332
4    0.615030
5   -0.622436
dtype: float64

In [45]: df1
Out[45]:
          a         b         c         d
0 -0.634222 -0.103264  0.745069  0.801288
4  0.782387 -0.090279  0.757662 -0.602408
5 -0.117456  2.124496  1.057301  0.765466
7  0.767532  0.104304 -0.586850  1.051297
8 -0.103272  0.958334  1.163092  1.182315
9 -0.616254  0.296678 -0.112027  0.679112

Solution:

In [46]: df1.eval("e = @e.values", inplace=True)

In [47]: df1
Out[47]:
          a         b         c         d         e
0 -0.634222 -0.103264  0.745069  0.801288  1.225506
4  0.782387 -0.090279  0.757662 -0.602408 -1.033944
5 -0.117456  2.124496  1.057301  0.765466 -0.498953
7  0.767532  0.104304 -0.586850  1.051297 -0.373332
8 -0.103272  0.958334  1.163092  1.182315  0.615030
9 -0.616254  0.296678 -0.112027  0.679112 -0.622436
4
répondu MaxU 2017-03-14 21:49:44

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.

df = pd.DataFrame([[1, 2], [3, 4], [5,6]], columns=list('AB'))

newCol = [3,5,7]
newName = 'C'

values = np.insert(df.values,df.shape[1],newCol,axis=1)
header = df.columns.values.tolist()
header.append(newName)

df = pd.DataFrame(values,columns=header)
3
répondu Devin Charles 2015-10-20 13:07:47

Si vous obtenez le SettingWithCopyWarning , une solution facile est de copier le DataFrame vous essayez d'ajouter une colonne.

df = df.copy()
df['col_name'] = values
3
répondu fredcallaway 2016-03-07 04:00:33

les voies les plus faciles: -

data ['new_col'] = list_of_values

"151900920 des données".loc [:, 'new_col'] = list_of_values

1
répondu Abhishek 2018-09-08 05:17:14