Pandas pivot/expand 一列元组到命名列

Pandas pivot/expand a column of tuples into named columns

我有以下数据框

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

这是你的想法吗:

 (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 是一个元组列表,如果将 wrangling/transformation 移动到纯 python 中,然后重新组合回 DataFrame 之前,您可能会获得一些性能:

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

第一个 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

使用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