R
및 을 모두 사용하는 사용자로서 python
이러한 유형의 질문을 두 번 보았습니다.
R에서는 tidyr
라는 패키지의 내장 함수가 있습니다 unnest
. 그러나 Python
( pandas
)에는 이러한 유형의 질문에 대한 내장 함수가 없습니다.
object
열은 type
항상 pandas
'함수 로 데이터를 변환하기 어렵게 만든다는 것을 알고 있습니다 . 이와 같은 데이터를 받았을 때 가장 먼저 떠오른 것은 열을 '평탄화'하거나 중첩 해제하는 것입니다.
이 유형의 질문에 대해 pandas
및 python
기능을 사용 하고 있습니다. 위 솔루션의 속도가 걱정된다면 user3483203의 답변을 확인하세요. 그가 사용 numpy
하고 있고 대부분의 시간 numpy
이 더 빠르기 때문입니다. 나는 추천 Cpython
과 numba
속도가 귀하의 경우 중요합니다.
방법 0 [pandas> = 0.25] pandas 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
생성자는 다시 작성 (여러 열에서 좋지 않은 성능 좋은) 당신의 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 ..... An 위 의 방법 ( 방법 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]
또는
사용하는 방법 4reindex
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
고성능
을 numpy
위해 사용 하는 방법 6 :
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