programing

여러 데이터 프레임을 병합하는 방법

kingscode 2023. 6. 10. 16:03
반응형

여러 데이터 프레임을 병합하는 방법

데이터 프레임이 서로 다르므로 날짜 열을 기준으로 병합해야 합니다.개의 데이터 프레임만 , 는 데터프두개있다면만이레이임,▁use있을 사용할 수 입니다.df1.merge(df2, on='date')세 개의 데이터 프레임으로 수행하기 위해, 나는 사용합니다.df1.merge(df2.merge(df3, on='date'), on='date')그러나 여러 데이터 프레임으로 이 작업을 수행하는 것은 매우 복잡하고 읽을 수 없습니다.

모든 데이터 프레임에는 공통적으로 하나의 열이 있습니다.date그러나 행 수나 열 수가 동일하지 않으므로 각 날짜가 모든 데이터 프레임에 공통인 행만 필요합니다.

그래서 저는 모든 데이터가 포함된 데이터 프레임을 반환하는 재귀 함수를 작성하려고 하지만 작동하지 않았습니다.그러면 여러 데이터 프레임을 어떻게 병합해야 합니까?

여러 가지 방법을 시도했는데 다음과 같은 오류가 발생했습니다.out of range,keyerror 0/1/2/3그리고.can not merge DataFrame with instance of type <class 'NoneType'>.

제가 쓴 대본은 다음과 같습니다.

dfs = [df1, df2, df3] # list of dataframes

def mergefiles(dfs, countfiles, i=0):
    if i == (countfiles - 2): # it gets to the second to last and merges it with the last
        return
    
    dfm = dfs[i].merge(mergefiles(dfs[i+1], countfiles, i=i+1), on='date')
    return dfm

print(mergefiles(dfs, len(dfs)))

예: df_1:

May 19, 2017;1,200.00;0.1%
May 18, 2017;1,100.00;0.1%
May 17, 2017;1,000.00;0.1%
May 15, 2017;1,901.00;0.1%

df_2:

May 20, 2017;2,200.00;1000000;0.2%
May 18, 2017;2,100.00;1590000;0.2%
May 16, 2017;2,000.00;1230000;0.2%
May 15, 2017;2,902.00;1000000;0.2%

df_3:

May 21, 2017;3,200.00;2000000;0.3%
May 17, 2017;3,100.00;2590000;0.3%
May 16, 2017;3,000.00;2230000;0.3%
May 15, 2017;3,903.00;2000000;0.3%

예상되는 병합 결과:

May 15, 2017;  1,901.00;0.1%;  2,902.00;1000000;0.2%;   3,903.00;2000000;0.3%   

단답형

df_merged = reduce(lambda  left,right: pd.merge(left,right,on=['DATE'],
                                            how='outer'), data_frames)

긴 대답

아래는 복잡한 쿼리가 포함되지 않은 경우 여러 데이터 프레임을 병합하는 가장 깨끗하고 이해하기 쉬운 방법입니다.

DATE를 인덱스로 병합하고 OUTER 메서드를 사용하여 병합하기만 하면 됩니다(모든 데이터를 가져옵니다).

import pandas as pd
from functools import reduce

df1 = pd.read_table('file1.csv', sep=',')
df2 = pd.read_table('file2.csv', sep=',')
df3 = pd.read_table('file3.csv', sep=',')

이제 기본적으로 데이터 프레임으로 사용하는 모든 파일을 목록에 로드합니다.다을사용파병합다니합을 사용하여 합니다.merge또는reduce기능.

# compile the list of dataframes you want to merge
data_frames = [df1, df2, df3]

참고: 위 목록 내에 데이터 프레임을 최대한 추가할 수 있습니다.이것이 이 방법의 좋은 점입니다.복잡한 쿼리가 포함되지 않았습니다.

는 같은 날짜에 .DATE

df_merged = reduce(lambda  left,right: pd.merge(left,right,on=['DATE'],
                                            how='outer'), data_frames)

# if you want to fill the values that don't exist in the lines of merged dataframe simply fill with required strings as

df_merged = reduce(lambda  left,right: pd.merge(left,right,on=['DATE'],
                                            how='outer'), data_frames).fillna('void')
  • 이제 출력은 동일한 날짜의 값을 동일한 라인에 표시합니다.
  • fillna()를 사용하여 서로 다른 열에 대해 서로 다른 프레임의 존재하지 않는 데이터를 채울 수 있습니다.

그런 다음 원하는 경우 병합된 데이터를 csv 파일에 씁니다.

pd.DataFrame.to_csv(df_merged, 'merged.txt', sep=',', na_rep='.', index=False)

이것은 당신에게 줄 것입니다.

DATE VALUE1 VALUE2 VALUE3 ....

데이터에 동일한 열이 있으므로 다음 작업을 수행할 수 있습니다.

df1 = pd.DataFrame(data1)
df2 = pd.DataFrame(data2)

merged_df = pd.concat([df1, df2])

functools.dll 및 pd.concat은 좋은 솔루션이지만 실행 시간 측면에서는 pd.concat이 가장 좋습니다.

from functools import reduce
import pandas as pd

dfs = [df1, df2, df3, ...]
nan_value = 0

# solution 1 (fast)
result_1 = pd.concat(dfs, join='outer', axis=1).fillna(nan_value)

# solution 2
result_2 = reduce(lambda df_left,df_right: pd.merge(df_left, df_right, 
                                              left_index=True, right_index=True, 
                                              how='outer'), 
                  dfs).fillna(nan_value)

이에 대한 솔루션은 두 가지가 있지만 모든 열을 개별적으로 반환합니다.

import functools

dfs = [df1, df2, df3]

df_final = functools.reduce(lambda left,right: pd.merge(left,right,on='date'), dfs)
print (df_final)
          date     a_x   b_x       a_y      b_y   c_x         a        b   c_y
0  May 15,2017  900.00  0.2%  1,900.00  1000000  0.2%  2,900.00  2000000  0.2%

k = np.arange(len(dfs)).astype(str)
df = pd.concat([x.set_index('date') for x in dfs], axis=1, join='inner', keys=k)
df.columns = df.columns.map('_'.join)
print (df)
                0_a   0_b       1_a      1_b   1_c       2_a      2_b   2_c
date                                                                       
May 15,2017  900.00  0.2%  1,900.00  1000000  0.2%  2,900.00  2000000  0.2%

또 : 결하는또다방법:functools.reduce

설명서에서:

를 들면, 들면를예,reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])를 합니다. ((((1+2)+3)+4)+5)를 계산합니다.왼쪽 인수 x는 누적된 값이고 오른쪽 인수 y는 반복 가능한 업데이트 값입니다.

그래서:

from functools import reduce
dfs = [df1, df2, df3, df4, df5, df6]
df_final = reduce(lambda left,right: pd.merge(left,right,on='some_common_column_name'), dfs)

@dannyuu의 대답이 맞습니다. pd.concat은 축 옵션을 1로 설정하면 인덱스 열에 자연스럽게 조인을 수행합니다.기본값은 외부 조인이지만 내부 조인도 지정할 수 있습니다.다음은 예입니다.

x = pd.DataFrame({'a': [2,4,3,4,5,2,3,4,2,5], 'b':[2,3,4,1,6,6,5,2,4,2], 'val': [1,4,4,3,6,4,3,6,5,7], 'val2': [2,4,1,6,4,2,8,6,3,9]})
x.set_index(['a','b'], inplace=True)
x.sort_index(inplace=True)

y = x.__deepcopy__()
y.loc[(14,14),:] = [3,1]
y['other']=range(0,11)

y.sort_values('val', inplace=True)

z = x.__deepcopy__()
z.loc[(15,15),:] = [3,4]
z['another']=range(0,22,2)
z.sort_values('val2',inplace=True)


pd.concat([x,y,z],axis=1)

판다들을 보세요. 기둥 위의 여러 데이터 프레임을 3방향으로 결합합니다.

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

다음과 같이 dataframe.merge를 사용할 수도 있습니다.

df = df1.merge(df2).merge(df3)

갱신하다

이 방법의 성능을 현재 승인된 답변과 비교

import timeit

setup = '''import pandas as pd
from functools import reduce
df_1 = pd.DataFrame({'date': {0: 'May 19, 2017', 1: 'May 18, 2017', 2: 'May 17, 2017', 3: 'May 15, 2017'}, 'a': {0: '1,200.00', 1: '1,100.00', 2: '1,000.00', 3: '1,901.00'}, 'b': {0: '0.1%', 1: '0.1%', 2: '0.1%', 3: '0.1%'}})
df_2 = pd.DataFrame({'date': {0: 'May 20, 2017', 1: 'May 18, 2017', 2: 'May 16, 2017', 3: 'May 15, 2017'}, 'a': {0: '2,200.00', 1: '2,100.00', 2: '2,000.00', 3: '2,902.00'}, 'b': {0: 1000000, 1: 1590000, 2: 1230000, 3: 1000000}, 'c': {0: '0.2%', 1: '0.2%', 2: '0.2%', 3: '0.2%'}})
df_3 = pd.DataFrame({'date': {0: 'May 21, 2017', 1: 'May 17, 2017', 2: 'May 16, 2017', 3: 'May 15, 2017'}, 'a': {0: '3,200.00', 1: '3,100.00', 2: '3,000.00', 3: '3,903.00'}, 'b': {0: 2000000, 1: 2590000, 2: 2230000, 3: 2000000}, 'c': {0: '0.3%', 1: '0.3%', 2: '0.3%', 3: '0.3%'}})
dfs = [df_1, df_2, df_3]'''


#methods from currently accepted answer
>>> timeit.timeit(setup=setup, stmt="reduce(lambda  left,right: pd.merge(left,right,on=['date'], how='outer'), dfs)", number=1000)
3.3471919000148773
>>> timeit.timeit(setup=setup, stmt="df_merged = reduce(lambda  left,right: pd.merge(left,right,on=['date'], how='outer'), dfs).fillna('void')", number=1000)
4.079146400094032

#method demonstrated in this answer
>>> timeit.timeit(setup=setup, stmt="df = df_1.merge(df_2, on='date').merge(df_3, on='date')", number=1000)
2.7787032001651824

@interial007의 솔루션이 효과가 있었습니다.이것이 제가 사용 사례를 위해 개선한 방법입니다. 즉, 최종 병합된 데이터 프레임에서 dfs를 더 쉽게 구별할 수 있도록 각 df의 열을 서로 다른 접미사로 사용하는 것입니다.

from functools import reduce
import pandas as pd
dfs = [df1, df2, df3, df4]
suffixes = [f"_{i}" for i in range(len(dfs))]
# add suffixes to each df
dfs = [dfs[i].add_suffix(suffixes[i]) for i in range(len(dfs))]
# remove suffix from the merging column
dfs = [dfs[i].rename(columns={f"date{suffixes[i]}":"date"}) for i in range(len(dfs))]
# merge
dfs = reduce(lambda left,right: pd.merge(left,right,how='outer', on='date'), dfs)

저는 유사한 사용 사례를 가지고 있었고 아래와 같이 해결했습니다.기본적으로 목록의 첫 번째 df를 캡처한 다음 주의사항을 반복하여 병합 결과가 이전 df를 대체할 위치에 병합했습니다.

편집: 이 접근 방식이 대규모 데이터셋으로 어떻게 확장될지 확신할 수 없는 매우 작은 데이터 프레임을 다루고 있었습니다.#기울임자

import pandas as pd
df_list = [df1,df2,df3, ...dfn]
# grab first dataframe
all_merged = df_list[0]
# loop through all but first data frame
for to_merge in df_list[1:]:
    # result of merge replaces first or previously
    # merged data frame w/ all previous fields
    all_merged = pd.merge(
        left=all_merged
        ,right=to_merge
        ,how='inner'
        ,on=['some_fld_across_all']
        )

# can easily have this logic live in a function
def merge_mult_dfs(df_list):
    all_merged = df_list[0]
    for to_merge in df_list[1:]:
        all_merged = pd.merge(
            left=all_merged
            ,right=to_merge
            ,how='inner'
            ,on=['some_fld_across_all']
            )
    return all_merged

공통 날짜로 필터링하는 경우 다음을 반환합니다.

dfs = [df1, df2, df3]
checker = dfs[-1]
check = set(checker.loc[:, 0])

for df in dfs[:-1]:
    check = check.intersection(set(df.loc[:, 0]))

print(checker[checker.loc[:, 0].isin(check)])

@jezrael, @zipa, @everestial007을 도와주셔서 감사합니다, 두 답변 모두 제가 필요로 하는 답변입니다.재귀적인 작업을 수행하려는 경우 이 작업도 의도한 대로 수행됩니다.

def mergefiles(dfs=[], on=''):
    """Merge a list of files based on one column"""
    if len(dfs) == 1:
         return "List only have one element."

    elif len(dfs) == 2:
        df1 = dfs[0]
        df2 = dfs[1]
        df = df1.merge(df2, on=on)
        return df

    # Merge the first and second datafranes into new dataframe
    df1 = dfs[0]
    df2 = dfs[1]
    df = dfs[0].merge(dfs[1], on=on)

    # Create new list with merged dataframe
    dfl = []
    dfl.append(df)

    # Join lists
    dfl = dfl + dfs[2:] 
    dfm = mergefiles(dfl, on)
    return dfm

나에게 색인은 명시적인 지시 없이 무시됩니다.예:

    > x = pandas.DataFrame({'a': [1,2,2], 'b':[4,5,5]})
    > x
        a   b
    0   1   4
    1   2   5
    2   2   5

    > x.drop_duplicates()
        a   b
    0   1   4
    1   2   5

(다른 인덱스에도 불구하고 중복된 라인이 제거됨)

언급URL : https://stackoverflow.com/questions/44327999/how-to-merge-multiple-dataframes

반응형