【问题标题】:Pandas: convert df from "wide" to "long" format with col containing dtype object which should be an arrayPandas:将 df 从“宽”格式转换为“长”格式,其中 col 包含 dtype 对象,该对象应该是一个数组
【发布时间】:2018-08-18 04:14:06
【问题描述】:

我有一列看起来像列表的 dtype 对象:

import pandas as pd
import numpy as np

raw = '/******/*******/******/data.txt'
df = pd.read_csv(raw, sep='\t')
df.head()

id  val_0  val_1  val_2  feat_0  feat_1  feat_2  \
0  a      2      0      2       2       2       0   
1  b      1     -1      1       1       1      -2   
2  c      0     -2     -2       0       2       1   
3  d     -1      1     -1      -1       1      -2   
4  e     -2      2      0      -2       0       2       

                              objs_0                             objs_1  \
0  [u'word_0', u'word_1', u'word_2']  [u'word_0', u'word_1', u'word_2']   
1  [u'word_0', u'word_1', u'word_2']  [u'word_0', u'word_1', u'word_2']   
2  [u'word_0', u'word_1', u'word_2']  [u'word_0', u'word_1', u'word_2']   
3  [u'word_0', u'word_1', u'word_2']  [u'word_0', u'word_1', u'word_2']   
4  [u'word_0', u'word_1', u'word_2']  [u'word_0', u'word_1', u'word_2']       

                              objs_2  
0  [u'word_0', u'word_1', u'word_2']  
1  [u'word_0', u'word_1', u'word_2']  
2  [u'word_0', u'word_1', u'word_2']  
3  [u'word_0', u'word_1', u'word_2']  
4  [u'word_0', u'word_1', u'word_2']  

df['objs_0'].values

array(["[u'word_0', u'word_1', u'word_2']",
   "[u'word_0', u'word_1', u'word_2']",
   "[u'word_0', u'word_1', u'word_2']",
   "[u'word_0', u'word_1', u'word_2']",
   "[u'word_0', u'word_1', u'word_2']"], dtype=object)

最终,我需要将此 df 转换为“long”格式,并且我想使用此处的代码运行它: pandas: When cell contents are lists, create a row for each element in the list

但问题是我无法将这些字符串转换为列表。

我已经试过了:

df['objs_0'] = df['objs_0'].apply(lambda row: list(row))
df['objs_0']

但这只是按字符分解整个字符串。 此外,我的“字符串列表”的长度不可预测,所以我不能依赖 str.partition() 方法。对此的任何帮助将不胜感激!

【问题讨论】:

  • 你希望输出是什么样的?

标签: python pandas


【解决方案1】:

您可以使用 pandas 函数,pd.wide_to_long

df = pd.DataFrame({'id':[0,1],
                  'val_0':[2,1],
                  'val_1':[0,-1],
                  'feat_0':[2,1],
                  'feat_1':[2,1],
                  'objs_0':[['word_0','word_1'],['aword_0','aword_1']],
                  'objs_1':[['word_2','word_3'],['bword_0','bword_1']]})

pd.wide_to_long(df,['val','feat','objs'],'id','varcount','_','\w+').reset_index()

输出:

   id  varcount  val  feat                objs
0   0         0    2     2    [word_0, word_1]
1   1         0    1     1  [aword_0, aword_1]
2   0         1    0     2    [word_2, word_3]
3   1         1   -1     1  [bword_0, bword_1]

并且,继续 break make objs 为长格式:

pd.DataFrame(df_out['objs'].values.tolist()).stack().to_frame(name='obj')\
  .reset_index(level=1, drop=True)\
  .join(df_out)

输出:

       obj  id  varcount  val  feat                objs
0   word_0   0         0    2     2    [word_0, word_1]
0   word_1   0         0    2     2    [word_0, word_1]
1  aword_0   1         0    1     1  [aword_0, aword_1]
1  aword_1   1         0    1     1  [aword_0, aword_1]
2   word_2   0         1    0     2    [word_2, word_3]
2   word_3   0         1    0     2    [word_2, word_3]
3  bword_0   1         1   -1     1  [bword_0, bword_1]
3  bword_1   1         1   -1     1  [bword_0, bword_1]

【讨论】:

  • 感谢您的回复;但是,它无法处理我的数据。我做了更多的挖掘,发现我需要将我的“字符串列表”转换为实际的列表。为此,我使用了 AST import ast def obj_to_list(row): string = str(row) list_ = ast.literal_eval(string) return list_ df['objs_0_cln'] = df[objs_0'].apply(lambda x: obj_to_list (x))
  • 我认为您也可以使用 yaml 来实现这一点。导入yaml。 df = df.applymap(yaml.load) 或尝试仅执行该列。 df['objs'] = df['objs'].apply(yaml.load)
【解决方案2】:

你可以使用下面的代码来处理这种情况

df[["new1","new2","new3"]]=pd.DataFrame(df.objs_0.values.tolist(),index=df.index)

因此您可以将列表中的列拆分为名为 new1,new2,new3 的新列

请意识到您分配的列数应该完全等于列表在您要拆分为新列的列中的值数。

上面的代码将保持原始列不变,只需在数据框中添加新列,您可以根据需要选择删除原始列。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-02
    • 2018-04-29
    • 2014-02-02
    • 1970-01-01
    • 2021-12-28
    • 2018-01-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多