为了账号安全,请及时绑定邮箱和手机立即绑定

熊猫:当单元格内容是列表时,为列表中的每个元素创建一行。

熊猫:当单元格内容是列表时,为列表中的每个元素创建一行。

慕莱坞森 2019-07-11 16:17:02
熊猫:当单元格内容是列表时,为列表中的每个元素创建一行。我有一个dataframe,其中一些单元格包含多个值的列表。我不想在一个单元格中存储多个值,而是展开dataframe,以便列表中的每个项都得到自己的行(在所有其他列中都有相同的值)。所以如果我有:import pandas as pdimport numpy as npdf = 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)]    })dfOut[10]:                  samples  subject  trial_num0    [0.57, -0.83, 1.44]        1          11    [-0.01, 1.13, 0.36]        1          22   [1.18, -1.46, -0.94]        1          33  [-0.08, -4.22, -2.05]        2          14     [0.72, 0.79, 0.53]        2          25    [0.4, -0.32, -0.13]        2          3我如何转换成长形式,例如:   subject  trial_num  sample  sample_num0        1          1    0.57           01        1          1   -0.83           12        1          1    1.44           23        1          2   -0.01           04        1          2    1.13           15        1          2    0.36           26        1          3    1.18           0# etc.索引并不重要,将现有列设置为索引是可以的,最终排序也不重要。
查看完整描述

3 回答

?
吃鸡游戏

TA贡献1829条经验 获得超7个赞

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()我们可以将list栏(samples),得到一个一维矢量:


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]将保证我们按原来的顺序选择列.


查看完整回答
反对 回复 2019-07-11
?
暮色呼如

TA贡献1853条经验 获得超9个赞

比我预期的要长一点:


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


查看完整回答
反对 回复 2019-07-11
?
慕尼黑5688855

TA贡献1848条经验 获得超2个赞

您也可以使用pd.concatpd.melt为此:

>>> objs = [df, pd.DataFrame(df['samples'].tolist())]

>>> pd.concat(objs, axis=1).drop('samples', axis=1)

   subject  trial_num     0     1     2

0        1          1 -0.49 -1.00  0.44

1        1          2 -0.28  1.48  2.01

2        1          3 -0.52 -1.84  0.02

3        2          1  1.23 -1.36 -1.06

4        2          2  0.54  0.18  0.51

5        2          3 -2.18 -0.13 -1.35

>>> pd.melt(_, var_name='sample_num', value_name='sample', 

...         value_vars=[0, 1, 2], id_vars=['subject', 'trial_num'])

    subject  trial_num sample_num  sample

0         1          1          0   -0.49

1         1          2          0   -0.28

2         1          3          0   -0.52

3         2          1          0    1.23

4         2          2          0    0.54

5         2          3          0   -2.18

6         1          1          1   -1.00

7         1          2          1    1.48

8         1          3          1   -1.84

9         2          1          1   -1.36

10        2          2          1    0.18

11        2          3          1   -0.13

12        1          1          2    0.44

13        1          2          2    2.01

14        1          3          2    0.02

15        2          1          2   -1.06

16        2          2          2    0.51

17        2          3          2   -1.35

最后,如果需要,可以根据前三列进行排序。




查看完整回答
反对 回复 2019-07-11
  • 3 回答
  • 0 关注
  • 588 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信