【问题标题】:Interweave two dataframes交织两个数据帧
【发布时间】:2018-01-02 03:08:24
【问题描述】:

假设我有两个数据框 d1 和 d2

d1 = pd.DataFrame(np.ones((3, 3), dtype=int), list('abc'), [0, 1, 2])
d2 = pd.DataFrame(np.zeros((3, 2), dtype=int), list('abc'), [3, 4])

d1

   0  1  2
a  1  1  1
b  1  1  1
c  1  1  1

d2

   3  4
a  0  0
b  0  0
c  0  0

什么是交织两个数据框列的简单而通用的方法。我们可以假设d2 中的列数总是比d1 中的列数少一。而且,索引是一样的。

我想要这个:

pd.concat([d1[0], d2[3], d1[1], d2[4], d1[2]], axis=1)

   0  3  1  4  2
a  1  0  1  0  1
b  1  0  1  0  1
c  1  0  1  0  1

【问题讨论】:

    标签: python pandas numpy dataframe


    【解决方案1】:

    roundrobin itertools 配方具有交错特性。此选项提供了直接从 Python docs 实施配方或导入第三方包(例如 more_itertools)为您实施配方的选择:

    from more_itertools import roundrobin
    
    pd.concat([d1, d2], axis=1)[list(roundrobin(d1, d2))]
    
    # Output
       0  3  1  4  2
    a  1  0  1  0  1
    b  1  0  1  0  1
    c  1  0  1  0  1
    

    受@root 回答的启发,列索引被交错并用于分割连接的DataFrame。

    【讨论】:

      【解决方案2】:

      我的解决方案是使用pd.DataFrame.insert,确保先从后面插入

      df = d1.copy()
      for i in range(d2.shape[1], 0, -1):
          df.insert(i, d2.columns[i - 1], d2.iloc[:, i - 1])
      
      df
      
         0  3  1  4  2
      a  1  0  1  0  1
      b  1  0  1  0  1
      c  1  0  1  0  1
      

      【讨论】:

        【解决方案3】:

        这是一种 NumPy 方法 -

        def numpy_interweave(d1, d2):
            c1 = list(d1.columns)
            c2 = list(d2.columns)
            N = (len(c1)+len(c2))
            cols = [None]*N
            cols[::2] = c1
            cols[1::2] = c2
        
            out_dtype = np.result_type(d1.values.dtype, d2.values.dtype)
            out = np.empty((d1.shape[0],N),dtype=out_dtype)
            out[:,::2] = d1.values
            out[:,1::2] = d2.values
        
            df_out = pd.DataFrame(out, columns=cols, index=d1.index)
            return df_out
        

        示例运行 -

        In [346]: d1
        Out[346]: 
           x  y  z
        a  6  7  4
        b  3  5  6
        c  4  6  2
        
        In [347]: d2
        Out[347]: 
           p  q
        a  4  2
        b  7  7
        c  7  2
        
        In [348]: numpy_interweave(d1, d2)
        Out[348]: 
           x  p  y  q  z
        a  6  4  7  2  4
        b  3  7  5  7  6
        c  4  7  6  2  2
        

        【讨论】:

        • 谢谢!这种方法在我们的 Pandas 1.0.5 和 Python 3.8 项目中运行良好。
        【解决方案4】:

        编写一个函数来抽象出通用的合并重新排序

        from itertools import zip_longest
        def weave(df1, df2):
          col1 = df1.columns
          col2 = df2.columns
          weaved =  [col for zipped in zip_longest(col1,col2) 
                         for col in zipped
                         if col is not None]
          return pd.concat([df1, df2], axis=1)[weaved]
        
        weave(d1, d2)
        # Output:
           0  3  1  4  2
        a  1  0  1  0  1
        b  1  0  1  0  1
        c  1  0  1  0  1
        

        【讨论】:

          【解决方案5】:

          我们可以使用itertools.zip_longest:

          In [75]: from itertools import zip_longest
          
          In [76]: cols = pd.Series(np.concatenate(list(zip_longest(d1.columns, d2.columns)))).dropna()
          
          In [77]: cols
          Out[77]:
          0    0
          1    3
          2    1
          3    4
          4    2
          dtype: object
          
          In [78]: df = pd.concat([d1, d2], axis=1)[cols]
          
          In [79]: df
          Out[79]:
             0  3  1  4  2
          a  1  0  1  0  1
          b  1  0  1  0  1
          c  1  0  1  0  1
          

          【讨论】:

            【解决方案6】:

            交织列:

            c = np.empty((d1.columns.size + d2.columns.size,), dtype=object)
            c[0::2], c[1::2] = d1.columns, d2.columns
            

            现在,使用布尔索引进行连接和重新排序:

            d1.join(d2)[c]
            
               0  3  1  4  2
            a  1  0  1  0  1
            b  1  0  1  0  1
            c  1  0  1  0  1
            

            在处理多个数据帧时,您可能更喜欢pd.concat。

            【讨论】:

              【解决方案7】:

              使用pd.concat 组合DataFrame,并使用toolz.interleave 重新排列列:

              from toolz import interleave
              
              pd.concat([d1, d2], axis=1)[list(interleave([d1, d2]))]
              

              结果输出如预期:

                 0  3  1  4  2
              a  1  0  1  0  1
              b  1  0  1  0  1
              c  1  0  1  0  1
              

              【讨论】:

              • 一如既往的出色...我已经根据您的建议开始使用cytoolz (-:
              • 这个答案几乎感觉像是在作弊,因为interleave 函数是为相关操作量身定制的。是的,我是toolz/cytoolz 的忠实粉丝。我记得很高兴看到你在不久前的一个问题中使用cytoolz!
              • 你好,我正在使用这个解决方案,但我得到了重复的列。知道我该如何处理吗?
              猜你喜欢
              • 2011-07-17
              • 1970-01-01
              • 2021-01-24
              • 1970-01-01
              • 2011-09-15
              • 1970-01-01
              • 2016-04-02
              • 2013-01-24
              • 1970-01-01
              相关资源
              最近更新 更多