복붙노트

[PYTHON] pandas DataFrame에서 열을 중첩 제거하려면 어떻게합니까?

PYTHON

pandas 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

이를 위해 무엇을해야합니까?

해결법

  1. ==============================

    1.R과 python을 모두 가지고 있고이 사이트에서 1 년을 보냈던 사용자로서 저는 이런 유형의 질문을 두 번 보았습니다.

    R과 python을 모두 가지고 있고이 사이트에서 1 년을 보냈던 사용자로서 저는 이런 유형의 질문을 두 번 보았습니다.

    R에서 그들은 unest라고 불리는 패키지 tidyr의 빌드 인 함수를 가지고 있기 때문에, 그러나 Python (pandas)에서는이 유형의 질문을위한 빌드 인 함수가 없습니다.

    개체 열 형식은 항상 데이터를 판다의 기능으로 변환하기 어렵게 만듭니다. 이와 같은 데이터를 받았을 때 가장 먼저 떠오르는 것은 열을 "평평하게"또는 부식하지 않는 것입니다.

    방법 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 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)을 여전히 사용한다면 우리는 하나씩 열을 다시 만들 수 없습니다.

    해결책 : 단일 열을 '제거'한 후 인덱스에 조인하거나 병합하십시오.

    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
    

    이전과 완전히 똑같은 열 순서가 필요한 경우 끝에 색인을 추가하십시오.

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

    방법 3 목록 다시 만들기

    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]
    

    다시 색인 또는 loc을 사용하는 방법 4

    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
    

    특수 케이스에는 두 개의 열 유형 객체가 있습니다.

    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
    

    요약 :

    나는 질문 의이 유형에 대한 팬더와 파이썬 함수를 사용하고 있습니다, 당신이 위의 솔루션의 속도에 대해 걱정한다면, 그는 numpy를 사용하고 numpy를 사용하는 것이 빠르기 때문에 user3483203의 대답을 확인할 수 있습니다. 속도가 문제에 영향을 준다면 Cpython과 numba를 추천합니다.

  2. ==============================

    2.옵션 1

    옵션 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)")
    

    공연

  3. ==============================

    3.꽤 추천하지 않는 것 (적어도이 경우 작동) :

    꽤 추천하지 않는 것 (적어도이 경우 작동) :

    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
    
  4. from https://stackoverflow.com/questions/53218931/how-do-i-unnest-a-column-in-a-pandas-dataframe by cc-by-sa and MIT license