Как развернуть (взорвать) столбец в панде DataFrame? - PullRequest
0 голосов
/ 09 ноября 2018

У меня есть следующий DataFrame, где один из столбцов является объектом (ячейка типа списка):

df=pd.DataFrame({'A':[1,2],'B':[[1,2],[1,2]]})
df
Out[458]: 
   A       B
0  1  [1, 2]
1  2  [1, 2]

Мой ожидаемый результат:

   A  B
0  1  1
1  1  2
3  2  1
4  2  2

Что я должен сделать, чтобы достичь этого?


Смежный вопрос

pandas: если содержимое ячейки является списком, создайте строку для каждого элемента в списке

Хороший вопрос и ответ, но он обрабатывает только один столбец со списком (В моем ответе функция самоопределения будет работать для нескольких столбцов, также принятый ответ - это самый трудоемкий apply, что не рекомендуется, проверьте больше info Когда мне нужно использовать pandas apply () в моем коде? )

Ответы [ 11 ]

0 голосов
/ 09 ноября 2018

Как пользователь с R и python, я видел этот тип вопроса пару раз.

В R они имеют встроенную функцию из пакета tidyr, которая называется unnest. Но в Python (pandas) нет встроенной функции для этого типа вопроса.

Я знаю, object столбцы type всегда затрудняют преобразование данных с помощью функции pandas '. Когда я получил такие данные, первое, что пришло в голову, это «сгладить» или развернуть столбцы.

Я использую функции pandas и python для этого типа вопроса. Если вас беспокоит скорость вышеупомянутых решений, проверьте ответ пользователя 3448203, так как он использует numpy и большую часть времени numpy быстрее. Я рекомендую Cpython и numba, если скорость имеет значение в вашем случае.


Метод 0 [панды <= 0,25] </strong>
Начиная с панды 0,25 , если вам нужно только взорвать один столбец, вы можете использовать функцию explode:

df.explode('B')

       A  B
    0  1  1
    1  1  2
    0  2  1
    1  2  2

Метод 1
apply + pd.Series (легко понять, но с точки зрения производительности не рекомендуется.)

df.set_index('A').B.apply(pd.Series).stack().reset_index(level=0).rename(columns={0:'B'})
Out[463]: 
   A  B
0  1  1
1  1  2
0  2  1
1  2  2

Метод 2
Используя repeat с конструктором DataFrame, воссоздайте свой фрейм данных (хорошо работает, плохо работает с несколькими столбцами)

df=pd.DataFrame({'A':df.A.repeat(df.B.str.len()),'B':np.concatenate(df.B.values)})
df
Out[465]: 
   A  B
0  1  1
0  1  2
1  2  1
1  2  2

Метод 2.1
например, кроме A у нас есть A.1 ..... A.n. Если мы все еще используем метод ( Метод 2 ), описанный выше, нам будет трудно заново создать столбцы один за другим.

Решение: join или merge с index после 'unnest' отдельных столбцов

s=pd.DataFrame({'B':np.concatenate(df.B.values)},index=df.index.repeat(df.B.str.len()))
s.join(df.drop('B',1),how='left')
Out[477]: 
   B  A
0  1  1
0  2  1
1  1  2
1  2  2

Если вам нужен порядок столбцов точно такой же, как и раньше, добавьте reindex в конце

s.join(df.drop('B',1),how='left').reindex(columns=df.columns)

Метод 3
воссоздать list

pd.DataFrame([[x] + [z] for x, y in df.values for z in y],columns=df.columns)
Out[488]: 
   A  B
0  1  1
1  1  2
2  2  1
3  2  2

Если больше двух столбцов, используйте

s=pd.DataFrame([[x] + [z] for x, y in zip(df.index,df.B) for z in y])
s.merge(df,left_on=0,right_index=True)
Out[491]: 
   0  1  A       B
0  0  1  1  [1, 2]
1  0  2  1  [1, 2]
2  1  1  2  [1, 2]
3  1  2  2  [1, 2]

Метод 4
используя reindex или loc

df.reindex(df.index.repeat(df.B.str.len())).assign(B=np.concatenate(df.B.values))
Out[554]: 
   A  B
0  1  1
0  1  2
1  2  1
1  2  2

#df.loc[df.index.repeat(df.B.str.len())].assign(B=np.concatenate(df.B.values))

Метод 5
когда список содержит только уникальные значения:

df=pd.DataFrame({'A':[1,2],'B':[[1,2],[3,4]]})
from collections import ChainMap
d = dict(ChainMap(*map(dict.fromkeys, df['B'], df['A'])))
pd.DataFrame(list(d.items()),columns=df.columns[::-1])
Out[574]: 
   B  A
0  1  1
1  2  1
2  3  2
3  4  2

Метод 6
используя numpy для высокой производительности:

newvalues=np.dstack((np.repeat(df.A.values,list(map(len,df.B.values))),np.concatenate(df.B.values)))
pd.DataFrame(data=newvalues[0],columns=df.columns)
   A  B
0  1  1
1  1  2
2  2  1
3  2  2

Метод 7
использование базовой функции itertools cycle и chain: решение Pure Python просто для удовольствия

from itertools import cycle,chain
l=df.values.tolist()
l1=[list(zip([x[0]], cycle(x[1])) if len([x[0]]) > len(x[1]) else list(zip(cycle([x[0]]), x[1]))) for x in l]
pd.DataFrame(list(chain.from_iterable(l1)),columns=df.columns)
   A  B
0  1  1
1  1  2
2  2  1
3  2  2

Обобщение на несколько столбцов

df=pd.DataFrame({'A':[1,2],'B':[[1,2],[3,4]],'C':[[1,2],[3,4]]})
df
Out[592]: 
   A       B       C
0  1  [1, 2]  [1, 2]
1  2  [3, 4]  [3, 4]

Функция самоопределения:

def unnesting(df, explode):
    idx = df.index.repeat(df[explode[0]].str.len())
    df1 = pd.concat([
        pd.DataFrame({x: np.concatenate(df[x].values)}) for x in explode], axis=1)
    df1.index = idx

    return df1.join(df.drop(explode, 1), how='left')


unnesting(df,['B','C'])
Out[609]: 
   B  C  A
0  1  1  1
0  2  2  1
1  3  3  2
1  4  4  2

По столбцам Unnesting

Все вышеприведенные методы говорят о по вертикали о том, чтобы расправиться и взорваться. Если вам нужно потратить список по горизонтали , проверьте с помощью pd.DataFrame конструктор

df.join(pd.DataFrame(df.B.tolist(),index=df.index).add_prefix('B_'))
Out[33]: 
   A       B       C  B_0  B_1
0  1  [1, 2]  [1, 2]    1    2
1  2  [3, 4]  [3, 4]    3    4

Обновлена ​​функция

def unnesting(df, explode, axis):
    if axis==1:
        idx = df.index.repeat(df[explode[0]].str.len())
        df1 = pd.concat([
            pd.DataFrame({x: np.concatenate(df[x].values)}) for x in explode], axis=1)
        df1.index = idx

        return df1.join(df.drop(explode, 1), how='left')
    else :
        df1 = pd.concat([
                         pd.DataFrame(df[x].tolist(), index=df.index).add_prefix(x) for x in explode], axis=1)
        return df1.join(df.drop(explode, 1), how='left')

Тестовый вывод

unnesting(df, ['B','C'], axis=0)
Out[36]: 
   B0  B1  C0  C1  A
0   1   2   1   2  1
1   3   4   3   4  2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...