панды трехстороннее соединение нескольких фреймов данных на столбцах
У меня есть 3 CSV-файлов. Каждый из них имеет первый столбец (строка) имена людей, в то время как все остальные столбцы в каждой таблице данных являются атрибутами этого человека.
Как я могу "объединить" все три документа CSV, чтобы создать один CSV с каждой строкой, имеющей все атрибуты для каждого уникального значения имени строки человека?
на join()
функция в pandas указывает, что мне нужен мультииндекс, но я смущен тем, что имеет иерархическая схема индексирования чтобы сделать соединение на основе одного индекса.
8 ответов:
предположить импорта:
import pandas as pd
ответ Джона Голта в основном
reduce
операции. Если у меня есть более чем несколько фреймов данных, я бы поместил их в список, подобный этому (сгенерированный с помощью понимания списка или циклов или еще чего-то):dfs = [df0, df1, df2, dfN]
предполагая, что у них есть какой-то общий столбец, например
name
в вашем примере, я бы сделал следующее:df_final = reduce(lambda left,right: pd.merge(left,right,on='name'), dfs)
таким образом, ваш код должен работать с любым количеством таблиц данных, которые вы хотите объединить.
Редактировать 1 Августа 2016 Года: для тех, кто использует Python 3:
reduce
доfunctools
. Поэтому, чтобы использовать эту функцию, вам сначала нужно импортировать этот модуль:from functools import reduce
вы можете попробовать это, если у вас есть 3 фрейма данных
# 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')
альтернативно, как упоминалось cwharland
df1.merge(df2,on='name').merge(df3,on='name')
Это также может быть сделано следующим образом список таблиц данных
df_list
:df = df_list[0] for df_ in df_list[1:]: df = df.merge(df_, on='join_col_name')
или если фреймы данных находятся в объекте генератора (например, для уменьшения потребления памяти):
df = next(df_list) for df_ in df_list: df = df.merge(df_, on='join_col_name')
Это идеальная ситуация для
join
методThe
join
метод построен именно для этих типов ситуаций. Вы можете объединить любое количество фреймов данных вместе с ним. Вызывающий фрейм данных соединяется с индексом коллекции переданных фреймов данных. Для работы с несколькими кадрами данных необходимо поместить соединяющие столбцы в индекс.код будет выглядеть примерно так:
filenames = ['fn1', 'fn2', 'fn3', 'fn4',....] dfs = [pd.read_csv(filename, index_col=index_col) for filename in filenames)] dfs[0].join(dfs[1:])
С данными @zero, вы могли бы сделать это:
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
вот способ объединить словарь фреймов данных, сохраняя имена столбцов в синхронизации со словарем. Также он заполняет недостающие значения, если это необходимо:
это функция для слияния дикт кадров данных
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)
один не нужен мультииндекс для выполнения вступить операции. Нужно просто правильно установить столбец индекса, на котором будут выполняться операции соединения (какая команда
df.set_index('Name')
например)The
join
операция по умолчанию выполняется с индексом. В вашем случае, вы просто должны указать, чтоName
столбец соответствует вашему индексу. Ниже приведен примерA учебник могут быть полезны.
# 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')
есть еще одно решение от панды документация (этого я здесь не вижу),
С помощью
.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
The
ignore_index=True
используется для игнорирования индекса добавленного фрейма данных, заменяя его следующим индексом, доступным в исходном.если есть разные имена столбцов,
Nan
будет введен.
на
python
3.6.3 сpandas
0.22.0 вы также можете использоватьconcat
пока вы устанавливаете в качестве индекса столбцы, которые вы хотите использовать для присоединенияpd.concat( (iDF.set_index('name') for iDF in [df1, df2, df3]), axis=1, join='inner' ).reset_index()
здесь
df1
,df2
иdf3
определяются как ответ Джона Голта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'] )