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 .
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
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')
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
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')
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']
)
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:
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)
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)
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')
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.
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'})