web-dev-qa-db-fra.com

pandas trois voies joignant plusieurs images sur des colonnes

J'ai 3 fichiers CSV. Chacune a la première colonne en tant que (chaîne) noms de personnes, tandis que toutes les autres colonnes de chaque cadre de données sont des attributs de cette personne.

Comment puis-je "joindre" les trois documents CSV pour créer un seul fichier CSV, chaque ligne ayant tous les attributs pour chaque valeur unique du nom de chaîne de la personne?

La fonction join() dans pandas indique que j'ai besoin d'un multi-index, mais je ne comprends pas ce qu'un schéma d'indexation hiérarchique doit faire pour créer une jointure basée sur un seul index.

148
lollercoaster

Importations présumées:

import pandas as pd

La réponse de John Galt est fondamentalement une opération reduce. Si j'ai plus d'une poignée de trames de données, je les mettrais dans une liste comme celle-ci (générée via des compréhensions de liste, des boucles ou autres):

dfs = [df0, df1, df2, dfN]

En supposant qu'ils aient une colonne commune, comme name dans votre exemple, je procéderais comme suit:

df_final = reduce(lambda left,right: pd.merge(left,right,on='name'), dfs)

De cette façon, votre code doit fonctionner avec le nombre de trames de données que vous souhaitez fusionner.

Edit August 1, 2016 : Pour ceux qui utilisent Python 3: reduce a été déplacé dans functools . Donc, pour utiliser cette fonction, vous devez d'abord importer ce module:

from functools import reduce
396
Kit

Vous pouvez essayer ceci si vous avez 3 cadres de données

# Merge multiple dataframes
df1 = pd.DataFrame(np.array([
    ['a', 5, 9],
    ['b', 4, 61],
    ['c', 24, 9]]),
    columns=['name', 'attr11', 'attr12'])
df2 = pd.DataFrame(np.array([
    ['a', 5, 19],
    ['b', 14, 16],
    ['c', 4, 9]]),
    columns=['name', 'attr21', 'attr22'])
df3 = pd.DataFrame(np.array([
    ['a', 15, 49],
    ['b', 4, 36],
    ['c', 14, 9]]),
    columns=['name', 'attr31', 'attr32'])

pd.merge(pd.merge(df1,df2,on='name'),df3,on='name')

alternativement, comme mentionné par cwharland

df1.merge(df2,on='name').merge(df3,on='name')
89
Zero

C'est une situation idéale pour la méthode join

La méthode join est construite exactement pour ce type de situation. Vous pouvez joindre autant de DataFrames que vous le souhaitez. Le DataFrame appelant se joint à l'index de la collection de DataFrames transmis. Pour utiliser plusieurs DataFrames, vous devez placer les colonnes de jointure dans l'index.

Le code ressemblerait à ceci:

filenames = ['fn1', 'fn2', 'fn3', 'fn4',....]
dfs = [pd.read_csv(filename, index_col=index_col) for filename in filenames)]
dfs[0].join(dfs[1:])

Avec les données de @ zero, vous pouvez faire ceci:

df1 = pd.DataFrame(np.array([
    ['a', 5, 9],
    ['b', 4, 61],
    ['c', 24, 9]]),
    columns=['name', 'attr11', 'attr12'])
df2 = pd.DataFrame(np.array([
    ['a', 5, 19],
    ['b', 14, 16],
    ['c', 4, 9]]),
    columns=['name', 'attr21', 'attr22'])
df3 = pd.DataFrame(np.array([
    ['a', 15, 49],
    ['b', 4, 36],
    ['c', 14, 9]]),
    columns=['name', 'attr31', 'attr32'])

dfs = [df1, df2, df3]
dfs = [df.set_index('name') for df in dfs]
dfs[0].join(dfs[1:])

     attr11 attr12 attr21 attr22 attr31 attr32
name                                          
a         5      9      5     19     15     49
b         4     61     14     16      4     36
c        24      9      4      9     14      9
49
Ted Petrou

Cela peut également être fait comme suit pour une liste de trames de données df_list:

df = df_list[0]
for df_ in df_list[1:]:
    df = df.merge(df_, on='join_col_name')

ou si les trames de données se trouvent dans un objet générateur (par exemple, pour réduire la consommation de mémoire):

df = next(df_list)
for df_ in df_list:
    df = df.merge(df_, on='join_col_name')
16
AlexG

Dans python 3.6.3 avec pandas 0.22.0, vous pouvez également utiliser concat tant que vous définissez comme index les colonnes que vous souhaitez utiliser pour la jointure.

pd.concat(
    (iDF.set_index('name') for iDF in [df1, df2, df3]),
    axis=1, join='inner'
).reset_index()

df1, df2 et df3 sont définis comme suit réponse de John Galt

import pandas as pd
df1 = pd.DataFrame(np.array([
    ['a', 5, 9],
    ['b', 4, 61],
    ['c', 24, 9]]),
    columns=['name', 'attr11', 'attr12']
)
df2 = pd.DataFrame(np.array([
    ['a', 5, 19],
    ['b', 14, 16],
    ['c', 4, 9]]),
    columns=['name', 'attr21', 'attr22']
)
df3 = pd.DataFrame(np.array([
    ['a', 15, 49],
    ['b', 4, 36],
    ['c', 14, 9]]),
    columns=['name', 'attr31', 'attr32']
)
8
Igor Fobia

Voici une méthode pour fusionner un dictionnaire de trames de données tout en maintenant les noms des colonnes en synchronisation avec le dictionnaire. En outre, il remplit les valeurs manquantes si nécessaire:

C'est la fonction pour fusionner un dict de trames de données

def MergeDfDict(dfDict, onCols, how='outer', naFill=None):
  keys = dfDict.keys()
  for i in range(len(keys)):
    key = keys[i]
    df0 = dfDict[key]
    cols = list(df0.columns)
    valueCols = list(filter(lambda x: x not in (onCols), cols))
    df0 = df0[onCols + valueCols]
    df0.columns = onCols + [(s + '_' + key) for s in valueCols] 

    if (i == 0):
      outDf = df0
    else:
      outDf = pd.merge(outDf, df0, how=how, on=onCols)   

  if (naFill != None):
    outDf = outDf.fillna(naFill)

  return(outDf)

OK, permet de générer des données et de tester ceci:

def GenDf(size):
  df = pd.DataFrame({'categ1':np.random.choice(a=['a', 'b', 'c', 'd', 'e'], size=size, replace=True),
                      'categ2':np.random.choice(a=['A', 'B'], size=size, replace=True), 
                      'col1':np.random.uniform(low=0.0, high=100.0, size=size), 
                      'col2':np.random.uniform(low=0.0, high=100.0, size=size)
                      })
  df = df.sort_values(['categ2', 'categ1', 'col1', 'col2'])
  return(df)


size = 5
dfDict = {'US':GenDf(size), 'IN':GenDf(size), 'GER':GenDf(size)}   
MergeDfDict(dfDict=dfDict, onCols=['categ1', 'categ2'], how='outer', naFill=0)
4
rz1317

On n'a pas besoin d'un multi-index pour effectuer des opérations join . Il suffit de définir correctement la colonne d’index sur laquelle effectuer les opérations de jointure (commande df.set_index('Name') par exemple)

L'opération join est effectuée par défaut sur l'index. Dans votre cas, il vous suffit de spécifier que la colonne Name correspond à votre index. Ci-dessous un exemple

Un tutoriel peut être utile.

# Simple example where dataframes index are the name on which to perform the join operations
import pandas as pd
import numpy as np
name = ['Sophia' ,'Emma' ,'Isabella' ,'Olivia' ,'Ava' ,'Emily' ,'Abigail' ,'Mia']
df1 = pd.DataFrame(np.random.randn(8, 3), columns=['A','B','C'], index=name)
df2 = pd.DataFrame(np.random.randn(8, 1), columns=['D'],         index=name)
df3 = pd.DataFrame(np.random.randn(8, 2), columns=['E','F'],     index=name)
df = df1.join(df2)
df = df.join(df3)

# If you a 'Name' column that is not the index of your dataframe, one can set this column to be the index
# 1) Create a column 'Name' based on the previous index
df1['Name']=df1.index
# 1) Select the index from column 'Name'
df1=df1.set_index('Name')

# If indexes are different, one may have to play with parameter how
gf1 = pd.DataFrame(np.random.randn(8, 3), columns=['A','B','C'], index=range(8))
gf2 = pd.DataFrame(np.random.randn(8, 1), columns=['D'], index=range(2,10))
gf3 = pd.DataFrame(np.random.randn(8, 2), columns=['E','F'], index=range(4,12))

gf = gf1.join(gf2, how='outer')
gf = gf.join(gf3, how='outer')
4

Il y a une autre solution dans documentation sur les pandas (que je ne vois pas ici),

en utilisant le .append

>>> df = pd.DataFrame([[1, 2], [3, 4]], columns=list('AB'))
   A  B
0  1  2
1  3  4
>>> df2 = pd.DataFrame([[5, 6], [7, 8]], columns=list('AB'))
   A  B
0  5  6
1  7  8
>>> df.append(df2, ignore_index=True)
   A  B
0  1  2
1  3  4
2  5  6
3  7  8

Le ignore_index=True est utilisé pour ignorer l'index du cadre de données ajouté, en le remplaçant par le prochain index disponible dans le source.

S'il existe différents noms de colonne, Nan sera introduit.

2
Sylhare

Solution simple:

Si les noms de colonne sont similaires:

 df1.merge(df2,on='col_name').merge(df3,on='col_name')

Si les noms de colonne sont différents:

df1.merge(df2,left_on='col_name1', right_on='col_name2').merge(df3,left_on='col_name1', right_on='col_name3').drop(columns=['col_name2', 'col_name3']).rename(columns={'col_name1':'col_name'})
1
Gil Baggio