将列表的列拆分为多行

8
我希望在某一列(例如列_x)将列表扩展到多行。
所以,
df = pd.DataFrame({'column_a': ['a_1', 'a_2'], 
                   'column_b': ['b_1', 'b_2'], 
                   'column_x': [['c_1', 'c_2'], ['d_1', 'd_2']]
                  })

将被转换为

    column_a    column_b    column_x
0   a_1         b_1         [c_1, c_2]
1   a_2         b_2         [d_1, d_2]

to

    column_a    column_b    column_x
0   a_1         b_1         c_1
1   a_1         b_1         c_2
2   a_2         b_2         d_1
3   a_2         b_2         d_2

迄今为止,我写的代码正是这样做的,并且它可以快速地运行。

lens = [len(item) for item in df['column_x']]
pd.DataFrame( {"column_a" : np.repeat(df['column_a'].values, lens), 
               "column_b" : np.repeat(df['column_b'].values, lens), 
               "column_x" : np.concatenate(df['column_x'].values)})

然而,我有很多列。是否有一种简洁而优雅的解决方案可以重复整个数据框,而不需要再次指定每一列?

1
我认为这里的主要问题是如果所有列具有相同的“dtypes”。因为如果使用df = pd.DataFrame({'column_a': [1, 2], 'column_b': ['b_1', 'b_2'], 'column_x': [['c_1', 'c_2'], ['d_1', 'd_2']]}),那么两个解决方案会得到不同的输出 - 通过print(df1.dtypes)print(df.dtypes)进行检查。这里的主要问题是numpy将所有dtypes转换为相同的类型,因此更通用的解决方案是重复索引,并且如果所有列的dtypes相同,则也可以使用“coldspeed”解决方案。这取决于数据。 - jezrael
这是一个重要的备注!非常感谢。 - Michael Dorner
2个回答

8

Pandas >= 0.25

使用Pandas >= 0.25 版本,可以通过单个函数调用实现此功能,方法是使用 df.explode

df.explode('column_x')

  column_a column_b column_x
0      a_1      b_1      c_1
0      a_1      b_1      c_2
1      a_2      b_2      d_1
1      a_2      b_2      d_2

请注意,您只能将Series/DataFrame拆分为一列。

Pandas < 0.25

对于除了“column_x”列之外的每一列,沿着第0个轴调用np.repeat

df1 = pd.DataFrame(
    df.drop('column_x', 1).values.repeat(df['column_x'].str.len(), axis=0),
    columns=df.columns.difference(['column_x'])
)
df1['column_x'] = np.concatenate(df['column_x'].values)

df1

  column_a column_b column_x
0      a_1      b_1      c_1
1      a_1      b_1      c_2
2      a_2      b_2      d_1
3      a_2      b_2      d_2

2

您可以重复使用索引值:

lens = df['column_x'].str.len()
a = np.repeat(df.index.values, lens)
print (a)
[0 0 1 1]

df = df.loc[a].assign(column_x=np.concatenate(df['column_x'].values)).reset_index(drop=True)
print (df)
  column_a column_b column_x
0      a_1      b_1      c_1
1      a_1      b_1      c_2
2      a_2      b_2      d_1
3      a_2      b_2      d_2

重复的索引值真是让人头疼,不是吗?会使单元格坐标变得不唯一。 - smci
@smci - 你说得对,但如果不需要将所有的数据类型更改为字符串,这是一个好的解决方案。 - jezrael
jezrael,不需要这样做:df.reset_index(inplace=True, drop=True)会重新索引df,并使用整数。 (请注意,它将使存储索引的任何现有变量无效)。 - smci
从性能角度来看:这个解决方案的速度几乎是@cᴏʟᴅsᴘᴇᴇᴅ解决方案的两倍。 - Michael Dorner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接