web-dev-qa-db-fra.com

Comment fusionner un Series et un DataFrame

Si vous êtes venu ici pour rechercher des informations sur comment Fusionner une DataFrame et Series sur l'index, veuillez regarder this réponse .

L'intention initiale du PO était de demander à comment affecter des éléments de série En tant que colonnes à un autre DataFrame. Si vous êtes intéressé à connaître le répondez à cela, regardez le réponse acceptée par EdChum.


Le mieux que je puisse trouver est

df = pd.DataFrame({'a':[1, 2], 'b':[3, 4]})  # see EDIT below
s = pd.Series({'s1':5, 's2':6})

for name in s.index:
    df[name] = s[name]

   a  b  s1  s2
0  1  3   5   6
1  2  4   5   6

Quelqu'un peut-il suggérer une meilleure syntaxe/méthode plus rapide? 

Mes tentatives

df.merge(s)
AttributeError: 'Series' object has no attribute 'columns'

et

df.join(s)
ValueError: Other Series must have a name

EDIT Les deux premières réponses postées ont mis en évidence un problème avec ma question. Veuillez donc utiliser ce qui suit pour construire df:

df = pd.DataFrame({'a':[np.nan, 2, 3], 'b':[4, 5, 6]}, index=[3, 5, 6])

avec le résultat final

    a  b  s1  s2
3 NaN  4   5   6
5   2  5   5   6
6   3  6   5   6
41
Nathan Lloyd

Vous pouvez construire un cadre de données à partir de la série, puis fusionner avec le cadre de données . Vous devez donc spécifier les données en tant que valeurs, les multiplier par la longueur, définir les colonnes sur l'index et définir les paramètres pour left_index et right_index sur True:

In [27]:

df.merge(pd.DataFrame(data = [s.values] * len(s), columns = s.index), left_index=True, right_index=True)
Out[27]:
   a  b  s1  s2
0  1  3   5   6
1  2  4   5   6

EDITdans le cas où vous voulez que l’index de votre df construit de la série utilise l’index du df, vous pouvez alors:

df.merge(pd.DataFrame(data = [s.values] * len(df), columns = s.index, index=df.index), left_index=True, right_index=True)

Cela suppose que les index correspondent à la longueur.

15
EdChum

Mettre à jour
À partir de la version 0.24.0, vous pouvez fusionner DataFrame et Series tant que la série est nommée. 

df.merge(s.rename('new'), left_index=True, right_index=True)
# If series is already named,
# df.merge(s, left_index=True, right_index=True)

De nos jours, vous pouvez simplement convertir la série en DataFrame avec to_frame () . Donc (si vous vous inscrivez sur l'index):

df.merge(s.to_frame(), left_index=True, right_index=True)
106
Nicholas Morley

Voici un moyen:

df.join(pd.DataFrame(s).T).fillna(method='ffill')

Pour décomposer ce qui se passe ici ...

pd.DataFrame(s).T crée un DataFrame à une ligne à partir de s qui ressemble à ceci:

   s1  s2
0   5   6

Ensuite, join concatène ce nouveau cadre avec df:

   a  b  s1  s2
0  1  3   5   6
1  2  4 NaN NaN

Enfin, les valeurs NaN de l'index 1 sont remplies avec les valeurs précédentes de la colonne en utilisant fillna avec l'argument forward-fill (ffill):

   a  b  s1  s2
0  1  3   5   6
1  2  4   5   6

Pour éviter d'utiliser fillna, il est possible d'utiliser pd.concat pour répéter les lignes du DataFrame construit à partir de s. Dans ce cas, la solution générale est la suivante:

df.join(pd.concat([pd.DataFrame(s).T] * len(df), ignore_index=True))

Voici une autre solution pour relever le défi de l'indexation posé dans la question modifiée:

df.join(pd.DataFrame(s.repeat(len(df)).values.reshape((len(df), -1), order='F'), 
        columns=s.index, 
        index=df.index))

s est transformé en un DataFrame en répétant les valeurs et en remodelant (en spécifiant l'ordre 'Fortran'), ainsi qu'en transmettant les noms de colonnes et l'index appropriés. Ce nouveau DataFrame est ensuite associé à df.

3
Alex Riley

Si je pouvais suggérer de configurer vos cadres de données comme ceci (auto-indexation):

df = pd.DataFrame({'a':[np.nan, 1, 2], 'b':[4, 5, 6]})

alors vous pouvez configurer vos valeurs s1 et s2 ainsi (en utilisant shape () pour renvoyer le nombre de lignes de df):

s = pd.DataFrame({'s1':[5]*df.shape[0], 's2':[6]*df.shape[0]})

alors le résultat que vous voulez est facile:

display (df.merge(s, left_index=True, right_index=True))

Sinon, ajoutez simplement les nouvelles valeurs à votre image de base de données: 

df = pd.DataFrame({'a':[nan, 1, 2], 'b':[4, 5, 6]})
df['s1']=5
df['s2']=6
display(df)

Les deux reviennent:

     a  b  s1  s2
0  NaN  4   5   6
1  1.0  5   5   6
2  2.0  6   5   6

Si vous avez une autre liste de données (au lieu d'une seule valeur à appliquer) et que vous savez qu'elle est dans le même ordre que df, par exemple:

s1=['a','b','c']

alors vous pouvez attacher ceci de la même manière:

df['s1']=s1

résultats:

     a  b s1
0  NaN  4  a
1  1.0  5  b
2  2.0  6  c
0
James

Vous pouvez facilement définir une colonne pandas.DataFrame sur une constante. Cette constante peut être un int tel que dans votre exemple. Si la colonne que vous spécifiez ne figure pas dans le df, alors les pandas créeront une nouvelle colonne avec le nom que vous spécifiez. Donc, après la construction de votre cadre de données (à partir de votre question):

df = pd.DataFrame({'a':[np.nan, 2, 3], 'b':[4, 5, 6]}, index=[3, 5, 6])

Vous pouvez juste courir:

df['s1'], df['s2'] = 5, 6

Vous pouvez écrire une boucle ou une compréhension pour que cela soit le cas pour tous les éléments d'une liste de n-uplets, ou de clés et de valeurs dans un dictionnaire, en fonction de la manière dont vos données réelles sont stockées.

0
Alex