web-dev-qa-db-de.com

pandas Dreiwegeverbindung mehrerer Datenrahmen in Spalten

Ich habe 3 CSV-Dateien. Jede hat die erste Spalte als (Zeichenfolge-) Namen von Personen, während alle anderen Spalten in jedem Datenrahmen Attribute dieser Person sind.

Wie kann ich alle drei CSV-Dokumente "zusammenfügen", um eine einzelne CSV mit jeder Zeile zu erstellen, die alle Attribute für jeden eindeutigen Wert des Zeichenfolgennamens der Person aufweist?

Die join() -Funktion in pandas) gibt an, dass ich einen Multiindex benötige, aber ich bin verwirrt darüber, was ein hierarchisches Indexschema damit zu tun hat, einen Join basierend auf einem einzelnen Index zu erstellen .

148
lollercoaster

Angenommene Einfuhren:

import pandas as pd

John Galts Antwort ist im Grunde eine reduce Operation. Wenn ich mehr als eine Handvoll Datenrahmen habe, würde ich sie in eine Liste wie diese einfügen (generiert über Listenverständnisse oder Schleifen oder so weiter):

dfs = [df0, df1, df2, dfN]

Angenommen, sie haben eine gemeinsame Spalte wie name in Ihrem Beispiel, dann würde ich Folgendes tun:

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

Auf diese Weise sollte Ihr Code mit einer beliebigen Anzahl von Datenrahmen funktionieren, die Sie zusammenführen möchten.

Edit 1. August 2016 : Für diejenigen, die Python 3: reduce verwenden, wurde in verschoben functools. Um diese Funktion nutzen zu können, müssen Sie zuerst dieses Modul importieren:

from functools import reduce
396
Kit

Sie können dies versuchen, wenn Sie 3 Datenrahmen haben

# 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')

alternativ, wie von cwharland erwähnt

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

Dies ist eine ideale Situation für die Methode join

Die join -Methode wurde genau für diese Art von Situationen entwickelt. Sie können damit eine beliebige Anzahl von DataFrames verbinden. Der aufrufende DataFrame verbindet sich mit dem Index der Auflistung der übergebenen DataFrames. Um mit mehreren DataFrames zu arbeiten, müssen Sie die Verknüpfungsspalten in den Index einfügen.

Der Code würde ungefähr so ​​aussehen:

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

Mit den Daten von @ zero können Sie dies tun:

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

Dies kann auch wie folgt für eine Liste von Datenrahmen df_list:

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

oder wenn sich die Datenrahmen in einem Generatorobjekt befinden (z. B. um den Speicherverbrauch zu verringern):

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

In python 3.6.3 mit pandas 0.22.0 können Sie auch concat verwenden, solange Sie als Index die Spalten festlegen, die Sie für die Verknüpfung verwenden möchten

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

wo df1, df2, und df3 sind wie in John Galts Antwort definiert

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

Hier ist eine Methode zum Zusammenführen eines Datenrahmenwörterbuchs, wobei die Spaltennamen mit dem Wörterbuch synchron bleiben. Außerdem werden fehlende Werte bei Bedarf ergänzt:

Dies ist die Funktion zum Zusammenführen eines Diktats von Datenrahmen

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, lass uns Daten generieren und dies testen:

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

Man braucht keinen Multiindex, um Join Operationen auszuführen. Man muss nur die Indexspalte richtig einstellen, für die die Verknüpfungsoperationen ausgeführt werden sollen (welcher Befehl df.set_index('Name') zum Beispiel)

Die Operation join wird standardmäßig für den Index ausgeführt. In Ihrem Fall müssen Sie nur angeben, dass die Spalte Name Ihrem Index entspricht. Unten ist ein Beispiel

Ein Tutorial kann nützlich sein.

# 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

Es gibt eine andere Lösung aus der Pandadokumentation (die ich hier nicht sehe),

mit dem .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

Das ignore_index=True wird verwendet, um den Index des angehängten Datenrahmens zu ignorieren und durch den nächsten im Quellindex verfügbaren Index zu ersetzen.

Wenn es unterschiedliche Spaltennamen gibt, wird Nan eingeführt.

2
Sylhare

Einfache Lösung:

Wenn die Spaltennamen ähnlich sind:

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

Wenn die Spaltennamen unterschiedlich sind:

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