Извлечь диапазоны из двух одинаковых Pandas фреймов данных и показать объединенные с охватом заголовков? - PullRequest
0 голосов
/ 10 апреля 2020

Рассмотрим эти данные:

>>> import pandas as pd
>>>
dfA = pd.DataFrame({
  "key":[1,3,6,10,15,21],
  "columnA":[10,20,30,40,50,60],
  "columnB":[100,200,300,400,500,600],
  "columnC":[110,202,330,404,550,606],
})
dfB = pd.DataFrame({
  "key":[1,2,5,9,14,20],
  "columnA":[40,50,60,70,80,90],
  "columnB":[400,500,600,700,800,900],
  "columnC":[440,505,660,707,880,909],
})
>>> dfA
   key  columnA  columnB  columnC
0    1       10      100      110
1    3       20      200      202
2    6       30      300      330
3   10       40      400      404
4   15       50      500      550
5   21       60      600      606
>>> dfB
   key  columnA  columnB  columnC
0    1       40      400      440
1    2       50      500      505
2    5       60      600      660
3    9       70      700      707
4   14       80      800      880
5   20       90      900      909

Я в основном хочу извлечь диапазон строк, где столбец «ключ» находится между 2 и 16 из обеих таблиц, и показать этот «поддиапазон» только для «ключ», Столбцы «Столбец А» и «Столбец C» расположены рядом друг с другом для визуального сравнения.

Через Извлечь диапазон строк с помощью .between () и указать c столбцы, из Pandas DataFrame? и Слияние Pandas данных в столбце и результаты, отсортированные по одному и тому же столбцу Я получил следующую (вроде) однострочную строку:

>>>
pd.merge(
  dfA[dfA['key'].between(2,16)][['key','columnA','columnC']], 
  dfB[dfB['key'].between(2,16)][['key','columnA','columnC']], 
  on='key', how='outer'
).astype('Int64').sort_values('key', ignore_index=True)

   key  columnA_x  columnC_x  columnA_y  columnC_y
0    2       <NA>       <NA>         50        505
1    3         20        202       <NA>       <NA>
2    5       <NA>       <NA>         60        660
3    6         30        330       <NA>       <NA>
4    9       <NA>       <NA>         70        707
5   10         40        404       <NA>       <NA>
6   14       <NA>       <NA>         80        880
7   15         50        550       <NA>       <NA>

По сути, это данные, которые я хотел получить - за исключением того, что я хотел бы знать это:

  • Есть ли способ сделать выше, без необходимости набирать диапазон строк (здесь .between(2,16)) дважды?
  • Как можно отформатировать эти результаты с помощью дополнительных "охватывающих" или "объединенных" заголовков (MultiIndex, как в Pandas для Excel (объединены) Колонка заголовка) )? Точнее, выше показаны заголовки столбцов:
(index)   key  columnA_x  columnC_x  columnA_y  columnC_y

... и вместо этого я хотел бы, чтобы исходное имя столбца стало заголовком категории для столбцов, а фактические столбцы стали «A» или «B» ниже категории - для всех, кроме (объединенного) «ключевого» столбца ... так что-то вроде:

               columnA        columnC
(index)   key        A   B          A   B

(Итак, это включает переназначение (переименование) имен столбцов в в определенной степени ...)

Как я могу это сделать? И можно ли это сделать в одну строку, как в приведенном выше примере pd.merge?

Ответы [ 2 ]

2 голосов
/ 10 апреля 2020

Вы можете сделать это, установив key в качестве индекса и конкатата:

(pd.concat([d.set_index('key').loc[2:16] for d in (df1,df2)],
          axis=1, keys=['A','B'])
   .swaplevel(0,1, axis=1)
   .sort_index(axis=1)
)

Вывод:

    columnA       columnB        columnC       
          A     B       A      B       A      B
key                                            
2       NaN  50.0     NaN  500.0     NaN  505.0
3      20.0   NaN   200.0    NaN   202.0    NaN
5       NaN  60.0     NaN  600.0     NaN  660.0
6      30.0   NaN   300.0    NaN   330.0    NaN
9       NaN  70.0     NaN  700.0     NaN  707.0
10     40.0   NaN   400.0    NaN   404.0    NaN
14      NaN  80.0     NaN  800.0     NaN  880.0
15     50.0   NaN   500.0    NaN   550.0    NaN
0 голосов
/ 10 апреля 2020

Обратите внимание на это - согласно комментарию @ QuangHoang:

>>>
(pd.concat([d.set_index('key').loc[2:16, ['ColumnA','ColumnC']] for d in (dfA,dfB)],
          axis=1, keys=['A','B'])
   .swaplevel(0,1, axis=1)
   .sort_index(axis=1)
)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <listcomp>
  File "C:/msys64/mingw64/lib/python3.8/site-packages/pandas/core/indexing.py", line 1762, in __getitem__
    return self._getitem_tuple(key)
  File "C:/msys64/mingw64/lib/python3.8/site-packages/pandas/core/indexing.py", line 1289, in _getitem_tuple
    retval = getattr(retval, self.name)._getitem_axis(key, axis=i)
  File "C:/msys64/mingw64/lib/python3.8/site-packages/pandas/core/indexing.py", line 1954, in _getitem_axis
    return self._getitem_iterable(key, axis=axis)
  File "C:/msys64/mingw64/lib/python3.8/site-packages/pandas/core/indexing.py", line 1595, in _getitem_iterable
    keyarr, indexer = self._get_listlike_indexer(key, axis, raise_missing=False)
  File "C:/msys64/mingw64/lib/python3.8/site-packages/pandas/core/indexing.py", line 1552, in _get_listlike_indexer
    self._validate_read_indexer(
  File "C:/msys64/mingw64/lib/python3.8/site-packages/pandas/core/indexing.py", line 1640, in _validate_read_indexer
    raise KeyError(f"None of [{key}] are in the [{axis_name}]")
KeyError: "None of [Index(['ColumnA', 'ColumnC'], dtype='object')] are in the [columns]"

... однако, это похоже на работу:

(pd.concat([ d[d['key'].between(2,16)][['key','columnA','columnC']].set_index('key') for d in (dfA,dfB) ],
          axis=1, keys=['A','B'])
   .swaplevel(0,1, axis=1)
   .sort_index(axis=1)
)

... и вывод:

    columnA       columnC
          A     B       A      B
key
2       NaN  50.0     NaN  505.0
3      20.0   NaN   202.0    NaN
5       NaN  60.0     NaN  660.0
6      30.0   NaN   330.0    NaN
9       NaN  70.0     NaN  707.0
10     40.0   NaN   404.0    NaN
14      NaN  80.0     NaN  880.0
15     50.0   NaN   550.0    NaN
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...