将列表的列分解为多行

Posted

技术标签:

【中文标题】将列表的列分解为多行【英文标题】:Explode column of list to multiple rows 【发布时间】:2018-08-15 07:46:27 【问题描述】:

我想将某个列(在示例 column_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]

    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

到目前为止,我的代码就是这样做的,它确实做到了fast。

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))

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

【问题讨论】:

如果所有列都具有相同的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 将所有 dtype 转换为相同,因此更通用的解决方案是重复 index,如果所有列的相同 dtypes 可能也使用 cᴏʟᴅsᴘᴇᴇᴅ 解决方案。这取决于数据。 这句话很重要!非常感谢。 【参考方案1】:

熊猫 >= 0.25

Pandas 可以通过 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。


熊猫

沿第 0th 轴为每一列调用 np.repeat除了 column_x

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 - 你是对的,但如果不需要将所有 dtype 更改为字符串,这是一个很好的解决方案 jezrael 没有必要:df.reset_index(inplace=True, drop=True) 将使用整数重新索引 df。 (请注意,它会使存储索引的任何现有变量无效)。 从性能角度来看:这个解决方案几乎是@cᴏʟᴅsᴘᴇᴇᴅ 解决方案的两倍。

以上是关于将列表的列分解为多行的主要内容,如果未能解决你的问题,请参考以下文章

Sparklyr:如何将列表列分解为Spark表中自己的列?

根据列值将一行分解/拆分为多行

将稀疏特征向量分解为单独的列

如何在不使用数据框的情况下将一行分解为多行?

MSSQL 将多行返回到数组中,每行分解为一个数组

如何将 JSON 格式的单行 Spark 数据框分解为多行?