source

팬더 DataFrame의 컬럼을 여러 줄로 네스트(폭발)하는 방법

manycodes 2023. 1. 19. 21:06
반응형

팬더 DataFrame의 컬럼을 여러 줄로 네스트(폭발)하는 방법

다음 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

이를 달성하려면 어떻게 해야 합니까?


관련 질문

panda: 셀의 내용이 목록일 경우 목록의 각 요소에 대해 행을 만듭니다.

가 있는 내 정의 이 여러 컬럼에 대해 또, 받아들여진 은, 시간이 걸리는 것을 합니다).apply(권장하지 않는 것 같습니다만, 상세 정보를 확인해 주세요).코드에 팬더 어플리케이션()을 사용하는 경우는 언제입니까?

는 알고 있다object은 판다.dtype은 판다 함수를 사용하여 데이터를 변환하기 어렵습니다.이런 데이터를 받으면 가장 먼저 떠오르는 것이 기둥을 "평활화"하거나 풀어야 한다는 것이었습니다.

이런 질문에는 판다와 Python 함수를 사용하고 있습니다.위의 솔루션의 속도가 걱정되는 경우 사용자 3483203의 답변을 확인하십시오. 왜냐하면 사용자 3483203은 numpy를 사용하고 있고 대부분의 경우 numpy가 더 빠르기 때문입니다.속도가 중요하다면 시톤이나 눔바를 추천합니다.


방법 0 [pander > = 0.25] 팬더 0.25부터 1칼럼만 폭발시키면 다음과 같은 기능을 사용할 수 있습니다.

df.explode('B')

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

에 빈 " " " " "list ★★★NaN 있으면 되지 , 리스트가 비어 있으면 문제가 됩니다.NaN로 채워질 필요가 있다.list

df = pd.DataFrame({'A': [1, 2, 3, 4],'B': [[1, 2], [1, 2], [], np.nan]})
df.B = df.B.fillna({i: [] for i in df.index})  # replace NaN with []
df.explode('B')

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

방법 1(이해하기 쉽지만 퍼포먼스 측면에서는 권장하지 않음)

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 사용repeatDataFrame 프레임 않음)을 다시 . 또는 데이터 프레임이 생성되다(데이터 프레임).

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. 위의 방법(Method 2)을 계속 사용하면 열을 하나씩 다시 만드는 것이 어렵습니다.

: ★★★★★★★★★★★★★★:join ★★★★★★★★★★★★★★★★★」mergeindex 뒤에 unnest 뒤에 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

기본 함수를 이용한 방법 7itertools cycle ★★★★★★★★★★★★★★★★★」chain: 재미삼아 순수 비단뱀 솔루션

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

열 단위 네스트 해제

위의 모든 방법은 수직 언네스팅과 폭발에 대해 설명하고 있습니다.목록을 수평으로 소비해야 할 경우 다음 항목을 확인하십시오.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

원래 폭발 기능으로 2021-02-17 업데이트

def unnesting(df, explode, axis):
    if axis==1:
        df1 = pd.concat([df[x].explode() for x in explode], axis=1)
        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')

옵션 1

같은 ,numpy다음과 같은 경우 효율적인 옵션이 될 수 있습니다.

vals = np.array(df.B.values.tolist())    
a = np.repeat(df.A, vals.shape[1])

pd.DataFrame(np.column_stack((a, vals.ravel())), columns=df.columns)

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

옵션 2

서브 리스트의 길이가 다른 경우는, 다음의 순서를 실행할 필요가 있습니다.

vals = df.B.values.tolist()
rs = [len(r) for r in vals]    
a = np.repeat(df.A, rs)

pd.DataFrame(np.column_stack((a, np.concatenate(vals))), columns=df.columns)

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

옵션 3

해서 평탄하게 .N과 타일M칼럼은 나중에 더 효율적으로 만들도록 하겠습니다.

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

   A          B          C  D
0  1     [1, 2]  [1, 2, 3]  A
1  2  [1, 2, 3]     [1, 2]  B
2  3        [1]     [1, 2]  C

def unnest(df, tile, explode):
    vals = df[explode].sum(1)
    rs = [len(r) for r in vals]
    a = np.repeat(df[tile].values, rs, axis=0)
    b = np.concatenate(vals.values)
    d = np.column_stack((a, b))
    return pd.DataFrame(d, columns = tile +  ['_'.join(explode)])

unnest(df, ['A', 'D'], ['B', 'C'])

    A  D B_C
0   1  A   1
1   1  A   2
2   1  A   1
3   1  A   2
4   1  A   3
5   2  B   1
6   2  B   2
7   2  B   3
8   2  B   1
9   2  B   2
10  3  C   1
11  3  C   1
12  3  C   2

기능들

def wen1(df):
    return df.set_index('A').B.apply(pd.Series).stack().reset_index(level=0).rename(columns={0: 'B'})

def wen2(df):
    return pd.DataFrame({'A':df.A.repeat(df.B.str.len()),'B':np.concatenate(df.B.values)})

def wen3(df):
    s = pd.DataFrame({'B': np.concatenate(df.B.values)}, index=df.index.repeat(df.B.str.len()))
    return s.join(df.drop('B', 1), how='left')

def wen4(df):
    return pd.DataFrame([[x] + [z] for x, y in df.values for z in y],columns=df.columns)

def chris1(df):
    vals = np.array(df.B.values.tolist())
    a = np.repeat(df.A, vals.shape[1])
    return pd.DataFrame(np.column_stack((a, vals.ravel())), columns=df.columns)

def chris2(df):
    vals = df.B.values.tolist()
    rs = [len(r) for r in vals]
    a = np.repeat(df.A.values, rs)
    return pd.DataFrame(np.column_stack((a, np.concatenate(vals))), columns=df.columns)

타이밍

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from timeit import timeit

res = pd.DataFrame(
       index=['wen1', 'wen2', 'wen3', 'wen4', 'chris1', 'chris2'],
       columns=[10, 50, 100, 500, 1000, 5000, 10000],
       dtype=float
)

for f in res.index:
    for c in res.columns:
        df = pd.DataFrame({'A': [1, 2], 'B': [[1, 2], [1, 2]]})
        df = pd.concat([df]*c)
        stmt = '{}(df)'.format(f)
        setp = 'from __main__ import df, {}'.format(f)
        res.at[f, c] = timeit(stmt, setp, number=50)

ax = res.div(res.min()).T.plot(loglog=True)
ax.set_xlabel("N")
ax.set_ylabel("time (relative)")

성능

여기에 이미지 설명 입력

리스트와 같은 기둥을 폭발시키는 것은 팬더 0.25에서 상당히 단순화되었습니다.explode()★★★★

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

출력:

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

한 가지 대안은 메쉬그리드 레시피를 컬럼의 행에 적용하여 네스트 해제하는 것입니다.

import numpy as np
import pandas as pd


def unnest(frame, explode):
    def mesh(values):
        return np.array(np.meshgrid(*values)).T.reshape(-1, len(values))

    data = np.vstack(mesh(row) for row in frame[explode].values)
    return pd.DataFrame(data=data, columns=explode)


df = pd.DataFrame({'A': [1, 2], 'B': [[1, 2], [1, 2]]})
print(unnest(df, ['A', 'B']))  # base
print()

df = pd.DataFrame({'A': [1, 2], 'B': [[1, 2], [3, 4]], 'C': [[1, 2], [3, 4]]})
print(unnest(df, ['A', 'B', 'C']))  # multiple columns
print()

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

print(unnest(df, ['A', 'B']))  # uneven length lists
print()
print(unnest(df, ['D', 'B']))  # different types
print()

산출량

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

   A  B  C
0  1  1  1
1  1  2  1
2  1  1  2
3  1  2  2
4  2  3  3
5  2  4  3
6  2  3  4
7  2  4  4

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

   D  B
0  A  1
1  A  2
2  B  1
3  B  2
4  B  3
5  C  1

문제의 셋업

길이가 다른 개체가 포함된 열이 여러 개 있다고 가정합니다.

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

df

   A       B          C
0  1  [1, 2]     [1, 2]
1  2  [3, 4]  [3, 4, 5]

길이가 같으면 다양한 요소가 일치하고 함께 "zip"되어야 한다고 생각하기 쉽습니다.

   A       B          C
0  1  [1, 2]     [1, 2]  # Typical to assume these should be zipped [(1, 1), (2, 2)]
1  2  [3, 4]  [3, 4, 5]

단, 길이가 다른 오브젝트를 볼 때는 그 전제조건에 의문이 생깁니다.그렇다면 오브젝트 중 하나에서 초과된 오브젝트를 어떻게 처리할 것인가?아니면, 우리는 모든 물건의 제품을 원할 수도 있습니다.이것은 빠르게 커지겠지만, 아마도 원하는 것일 것이다.

   A       B          C
0  1  [1, 2]     [1, 2]
1  2  [3, 4]  [3, 4, 5]  # is this [(3, 3), (4, 4), (None, 5)]?

또는

   A       B          C
0  1  [1, 2]     [1, 2]
1  2  [3, 4]  [3, 4, 5]  # is this [(3, 3), (3, 4), (3, 5), (4, 3), (4, 4), (4, 5)]

기능

은 우아하게 처리됩니다.zip ★★★★★★★★★★★★★★★★★」product해, 라고 가정한다.zip가장 긴 물체의 길이에 따라zip_longest

from itertools import zip_longest, product

def xplode(df, explode, zipped=True):
    method = zip_longest if zipped else product

    rest = {*df} - {*explode}

    zipped = zip(zip(*map(df.get, rest)), zip(*map(df.get, explode)))
    tups = [tup + exploded
     for tup, pre in zipped
     for exploded in method(*pre)]

    return pd.DataFrame(tups, columns=[*rest, *explode])[[*df]]

압축된

xplode(df, ['B', 'C'])

   A    B  C
0  1  1.0  1
1  1  2.0  2
2  2  3.0  3
3  2  4.0  4
4  2  NaN  5

제품.

xplode(df, ['B', 'C'], zipped=False)

   A  B  C
0  1  1  1
1  1  1  2
2  1  2  1
3  1  2  2
4  2  3  3
5  2  3  4
6  2  3  5
7  2  4  3
8  2  4  4
9  2  4  5

신규 셋업

예를 조금 더 높이다

df = pd.DataFrame({
    'A': [1, 2],
    'B': [[1, 2], [3, 4]],
    'C': 'C',
    'D': [[1, 2], [3, 4, 5]],
    'E': [('X', 'Y', 'Z'), ('W',)]
})

df

   A       B  C          D          E
0  1  [1, 2]  C     [1, 2]  (X, Y, Z)
1  2  [3, 4]  C  [3, 4, 5]       (W,)

압축된

xplode(df, ['B', 'D', 'E'])

   A    B  C    D     E
0  1  1.0  C  1.0     X
1  1  2.0  C  2.0     Y
2  1  NaN  C  NaN     Z
3  2  3.0  C  3.0     W
4  2  4.0  C  4.0  None
5  2  NaN  C  5.0  None

제품.

xplode(df, ['B', 'D', 'E'], zipped=False)

    A  B  C  D  E
0   1  1  C  1  X
1   1  1  C  1  Y
2   1  1  C  1  Z
3   1  1  C  2  X
4   1  1  C  2  Y
5   1  1  C  2  Z
6   1  2  C  1  X
7   1  2  C  1  Y
8   1  2  C  1  Z
9   1  2  C  2  X
10  1  2  C  2  Y
11  1  2  C  2  Z
12  2  3  C  3  W
13  2  3  C  4  W
14  2  3  C  5  W
15  2  4  C  3  W
16  2  4  C  4  W
17  2  4  C  5  W

내 5센트:

df[['B', 'B2']] = pd.DataFrame(df['B'].values.tolist())

df[['A', 'B']].append(df[['A', 'B2']].rename(columns={'B2': 'B'}),
                      ignore_index=True)

기타 5개

df[['B1', 'B2']] = pd.DataFrame([*df['B']]) # if values.tolist() is too boring

(pd.wide_to_long(df.drop('B', 1), 'B', 'A', '')
 .reset_index(level=1, drop=True)
 .reset_index())

둘 다 같은 결과를 낳는다

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

일반적으로 서브리스트의 길이가 다르고 가입/합병 비용이 훨씬 더 많이 들기 때문입니다.다른 길이의 하위 목록과 더 일반적인 열에 대해 방법을 다시 테스트했습니다.

MultiIndex는 쓰기 쉬운 방법으로 numpy 방식과 거의 동일한 성능을 제공합니다.

놀랍게도, 제 실장 방식으로는 이해력이 가장 뛰어난 성능을 발휘합니다.

def stack(df):
    return df.set_index(['A', 'C']).B.apply(pd.Series).stack()


def comprehension(df):
    return pd.DataFrame([x + [z] for x, y in zip(df[['A', 'C']].values.tolist(), df.B) for z in y])


def multiindex(df):
    return pd.DataFrame(np.concatenate(df.B.values), index=df.set_index(['A', 'C']).index.repeat(df.B.str.len()))


def array(df):
    return pd.DataFrame(
        np.column_stack((
            np.repeat(df[['A', 'C']].values, df.B.str.len(), axis=0),
            np.concatenate(df.B.values)
        ))
    )


import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from timeit import timeit

res = pd.DataFrame(
    index=[
        'stack',
        'comprehension',
        'multiindex',
        'array',
    ],
    columns=[1000, 2000, 5000, 10000, 20000, 50000],
    dtype=float
)

for f in res.index:
    for c in res.columns:
        df = pd.DataFrame({'A': list('abc'), 'C': list('def'), 'B': [['g', 'h', 'i'], ['j', 'k'], ['l']]})
        df = pd.concat([df] * c)
        stmt = '{}(df)'.format(f)
        setp = 'from __main__ import df, {}'.format(f)
        res.at[f, c] = timeit(stmt, setp, number=20)

ax = res.div(res.min()).T.plot(loglog=True)
ax.set_xlabel("N")
ax.set_ylabel("time (relative)")

성능

각 방법의 상대 시간

나는 그 문제를 더 많은 열에 적용하기 위해 조금 일반화했다.

솔루션의 기능 개요:

In[74]: df
Out[74]: 
    A   B             C             columnD
0  A1  B1  [C1.1, C1.2]                D1
1  A2  B2  [C2.1, C2.2]  [D2.1, D2.2, D2.3]
2  A3  B3            C3        [D3.1, D3.2]

In[75]: dfListExplode(df,['C','columnD'])
Out[75]: 
    A   B     C columnD
0  A1  B1  C1.1    D1
1  A1  B1  C1.2    D1
2  A2  B2  C2.1    D2.1
3  A2  B2  C2.1    D2.2
4  A2  B2  C2.1    D2.3
5  A2  B2  C2.2    D2.1
6  A2  B2  C2.2    D2.2
7  A2  B2  C2.2    D2.3
8  A3  B3    C3    D3.1
9  A3  B3    C3    D3.2

완전한 예:

실제 폭발은 3줄로 이루어집니다.나머지는 화장품입니다(다기둥 폭발, 폭발란의 리스트가 아닌 문자열 취급 등).

import pandas as pd
import numpy as np

df=pd.DataFrame( {'A': ['A1','A2','A3'],
                  'B': ['B1','B2','B3'],
                  'C': [ ['C1.1','C1.2'],['C2.1','C2.2'],'C3'],
                  'columnD': [ 'D1',['D2.1','D2.2', 'D2.3'],['D3.1','D3.2']],
                  })
print('df',df, sep='\n')

def dfListExplode(df, explodeKeys):
    if not isinstance(explodeKeys, list):
        explodeKeys=[explodeKeys]
    # recursive handling of explodeKeys
    if len(explodeKeys)==0:
        return df
    elif len(explodeKeys)==1:
        explodeKey=explodeKeys[0]
    else:
        return dfListExplode( dfListExplode(df, explodeKeys[:1]), explodeKeys[1:])
    # perform explosion/unnesting for key: explodeKey
    dfPrep=df[explodeKey].apply(lambda x: x if isinstance(x,list) else [x]) #casts all elements to a list
    dfIndExpl=pd.DataFrame([[x] + [z] for x, y in zip(dfPrep.index,dfPrep.values) for z in y ], columns=['explodedIndex',explodeKey])
    dfMerged=dfIndExpl.merge(df.drop(explodeKey, axis=1), left_on='explodedIndex', right_index=True)
    dfReind=dfMerged.reindex(columns=list(df))
    return dfReind

dfExpl=dfListExplode(df,['C','columnD'])
print('dfExpl',dfExpl, sep='\n')

WeNYoBen 답변 크레딧

권장하지 않는 것(적어도 이 경우에는 작동):

df=pd.concat([df]*2).sort_index()
it=iter(df['B'].tolist()[0]+df['B'].tolist()[0])
df['B']=df['B'].apply(lambda x:next(it))

concat+sort_index+iter+apply+next.

지금:

print(df)

다음 중 하나:

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

인덱스에 관심이 있는 경우:

df=df.reset_index(drop=True)

지금:

print(df)

다음 중 하나:

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

pd.concat([df['A'], pd.DataFrame(df['B'].values.tolist())], axis = 1)\
  .melt(id_vars = 'A', value_name = 'B')\
  .dropna()\
  .drop('variable', axis = 1)

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

제가 생각한 이 방법에 대한 의견은요?아니면 콘코트와 멜트를 모두 사용하는 것이 너무 "불편한" 것으로 간주되는가?

두 개 이상의 컬럼이 폭발할 때 해결할 다른 좋은 방법이 있어요

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

print(df)
   A       B          C
0  1  [1, 2]  [1, 2, 3]
1  2  [1, 2]  [1, 2, 3]

나는 B와 C열을 폭발시키고 싶다.먼저 B를 터뜨리고, 두번째 C를 터뜨린다.그리고 나는 원래 df에서 B와 C를 떨어뜨린다.그 후 3개의 dfs에 인덱스 조인을 합니다.

explode_b = df.explode('B')['B']
explode_c = df.explode('C')['C']
df = df.drop(['B', 'C'], axis=1)
df = df.join([explode_b, explode_c])
df=pd.DataFrame({'A':[1,2],'B':[[1,2],[1,2]]})

out = pd.concat([df.loc[:,'A'],(df.B.apply(pd.Series))], axis=1, sort=False)

out = out.set_index('A').stack().droplevel(level=1).reset_index().rename(columns={0:"B"})

       A    B
   0    1   1
   1    1   2
   2    2   1
   3    2   2
  • 중간 오브젝트를 작성하지 않을 경우 이를 하나의 라이너로 구현할 수 있습니다.
# Here's the answer to the related question in:
# https://stackoverflow.com/q/56708671/11426125

# initial dataframe
df12=pd.DataFrame({'Date':['2007-12-03','2008-09-07'],'names':
[['Peter','Alex'],['Donald','Stan']]})

# convert dataframe to array for indexing list values (names)
a = np.array(df12.values)  

# create a new, dataframe with dimensions for unnested
b = np.ndarray(shape = (4,2))
df2 = pd.DataFrame(b, columns = ["Date", "names"], dtype = str)

# implement loops to assign date/name values as required
i = range(len(a[0]))
j = range(len(a[0]))
for x in i:
    for y in j:
        df2.iat[2*x+y, 0] = a[x][0]
        df2.iat[2*x+y, 1] = a[x][1][y]

# set Date column as Index
df2.Date=pd.to_datetime(df2.Date)
df2.index=df2.Date
df2.drop('Date',axis=1,inplace =True)

두 개 이상의 열이 폭발하고 배열의 변수 길이가 중첩되지 않아야 하는 경우입니다.

나는 결국 새로운 팬더 0.25를 적용했다.explode두 번 기능하고 생성된 중복을 제거하면 작업이 수행됩니다.

df = df.explode('A')
df = df.explode('B')
df = df.drop_duplicates()

아래는 @BEN_에 기반한 수평 폭발의 간단한 함수입니다.YO의 대답입니다.

import typing
import pandas as pd

def horizontal_explode(df: pd.DataFrame, col_name: str, new_columns: typing.Union[list, None]=None) -> pd.DataFrame:
    t = pd.DataFrame(df[col_name].tolist(), columns=new_columns, index=df.index)
    return pd.concat([df, t], axis=1)

실행 예:

items = [
    ["1", ["a", "b", "c"]],
    ["2", ["d", "e", "f"]]
]

df = pd.DataFrame(items, columns = ["col1", "col2"])
print(df)

t = horizontal_explode(df=df, col_name="col2")
del t["col2"]
print(t)

t = horizontal_explode(df=df, col_name="col2", new_columns=["new_col1", "new_col2", "new_col3"])
del t["col2"]
print(t)

관련 출력은 다음과 같습니다.

  col1       col2
0    1  [a, b, c]
1    2  [d, e, f]

  col1  0  1  2
0    1  a  b  c
1    2  d  e  f

  col1 new_col1 new_col2 new_col3
0    1        a        b        c
1    2        d        e        f
 demo = {'set1':{'t1':[1,2,3],'t2':[4,5,6],'t3':[7,8,9]}, 'set2':{'t1':[1,2,3],'t2':[4,5,6],'t3':[7,8,9]}, 'set3': {'t1':[1,2,3],'t2':[4,5,6],'t3':[7,8,9]}}
 df = pd.DataFrame.from_dict(demo, orient='index') 

 print(df.head())
 my_list=[]
 df2=pd.DataFrame(columns=['set','t1','t2','t3'])

 for key,item in df.iterrows():
    t1=item.t1
    t2=item.t2
    t3=item.t3
    mat1=np.matrix([t1,t2,t3])
    row1=[key,mat1[0,0],mat1[0,1],mat1[0,2]]
    df2.loc[len(df2)]=row1
    row2=[key,mat1[1,0],mat1[1,1],mat1[1,2]]
    df2.loc[len(df2)]=row2
    row3=[key,mat1[2,0],mat1[2,1],mat1[2,2]]
    df2.loc[len(df2)]=row3

print(df2) 

set t1 t2 t3
0  set1  1  2  3
1  set1  4  5  6
2  set1  7  8  9
3  set2  1  2  3
4  set2  4  5  6
5  set2  7  8  9
6  set3  1  2  3
7  set3  4  5  6
8  set3  7  8  9   

언급URL : https://stackoverflow.com/questions/53218931/how-to-unnest-explode-a-column-in-a-pandas-dataframe-into-multiple-rows

반응형