当前位置: 首页 > 知识库问答 >
问题:

在列表列中,为每个列表元素创建一行

丰佐
2023-03-14

我有一个数据框,其中一些单元格包含多个值的列表。我不想在一个单元格中存储多个值,而是希望扩展dataframe,以便列表中的每个项都有自己的行(在所有其他列中都有相同的值)。因此,如果我有:

import pandas as pd
import numpy as np

df = pd.DataFrame(
    {'trial_num': [1, 2, 3, 1, 2, 3],
     'subject': [1, 1, 1, 2, 2, 2],
     'samples': [list(np.random.randn(3).round(2)) for i in range(6)]
    }
)

df
Out[10]: 
                 samples  subject  trial_num
0    [0.57, -0.83, 1.44]        1          1
1    [-0.01, 1.13, 0.36]        1          2
2   [1.18, -1.46, -0.94]        1          3
3  [-0.08, -4.22, -2.05]        2          1
4     [0.72, 0.79, 0.53]        2          2
5    [0.4, -0.32, -0.13]        2          3

如何转换为长格式,例如:

   subject  trial_num  sample  sample_num
0        1          1    0.57           0
1        1          1   -0.83           1
2        1          1    1.44           2
3        1          2   -0.01           0
4        1          2    1.13           1
5        1          2    0.36           2
6        1          3    1.18           0
# etc.

索引并不重要,可以将现有列设置为索引,而最终的顺序并不重要。

共有3个答案

那存
2023-03-14

更新:下面的解决方案对较旧的Pandas版本很有帮助,因为DataFrame.explode()不可用。从Pandas 0.25.0开始,您只需使用DataFrame.explode()

lst_col = 'samples'

r = pd.DataFrame({
      col:np.repeat(df[col].values, df[lst_col].str.len())
      for col in df.columns.drop(lst_col)}
    ).assign(**{lst_col:np.concatenate(df[lst_col].values)})[df.columns]

结果:

In [103]: r
Out[103]:
    samples  subject  trial_num
0      0.10        1          1
1     -0.20        1          1
2      0.05        1          1
3      0.25        1          2
4      1.32        1          2
5     -0.17        1          2
6      0.64        1          3
7     -0.22        1          3
8     -0.71        1          3
9     -0.03        2          1
10    -0.65        2          1
11     0.76        2          1
12     1.77        2          2
13     0.89        2          2
14     0.65        2          2
15    -0.98        2          3
16     0.65        2          3
17    -0.30        2          3

PS在这里你可以找到一个更通用的解决方案

更新:一些解释:IMO理解这段代码的最简单方法是尝试一步一步地执行它:

在下面一行中,我们在一列中重复值N次,其中N-是相应列表的长度:

In [10]: np.repeat(df['trial_num'].values, df[lst_col].str.len())
Out[10]: array([1, 1, 1, 2, 2, 2, 3, 3, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3], dtype=int64)

这可以推广到包含标量值的所有列:

In [11]: pd.DataFrame({
    ...:           col:np.repeat(df[col].values, df[lst_col].str.len())
    ...:           for col in df.columns.drop(lst_col)}
    ...:         )
Out[11]:
    trial_num  subject
0           1        1
1           1        1
2           1        1
3           2        1
4           2        1
5           2        1
6           3        1
..        ...      ...
11          1        2
12          2        2
13          2        2
14          2        2
15          3        2
16          3        2
17          3        2

[18 rows x 2 columns]

使用np.concatenate()我们可以展平列表列(示例)中的所有值,并获得1D向量:

In [12]: np.concatenate(df[lst_col].values)
Out[12]: array([-1.04, -0.58, -1.32,  0.82, -0.59, -0.34,  0.25,  2.09,  0.12,  0.83, -0.88,  0.68,  0.55, -0.56,  0.65, -0.04,  0.36, -0.31])

综上所述:

In [13]: pd.DataFrame({
    ...:           col:np.repeat(df[col].values, df[lst_col].str.len())
    ...:           for col in df.columns.drop(lst_col)}
    ...:         ).assign(**{lst_col:np.concatenate(df[lst_col].values)})
Out[13]:
    trial_num  subject  samples
0           1        1    -1.04
1           1        1    -0.58
2           1        1    -1.32
3           2        1     0.82
4           2        1    -0.59
5           2        1    -0.34
6           3        1     0.25
..        ...      ...      ...
11          1        2     0.68
12          2        2     0.55
13          2        2    -0.56
14          2        2     0.65
15          3        2    -0.04
16          3        2     0.36
17          3        2    -0.31

[18 rows x 3 columns]

使用pd。DataFrame()[df.columns]将保证我们按照原始顺序选择列...

曾喜
2023-03-14

Series和DataFrame方法定义了将列表分解为单独行的.explode()方法。请参阅“文档”部分中的“分解类似列表的列”。

df = pd.DataFrame({
    'var1': [['a', 'b', 'c'], ['d', 'e',], [], np.nan], 
    'var2': [1, 2, 3, 4]
})
df
        var1  var2
0  [a, b, c]     1
1     [d, e]     2
2         []     3
3        NaN     4

df.explode('var1')

  var1  var2
0    a     1
0    b     1
0    c     1
1    d     2
1    e     2
2  NaN     3  # empty list converted to NaN
3  NaN     4  # NaN entry preserved as-is

# to reset the index to be monotonically increasing...
df.explode('var1').reset_index(drop=True)

  var1  var2
0    a     1
1    b     1
2    c     1
3    d     2
4    e     2
5  NaN     3
6  NaN     4

请注意,这也适当地处理列表和标量的混合列,以及空列表和NaN(这是基于重复的解决方案的缺点)。

但是,您应该注意,爆炸仅对单个列起作用(目前)。

注意:如果要分解一列字符串,需要先在分隔符上拆分,然后使用explode。请看我给出的(非常)相关的答案。

容飞掣
2023-03-14

比我预期的要长一点:

>>> df
                samples  subject  trial_num
0  [-0.07, -2.9, -2.44]        1          1
1   [-1.52, -0.35, 0.1]        1          2
2  [-0.17, 0.57, -0.65]        1          3
3  [-0.82, -1.06, 0.47]        2          1
4   [0.79, 1.35, -0.09]        2          2
5   [1.17, 1.14, -1.79]        2          3
>>>
>>> s = df.apply(lambda x: pd.Series(x['samples']),axis=1).stack().reset_index(level=1, drop=True)
>>> s.name = 'sample'
>>>
>>> df.drop('samples', axis=1).join(s)
   subject  trial_num  sample
0        1          1   -0.07
0        1          1   -2.90
0        1          1   -2.44
1        1          2   -1.52
1        1          2   -0.35
1        1          2    0.10
2        1          3   -0.17
2        1          3    0.57
2        1          3   -0.65
3        2          1   -0.82
3        2          1   -1.06
3        2          1    0.47
4        2          2    0.79
4        2          2    1.35
4        2          2   -0.09
5        2          3    1.17
5        2          3    1.14
5        2          3   -1.79

如果需要顺序索引,可以对结果应用reset\u index(drop=True)

更新:

>>> res = df.set_index(['subject', 'trial_num'])['samples'].apply(pd.Series).stack()
>>> res = res.reset_index()
>>> res.columns = ['subject','trial_num','sample_num','sample']
>>> res
    subject  trial_num  sample_num  sample
0         1          1           0    1.89
1         1          1           1   -2.92
2         1          1           2    0.34
3         1          2           0    0.85
4         1          2           1    0.24
5         1          2           2    0.72
6         1          3           0   -0.96
7         1          3           1   -2.72
8         1          3           2   -0.11
9         2          1           0   -1.33
10        2          1           1    3.13
11        2          1           2   -0.65
12        2          2           0    0.10
13        2          2           1    0.65
14        2          2           2    0.15
15        2          3           0    0.64
16        2          3           1   -0.10
17        2          3           2   -0.76
 类似资料:
  • 问题内容: 我有一个数据框,其中某些单元格包含多个值的列表。我不想扩展一个单元格中的多个值,而是想扩展数据框,以便列表中的每个项目都有自己的行(所有其他列中的值都相同)。所以,如果我有: 如何转换为长格式,例如: 索引并不重要,可以将现有的列设置为索引也可以,最后的顺序也不重要。 问题答案: 结果: PS 在这里你可能会发现一些通用的解决方案 更新:一些解释:IMO了解此代码的最简单方法是尝试逐步

  • 问题内容: 我有一个字典列表,并且想为该列表的每个元素添加一个键。我试过了: 但是update方法返回None,所以我的结果列表中没有None。 返回语法错误。 问题答案: 您无需担心要构建新的词典列表,因为对更新后的词典的引用与对旧词典的引用相同:

  • 问题内容: 我需要增量填充列表或列表元组。看起来像这样: 为了使它不那么冗长,更优雅,我想我会预先分配一个空列表 预分配部分对我来说并不明显。当我这样做时,我会收到对同一列表的引用列表,因此以下内容的输出 是: 我可以使用循环(),但我想知道是否存在“无环”解决方案。 是获得我想要的东西的唯一方法 问题答案: 这将创建x个不同的列表,每个列表都有一个列表副本(该列表中的每个项目都是通过引用提供的,

  • 对于C#中泛型列表的泛型列表的概念,我似乎有点难以理解。我认为问题源于

  • 问题内容: 这个问题已经在这里有了答案 : 9年前关闭。 我有两个清单: 我需要从这些列表中创建一个元组列表,如下所示: 我尝试这样做: 但导致: 即x中每个元素与y中每个元素的元组列表…什么是我想做的正确方法?谢谢… 编辑: 在编辑之前提到的其他两个重复是我的错,我将其缩进另一个for循环中是错误的… 问题答案: 使用内置函数: 在Python 3中: 在Python 2中:

  • 问题内容: 给出以下列表: 我想将[a]的每个元素重复其在[b]中的对应位置的编号,以产生此结果: 即0发生1次,5发生2次,1发生1次。 问题答案: 内容如下: -重复elem次 从两个列表中组成一个2元组的列表,将每个元素与另一个列表中的对应元素配对。这为您提供了用例中需要传递给的确切信息。 -将迭代器的结果列表展平为单个值列表。您既可以像我一样,也可以像马丁·彼得斯那样。