Объедините несколько пирамид DataFrames - PullRequest
11 голосов
/ 12 апреля 2019

Это может считаться дубликатом подробного объяснения различных подходов , однако я не могу найти решение своей проблемы из-за большего числа фреймов данных.

У меня есть несколько фреймов данных (более 10), каждый из которых отличается в одном столбце VARX.Это простой и упрощенный пример:

import pandas as pd

df1 = pd.DataFrame({'depth': [0.500000, 0.600000, 1.300000],
       'VAR1': [38.196202, 38.198002, 38.200001],
       'profile': ['profile_1', 'profile_1','profile_1']})

df2 = pd.DataFrame({'depth': [0.600000, 1.100000, 1.200000],
       'VAR2': [0.20440, 0.20442, 0.20446],
       'profile': ['profile_1', 'profile_1','profile_1']})

df3 = pd.DataFrame({'depth': [1.200000, 1.300000, 1.400000],
       'VAR3': [15.1880, 15.1820, 15.1820],
       'profile': ['profile_1', 'profile_1','profile_1']})

Каждый df имеет одинаковую или разную глубину для одинаковых профилей, поэтому

Мне нужно создать новый DataFrame, который объединит всеотдельные, где ключевые столбцы для операции: depth и profile, с all значениями глубины для каждого профиля.

VARXпоэтому значение должно быть NaN, если нет измерения глубины этой переменной для этого профиля.

Таким образом, результатом должен быть новый сжатый DataFrame со всеми VARX в качестве дополнительных столбцов к depthи profile, что-то вроде этого:

name_profile    depth   VAR1        VAR2        VAR3
profile_1   0.500000    38.196202   NaN         NaN
profile_1   0.600000    38.198002   0.20440     NaN
profile_1   1.100000    NaN         0.20442     NaN
profile_1   1.200000    NaN         0.20446     15.1880
profile_1   1.300000    38.200001   NaN         15.1820
profile_1   1.400000    NaN         NaN         15.1820

Обратите внимание, что фактическое количество профилей намного, намного больше.

Есть идеи?

Ответы [ 5 ]

8 голосов
/ 12 апреля 2019

Рассмотрите возможность установки индекса для каждого фрейма данных, а затем выполните горизонтальное объединение с помощью pd.concat:

dfs = [df.set_index(['profile', 'depth']) for df in [df1, df2, df3]]

print(pd.concat(dfs, axis=1).reset_index())
#      profile  depth       VAR1     VAR2    VAR3
# 0  profile_1    0.5  38.198002      NaN     NaN
# 1  profile_1    0.6  38.198002  0.20440     NaN
# 2  profile_1    1.1        NaN  0.20442     NaN
# 3  profile_1    1.2        NaN  0.20446  15.188
# 4  profile_1    1.3  38.200001      NaN  15.182
# 5  profile_1    1.4        NaN      NaN  15.182
4 голосов
/ 12 апреля 2019

Или используя merge:

from functools import partial, reduce

dfs = [df1,df2,df3]
merge = partial(pd.merge, on=['depth','profile'], how='outer')
reduce(merge, dfs)

    depth       VAR1    profile     VAR2    VAR3
0    0.6  38.198002  profile_1  0.20440     NaN
1    0.6  38.198002  profile_1  0.20440     NaN
2    1.3  38.200001  profile_1      NaN  15.182
3    1.1        NaN  profile_1  0.20442     NaN
4    1.2        NaN  profile_1  0.20446  15.188
5    1.4        NaN  profile_1      NaN  15.182

Обновление

Чтобы объединить кадры данных в цикле, как предлагается в комментариях, вы можете сделать что-то вроде:

df_final = pd.DataFrame(columns=df1.columns)
for df in dfs:
    df_final = df_final.merge(df, on=['depth','profile'], how='outer')
1 голос
/ 12 апреля 2019

Вы также можете использовать:

dfs = [df1, df2, df3]
df = pd.merge(dfs[0], dfs[1], left_on=['depth','profile'], right_on=['depth','profile'], how='outer')
for d in dfs[2:]:
    df = pd.merge(df, d, left_on=['depth','profile'], right_on=['depth','profile'], how='outer')

   depth       VAR1    profile     VAR2    VAR3
0    0.5  38.196202  profile_1      NaN     NaN
1    0.6  38.198002  profile_1  0.20440     NaN
2    1.3  38.200001  profile_1      NaN  15.182
3    1.1        NaN  profile_1  0.20442     NaN
4    1.2        NaN  profile_1  0.20446  15.188
5    1.4        NaN  profile_1      NaN  15.182
1 голос
/ 12 апреля 2019

Почему бы не объединить все фреймы данных, растопить их, а затем преобразовать их, используя свои идентификаторы?Возможно, есть более эффективный способ сделать это, но это работает.

df=pd.melt(pd.concat([df1,df2,df3]),id_vars=['profile','depth'])
df_pivot=df.pivot_table(index=['profile','depth'],columns='variable',values='value')

Где df_pivot будет

variable              VAR1     VAR2    VAR3
profile   depth                            
profile_1 0.5    38.196202      NaN     NaN
          0.6    38.198002  0.20440     NaN
          1.1          NaN  0.20442     NaN
          1.2          NaN  0.20446  15.188
          1.3    38.200001      NaN  15.182
          1.4          NaN      NaN  15.182
1 голос
/ 12 апреля 2019

Я бы использовал append.

>>> df1.append(df2).append(df3).sort_values('depth')

        VAR1     VAR2    VAR3  depth    profile
0  38.196202      NaN     NaN    0.5  profile_1
1  38.198002      NaN     NaN    0.6  profile_1
0        NaN  0.20440     NaN    0.6  profile_1
1        NaN  0.20442     NaN    1.1  profile_1
2        NaN  0.20446     NaN    1.2  profile_1
0        NaN      NaN  15.188    1.2  profile_1
2  38.200001      NaN     NaN    1.3  profile_1
1        NaN      NaN  15.182    1.3  profile_1
2        NaN      NaN  15.182    1.4  profile_1

Очевидно, что если у вас много фреймов данных, просто составьте список и переберите их.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...