development

열에서 여러 데이터 프레임을 결합하는 팬더 3 방향

big-blog 2020. 6. 8. 07:58
반응형

열에서 여러 데이터 프레임을 결합하는 팬더 3 방향


CSV 파일이 3 개 있습니다. 각각은 사람의 (문자열) 이름으로 첫 번째 열을 갖는 반면, 각 데이터 프레임의 다른 모든 열은 해당 개인의 속성입니다.

세 개의 CSV 문서를 모두 "결합"하여 각 행에 개인 문자열 이름의 각 고유 값에 대한 모든 속성이있는 단일 CSV를 만들 수 있습니까?

join()pandas 함수는 다중 인덱스가 필요하다는 것을 지정하지만 단일 인덱스를 기반으로 조인을 만드는 데 계층 적 인덱싱 체계가 무엇을 해야하는지 혼란 스럽습니다.


가정 수입 :

import pandas as pd

John Galt의 대답 은 기본적으로 reduce작업입니다. 소수의 데이터 프레임이있는 경우 다음과 같은 목록에 넣습니다 (목록 이해 또는 루프 또는 기타를 통해 생성됨).

dfs = [df0, df1, df2, dfN]

name와 같이 공통 열이 있다고 가정하면 다음을 수행합니다.

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

이런 식으로 코드는 병합하려는 데이터 프레임 수에 관계없이 작동해야합니다.

2016 년 8 월 1 일 수정 : 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')

join방법 의 이상적인 상황입니다

join방법은 이러한 유형의 상황에 맞게 작성되었습니다. 원하는 수의 DataFrame을 함께 결합 할 수 있습니다. 호출하는 DataFrame은 전달 된 DataFrame 컬렉션의 인덱스와 결합됩니다. 여러 DataFrame을 사용하려면 조인 열을 인덱스에 넣어야합니다.

코드는 다음과 같습니다.

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

데이터 프레임 목록에 대해 다음과 같이 수행 할 수도 있습니다 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')

0.22.0의 python3.6.3 에서는 결합에 사용하려는 열을 색인으로 설정 pandas하는 한 사용할 수도 있습니다.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']
)

조인 작업 을 수행하기 위해 다중 인덱스가 필요하지 않습니다 . 조인 작업을 수행 할 인덱스 열을 올바르게 설정하면됩니다 ( df.set_index('Name')예 : 명령 )

The join operation is by default performed on index. In your case, you just have to specify that the Name column corresponds to your index. Below is an example

A tutorial may be useful.

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

Here is a method to merge a dictionary of data frames while keeping the column names in sync with the dictionary. Also it fills in missing values if needed:

This is the function to merge a dict of data frames

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, lets generates data and test this:

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)

There is another solution from the pandas documentation (that I don't see here),

using the .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 is used to ignore the index of the appended dataframe, replacing it with the next index available in the source one.

If there are different column names, Nan will be introduced.


Simple Solution:

If the column names are similar:

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

If the column names are different:

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

참고URL : https://stackoverflow.com/questions/23668427/pandas-three-way-joining-multiple-dataframes-on-columns

반응형