代码之家  ›  专栏  ›  技术社区  ›  Mittenchops

Pandas将元组的列透视/展开为命名列

  •  0
  • Mittenchops  · 技术社区  · 3 年前

    我有以下数据帧

    df = pd.DataFrame([
    {"A": 1, "B": "20", "pairs": [(1,2), (2,3)]},
    {"A": 2, "B": "22", "pairs": [(1,1), (2,2), (1,3)]},
    {"A": 3, "B": "24", "pairs": [(1,1), (3,3)]},
    {"A": 4, "B": "26", "pairs": [(1,3)]},
    ])
    
    >>> df
       A   B                     pairs
    0  1  20          [(1, 2), (2, 3)]
    1  2  22  [(1, 1), (2, 2), (1, 3)]
    2  3  24          [(1, 1), (3, 3)]
    3  4  26                  [(1, 3)]
    

    我不想这些是元组的列表,而是想为这些对(p1和p2)创建新的列,其中这些列分别作为每个元组的第一个和第二个成员排序。这里还有一个宽到长的元素,我将一行分解为列表中成对的行。

    这似乎不适合我能找到的很多从宽到长的文档。我想要的输出格式是:

    >>> df
       A   B  p1  p2
    0  1  20   1   2
    1  1  20   2   3
    2  2  22   1   1
    3  2  22   2   2
    4  2  22   1   3
    5  3  24   1   1
    6  3  24   3   3
    7  4  26   1   3
    
    0 回复  |  直到 3 年前
        1
  •  2
  •   BENY    3 年前

    第一 explode 然后 join

    s = df.explode('pairs').reset_index(drop=True)
    out = s.join(pd.DataFrame(s.pop('pairs').tolist(),columns=['p1','p2']))
    out
    Out[98]: 
       A   B  p1  p2
    0  1  20   1   2
    1  1  20   2   3
    2  2  22   1   1
    3  2  22   2   2
    4  2  22   1   3
    5  3  24   1   1
    6  3  24   3   3
    7  4  26   1   3
    
        2
  •  2
  •   Corralien    3 年前

    使用 explode :

    >>> df.join(df.pop('pairs').explode().apply(pd.Series)
                               .rename(columns={0: 'p1', 1: 'p2'}))
    
       A   B  p1  p2
    0  1  20   1   2
    0  1  20   2   3
    1  2  22   1   1
    1  2  22   2   2
    1  2  22   1   3
    2  3  24   1   1
    2  3  24   3   3
    3  4  26   1   3
    
    
    
        3
  •  1
  •   sammywemmy    3 年前

    这就是你的想法吗:

     (df.explode('pairs') # blow it up into individual rows
        .assign(p1 = lambda df: df.pairs.str[0], 
                p2 = lambda df: df.pairs.str[-1])
        .drop(columns='pairs')
      )
    Out[1234]: 
       A   B  p1  p2
    0  1  20   1   2
    0  1  20   2   3
    1  2  22   1   1
    1  2  22   2   2
    1  2  22   1   3
    2  3  24   1   1
    2  3  24   3   3
    3  4  26   1   3
    

    另一个选项,使用 apply 方法和更长的代码行(就性能而言,我不知道哪一个更好):

    (df
    .set_index(['A', 'B'])
    .pairs
    .apply(pd.Series)
    .stack()
    .apply(pd.Series)
    .droplevel(-1)
    .set_axis(['p1', 'p2'],axis=1)
    .reset_index()
    )
    Out[1244]: 
       A   B  p1  p2
    0  1  20   1   2
    1  1  20   2   3
    2  2  22   1   1
    3  2  22   2   2
    4  2  22   1   3
    5  3  24   1   1
    6  3  24   3   3
    7  4  26   1   3
    

    自从 pair 是元组的列表,如果在重新组合回DataFrame之前将争用/转换移到纯python中,您可能会获得一些性能:

    from itertools import chain
    repeats = [*map(len, df.pairs)]
    reshaped = chain.from_iterable(df.pairs)
    reshaped = pd.DataFrame(reshaped, 
                            columns = ['p1', 'p2'], 
                            index = df.index.repeat(repeats))
    df.drop(columns='pairs').join(reshaped)
    Out[1265]: 
       A   B  p1  p2
    0  1  20   1   2
    0  1  20   2   3
    1  2  22   1   1
    1  2  22   2   2
    1  2  22   1   3
    2  3  24   1   1
    2  3  24   3   3
    3  4  26   1   3