Join 在部分匹配索引上联接数据帧

Join 在部分匹配索引上联接数据帧,join,pandas,Join,Pandas,我试图找到一种更优雅的方式来连接两个数据帧s,其中一个DF的索引级别是另一个DF的索引级别的部分子集。这是SQL中非常常见的操作,我惊讶地发现使用pandas很难做到: 下面是一个例子: import pandas as pd df = pd.DataFrame( { 2012:[4,5,8,9], 2013:[1,2,4,7], 2014:[6,5,4,3], }, index= pd.MultiIndex.from_t

我试图找到一种更优雅的方式来连接两个
数据帧
s,其中一个DF的索引级别是另一个DF的索引级别的部分子集。这是SQL中非常常见的操作,我惊讶地发现使用
pandas
很难做到:

下面是一个例子:

import pandas as pd

df = pd.DataFrame(
    {
        2012:[4,5,8,9],
        2013:[1,2,4,7],
        2014:[6,5,4,3],
    },
    index= pd.MultiIndex.from_tuples([('apples',False),('bananas',False),('oranges',True),('lemons',True)], names=('fruit','citrus'))
)
=>

现在我想知道一年中每种水果的最高销售量:

fruit_max_by_date = df.max(axis=1).to_frame()
citrus_max_by_date = fruit_max_by_date.max(level='citrus')
citrus_max_by_date.columns = [1]
=>

到目前为止还不错。但现在我尝试将后两者结合起来:

fruit_max_by_date.join(citrus_max_by_date) =>

                    0   1
    fruit   citrus       
    apples  False   6 NaN
    bananas False   5 NaN
    oranges True    8 NaN
    lemons  True    9 NaN

    [4 rows x 2 columns]
因为第二个表的索引与第一个表的索引不完全匹配,所以连接失败。这似乎与类似SQL的内部联接的直观行为完全相反

下面的所有解决方法(尤其是第二种)都很糟糕,基本上要么将索引抛出窗口,要么手动广播一个表的索引有更简单的方法吗?

解决方法:通过广播扩展较小表的索引 这是我能想到的最不难看的解决方法,但它仍然非常糟糕,因为它需要毫无理由地扩展第二个数组的大小

fruit_max_by_date.join( 
  citrus_max_by_date.reindex(fruit_max_by_date.index, level='citrus') ) =>

                    0  1
    fruit   citrus      
    apples  False   6  6
    bananas False   5  6
    oranges True    8  9
    lemons  True    9  9

    [4 rows x 2 columns]
解决方法:截断第一个表的索引 这是非常丑陋的,尤其是必须在事后重新组装索引,但它是有效的

fruit_max_by_date                   \
    .reset_index(level='fruit')     \
    .join(citrus_max_by_date)       \
    .set_index('fruit',append=True  \
    .reorder_levels((1,0))          =>

                    0  1
    citrus fruit        
    False  apples   6  6
           bananas  5  6
    True   oranges  8  9
           lemons   9  9

    [4 rows x 2 columns]
放弃所有使用索引的伪装,加入而不使用索引 好的,这是相对简单的,但是如果你不能使用索引,那么拥有索引到底有什么意义呢

如果使用
join
-而不是
merge
(FML!!)-还有另一个奇怪的副作用:在输出中,join-
列被重复:

    fruit_max_by_date.reset_index().join(
       citrus_max_by_date.reset_index(),
       on='citrus', rsuffix='_' ) =>

             fruit citrus  0 citrus_  1
        0   apples  False  6   False  6
        1  bananas  False  5   False  6
        2  oranges   True  8    True  9
        3   lemons   True  9    True  9

        [4 rows x 5 columns]

    fruit_max_by_date.reset_index().merge(
       citrus_max_by_date.reset_index(),
       on='citrus' ) =>

             fruit citrus  0  1
        0   apples  False  6  6
        1  bananas  False  5  6
        2  oranges   True  8  9
        3   lemons   True  9  9

        [4 rows x 4 columns]

你用的是什么版本?我使用最新版本(0.16.2)没有任何问题。这可能是在版本0.14.0中添加的?啊。。。谢谢我在0.13。。。应该已经升级了吗-(
fruit_max_by_date                   \
    .reset_index(level='fruit')     \
    .join(citrus_max_by_date)       \
    .set_index('fruit',append=True  \
    .reorder_levels((1,0))          =>

                    0  1
    citrus fruit        
    False  apples   6  6
           bananas  5  6
    True   oranges  8  9
           lemons   9  9

    [4 rows x 2 columns]
    fruit_max_by_date.reset_index().join(
       citrus_max_by_date.reset_index(),
       on='citrus', rsuffix='_' ) =>

             fruit citrus  0 citrus_  1
        0   apples  False  6   False  6
        1  bananas  False  5   False  6
        2  oranges   True  8    True  9
        3   lemons   True  9    True  9

        [4 rows x 5 columns]

    fruit_max_by_date.reset_index().merge(
       citrus_max_by_date.reset_index(),
       on='citrus' ) =>

             fruit citrus  0  1
        0   apples  False  6  6
        1  bananas  False  5  6
        2  oranges   True  8  9
        3   lemons   True  9  9

        [4 rows x 4 columns]