在DataFrame中爆炸多个相同长度的列表

时间:2019-08-28 09:29:00

标签: python pandas

我有一个Pandas DataFrame,在列中有几个列表我想拆分。每个列表具有相同的长度,并且必须在相同的索引处进行拆分。

我现在使用的是here的建议,但我无法使它起作用:

import numpy as np
import pandas as pd
from itertools import chain

split_size = 2

def split_list(arr, keep_partial=False):
    arrs = []
    while len(arr) >= split_size:
        sub = arr[:split_size]
        arrs.append(sub)
        arr   = arr[split_size:]
    if keep_partial:
        arrs.append(arr)
    return arrs


df = pd.DataFrame({'id': [1, 2, 3], 't': [[1,2,3,4], [1,2,3,4,5,6], [0,2]], 'v': [[0,-1,1,0], [0,-1,1,0,2,-2], [0,0]]})

def chainer(lst):
    return list(chain.from_iterable(split_list(lst, split_size)))

def chain_col(col):
    return col.apply(lambda x: chainer(x))

lens = df.t.apply(lambda x: len(split_list(x)))

pd.DataFrame({'id': np.repeat(df.id, lens), 't': chain_col(df.t), 'v': chain_col(df.v)})

问题在于它会重复每个 full 列表,而不是将它们分成几行。我认为问题在于chain.from_iterable的用法,但如果没有它,我只会重复获取列表列表(即拆分列表),而不是将每个拆分列表都拆分到DataFrame中自己的行。

我的数据集不是很大(几千行),所以如果有更好的方法,我将很高兴学习。我看着explode,但这似乎是根据单个列拆分数据集,我希望以相同的方式拆分多个列。

我想要的输出是id = 1

1. a row with t = [1,2] and v = [0,-1]
2. another row with t = [3,4] = [1,0]

理想情况下我将为每个“ id”添加一个子索引(例如1-> 1.1和1.2,这样我就可以区分它们),但这只是表面上的事情,而不是我的主要问题。

2 个答案:

答案 0 :(得分:0)

IIUC,这是一种使用功能的方法,该功能将列表拆分为n个块,然后用applymap拆分每个单元格,然后是explodeimplementation group: 'org.jpmml', name: 'jpmml-evaluator-spark', version: '1.0.0'

concat

def split_lists(l, n):
    """splits a list to n chunks"""
    for i in range(0, len(l), n):  
        yield l[i:i + n]  

def explode_multiple(x):
    """This will use the prev func, 
       explode each columns and concat them to a dataframe"""
    m=x.applymap(lambda x: [*split_lists(x,2)])
    m=pd.concat([m.explode(i).loc[:,i] for i in m.columns],axis=1).reset_index()
    return m

explode_multiple(df.set_index('id')) #setting id as index since other columns have list

答案 1 :(得分:0)

使用explodepd.concatGroupBy

注意:此答案使用了仅explode

中可用的新pandas>=0.25.0方法
d1 = df.explode('t').drop(columns='v')
d2 = df.explode('v').drop(columns=['id', 't'])

df2 = pd.concat([d1,d2], axis=1)
df2

s = df2.groupby('id')['id'].cumcount()//2

final = df2.groupby(['id', s]).agg({'t':list,
                                    'v':list}).reset_index(level=0)

final['id'] = final['id'].astype(str).str.cat('.'+final.groupby('id').cumcount().add(1).astype(str))

输出

    id       t        v
0  1.1  [1, 2]  [0, -1]
1  1.2  [3, 4]   [1, 0]
0  2.1  [1, 2]  [0, -1]
1  2.2  [3, 4]   [1, 0]
2  2.3  [5, 6]  [2, -2]
0  3.1  [0, 2]   [0, 0]