使用类型列表的值展平列,同时在Pandas中相应地复制其他列的值

Yu *_*hen 7 python data-manipulation dataframe pandas

亲爱的熊猫专家:

我正在尝试实现一个函数来展平具有list类型元素的数据帧的列,我想要数据帧的每一行,其中列具有list类型的元素,所有列但是指定的列将被展平重复,而指定的列将具有列表中的值之一.

以下说明了我的要求:

input = DataFrame({'A': [1, 2], 'B': [['a', 'b'], 'c']})
     A   B
0    1   [a, b]
1    2   c

expected = DataFrame({'A': [1, 1, 2], 'B': ['a', 'b', 'c']}, index=[0, 0, 1])

     A   B
0    1   a
0    1   b
1    2   c
Run Code Online (Sandbox Code Playgroud)

我觉得可能有一个优雅的解决方案/概念,但我正在努力.

这是我的尝试,但尚未奏效.

def flattenColumn(df, column):
    '''column is a string of the column's name.
    for each value of the column's element (which might be a list), duplicate the rest of columns at the correspdonding row with the (each) value.
    '''
    def duplicate_if_needed(row):
        return concat([concat([row.drop(column, axis = 1), DataFrame({column: each})], axis = 1) for each in row[column][0]])
    return df.groupby(df.index).transform(duplicate_if_needed)
Run Code Online (Sandbox Code Playgroud)

在认识到alko的帮助下,这是我在数据帧中处理2个以上列的解决方案的简单概括:

def flattenColumn(input, column):
    '''
    column is a string of the column's name.
    for each value of the column's element (which might be a list),
    duplicate the rest of columns at the corresponding row with the (each) value.
    '''
    column_flat = pandas.DataFrame(
        [
            [i, c_flattened]
            for i, y in input[column].apply(list).iteritems()
            for c_flattened in y
        ],
        columns=['I', column]
    )
    column_flat = column_flat.set_index('I')
    return (
        input.drop(column, 1)
             .merge(column_flat, left_index=True, right_index=True)
    )
Run Code Online (Sandbox Code Playgroud)

目前唯一的限制是列的顺序发生了变化,列展平将位于最右侧,而不是位于其原始位置.修复应该是可行的.

小智 15

您可以使用 df.explode()。在这里查看这个方法


alk*_*lko 9

我想简单的方法来压缩列表列表将是一个纯python代码,因为这个对象类型不适合pandas或numpy.所以你可以用它来做

>>> b_flat = pd.DataFrame([[i, x] 
...               for i, y in input['B'].apply(list).iteritems() 
...                    for x in y], columns=list('IB'))
>>> b_flat = b_flat.set_index('I')
Run Code Online (Sandbox Code Playgroud)

将B列展平后,您可以将其合并:

>>> input[['A']].merge(b_flat, left_index=True, right_index=True)
   A  B
0  1  a
0  1  b
1  2  c

[3 rows x 2 columns]
Run Code Online (Sandbox Code Playgroud)

如果希望重新创建索引(如预期结果),则可以添加.reset_index(drop=True)到上一个命令.


Ian*_*Gow 5

令人惊讶的是没有更“本地”的解决方案。将 @alko 的答案放入函数中非常简单:

def unnest(df, col, reset_index=False):
    import pandas as pd
    col_flat = pd.DataFrame([[i, x] 
                       for i, y in df[col].apply(list).iteritems() 
                           for x in y], columns=['I', col])
    col_flat = col_flat.set_index('I')
    df = df.drop(col, 1)
    df = df.merge(col_flat, left_index=True, right_index=True)
    if reset_index:
        df = df.reset_index(drop=True)
    return df
Run Code Online (Sandbox Code Playgroud)

然后简单地

input = pd.DataFrame({'A': [1, 2], 'B': [['a', 'b'], 'c']})
expected = unnest(input, 'B')
Run Code Online (Sandbox Code Playgroud)

我想最好允许一次取消嵌套多个列并处理名为 的嵌套列的可能性I,这会破坏此代码。