복붙노트

[PYTHON] 판다에서 인형으로 범주 형 변수 재구성

PYTHON

판다에서 인형으로 범주 형 변수 재구성

pd.get_dummies를 사용하면 범주 형 변수를 더미 변수로 변환 할 수 있습니다. 범주 형 변수를 재구성하는 것이 사소한 것 외에도,이를 수행하는 것이 바람직한 / 빠른 방법이 있습니까?

해결법

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

    1.

    In [46]: s = Series(list('aaabbbccddefgh')).astype('category')
    
    In [47]: s
    Out[47]: 
    0     a
    1     a
    2     a
    3     b
    4     b
    5     b
    6     c
    7     c
    8     d
    9     d
    10    e
    11    f
    12    g
    13    h
    dtype: category
    Categories (8, object): [a < b < c < d < e < f < g < h]
    
    In [48]: df = pd.get_dummies(s)
    
    In [49]: df
    Out[49]: 
        a  b  c  d  e  f  g  h
    0   1  0  0  0  0  0  0  0
    1   1  0  0  0  0  0  0  0
    2   1  0  0  0  0  0  0  0
    3   0  1  0  0  0  0  0  0
    4   0  1  0  0  0  0  0  0
    5   0  1  0  0  0  0  0  0
    6   0  0  1  0  0  0  0  0
    7   0  0  1  0  0  0  0  0
    8   0  0  0  1  0  0  0  0
    9   0  0  0  1  0  0  0  0
    10  0  0  0  0  1  0  0  0
    11  0  0  0  0  0  1  0  0
    12  0  0  0  0  0  0  1  0
    13  0  0  0  0  0  0  0  1
    
    In [50]: x = df.stack()
    
    # I don't think you actually need to specify ALL of the categories here, as by definition
    # they are in the dummy matrix to start (and hence the column index)
    In [51]: Series(pd.Categorical(x[x!=0].index.get_level_values(1)))
    Out[51]: 
    0     a
    1     a
    2     a
    3     b
    4     b
    5     b
    6     c
    7     c
    8     d
    9     d
    10    e
    11    f
    12    g
    13    h
    Name: level_1, dtype: category
    Categories (8, object): [a < b < c < d < e < f < g < h]
    

    그래서 자연스러운 행동 인 것처럼 우리가 '할'기능이 필요하다고 생각합니다. 어쩌면 get_categories (), 여기를 보아라.

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

    2.몇 년이 지났습니다.이 질문은 원래 질문을 받았을 때 팬더 툴킷에 없었을 수도 있지만,이 접근법은 나에게 조금 더 쉬워 보입니다. idxmax는 가장 큰 요소 (즉 1이있는 요소)에 해당하는 인덱스를 반환합니다. 우리는 1이 발생하는 열 이름을 원하기 때문에 axis = 1을 수행합니다.

    몇 년이 지났습니다.이 질문은 원래 질문을 받았을 때 팬더 툴킷에 없었을 수도 있지만,이 접근법은 나에게 조금 더 쉬워 보입니다. idxmax는 가장 큰 요소 (즉 1이있는 요소)에 해당하는 인덱스를 반환합니다. 우리는 1이 발생하는 열 이름을 원하기 때문에 axis = 1을 수행합니다.

    편집 : 나는 그것을 단순한 문자열 대신에 범주화하지 않았지만, @ Jeff가 pd.Categorical (그리고 pd.Series, 원할 경우)으로 감싸는 것과 같은 방식으로 그렇게 할 수있다.

    In [1]: import pandas as pd
    
    In [2]: s = pd.Series(['a', 'b', 'a', 'c'])
    
    In [3]: s
    Out[3]: 
    0    a
    1    b
    2    a
    3    c
    dtype: object
    
    In [4]: dummies = pd.get_dummies(s)
    
    In [5]: dummies
    Out[5]: 
       a  b  c
    0  1  0  0
    1  0  1  0
    2  1  0  0
    3  0  0  1
    
    In [6]: s2 = dummies.idxmax(axis=1)
    
    In [7]: s2
    Out[7]: 
    0    a
    1    b
    2    a
    3    c
    dtype: object
    
    In [8]: (s2 == s).all()
    Out[8]: True
    

    @ piRSquared 님의 의견에 대한 응답으로 편집 : 이 솔루션은 실제로 행당 1 개가 있다고 가정합니다. 나는 이것이 일반적으로 하나의 형식이라고 생각한다. pd_get_dummies는 drop_first = True 또는 NaN 값이 있고 dummy_na = False (기본값) (누락 된 경우)가있는 경우 모두 0 인 행을 반환 할 수 있습니다. 모든 0 행은 첫 번째 열 (예 : 위의 예에서)에 명명 된 변수의 인스턴스 인 것처럼 처리됩니다.

    drop_first = True 인 경우, "첫 번째"변수의 이름이 무엇인지 인형 데이터 프레임만으로 알 수있는 방법이 없기 때문에 추가 정보를 유지하지 않으면 작업이 반전되지 않습니다. drop_first = False (기본값)로 두는 것이 좋습니다.

    dummy_na = False가 기본값이기 때문에 문제가 발생할 수 있습니다. 이 솔루션을 사용하여 "dummification"을 반전시키고 데이터에 NaN이 포함되어 있다면 pd.get_dummies를 호출 할 때 dummy_na = True를 설정하십시오. dummy_na = True로 설정하면 해당 열이 모두 0 인 경우에도 항상 "nan"열이 추가되므로 실제로 NaN이 없으면 설정하지 않는 것이 좋습니다. 좋은 방법은 더미 세트 = pd.get_dummies (series, dummy_na = series.isnull (). any ())를 설정하는 것입니다. 또한 좋은 점은 idxmax 솔루션이 NaN을 정확하게 재생성한다는 것입니다 ( "nan"이라고하는 문자열이 아님).

    또한 drop_first = True 및 dummy_na = False를 설정하면 NaN이 첫 번째 변수의 인스턴스와 구별 할 수 없으므로 데이터 세트에 NaN 값이 포함될 수있는 경우에는이 설정을 사용하지 않는 것이 좋습니다.

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

    3.이것은 꽤 늦은 대답이지만, 당신이 그것을 할 수있는 빠른 방법을 요구하기 때문에, 나는 당신이 가장 뛰어난 전략을 찾고 있다고 가정합니다. 큰 데이터 프레임 (예 : 10000 행)에서는 idxmax 또는 get_level_values ​​대신 np.where를 사용하여 매우 빠른 속도 향상을 얻을 수 있으며 동일한 결과를 얻을 수 있습니다. 아이디어는 더미 데이터 프레임이 0이 아닌 열 이름을 인덱싱하는 것입니다.

    이것은 꽤 늦은 대답이지만, 당신이 그것을 할 수있는 빠른 방법을 요구하기 때문에, 나는 당신이 가장 뛰어난 전략을 찾고 있다고 가정합니다. 큰 데이터 프레임 (예 : 10000 행)에서는 idxmax 또는 get_level_values ​​대신 np.where를 사용하여 매우 빠른 속도 향상을 얻을 수 있으며 동일한 결과를 얻을 수 있습니다. 아이디어는 더미 데이터 프레임이 0이 아닌 열 이름을 인덱싱하는 것입니다.

    @ Nathan과 동일한 샘플 데이터 사용 :

    >>> dummies
       a  b  c
    0  1  0  0
    1  0  1  0
    2  1  0  0
    3  0  0  1
    
    s2 = pd.Series(dummies.columns[np.where(dummies!=0)[1]])
    
    >>> s2
    0    a
    1    b
    2    a
    3    c
    dtype: object
    

    작은 더미 데이터 프레임에서는 성능에 큰 차이가 없습니다. 그러나 대형 시리즈에서이 문제를 해결하기위한 다양한 전략을 테스트하십시오.

    s = pd.Series(np.random.choice(['a','b','c'], 10000))
    
    dummies = pd.get_dummies(s)
    
    def np_method(dummies=dummies):
        return pd.Series(dummies.columns[np.where(dummies!=0)[1]])
    
    def idx_max_method(dummies=dummies):
        return dummies.idxmax(axis=1)
    
    def get_level_values_method(dummies=dummies):
        x = dummies.stack()
        return pd.Series(pd.Categorical(x[x!=0].index.get_level_values(1)))
    
    def dot_method(dummies=dummies):
        return dummies.dot(dummies.columns)
    
    import timeit
    
    # Time each method, 1000 iterations each:
    
    >>> timeit.timeit(np_method, number=1000)
    1.0491090340074152
    
    >>> timeit.timeit(idx_max_method, number=1000)
    12.119140846014488
    
    >>> timeit.timeit(get_level_values_method, number=1000)
    4.109266621991992
    
    >>> timeit.timeit(dot_method, number=1000)
    1.6741622970002936
    

    np.where 메서드는 idxmax 메서드보다 11.5 배 빠른 get_level_values ​​메서드보다 약 4 배 빠릅니다! 유사한 질문에 대한이 대답에서 개략적으로 설명한 .dot () 메서드를 깨는 것입니다 (하지만 약간 만).

    그들은 모두 동일한 결과를 반환합니다.

    >>> (get_level_values_method() == np_method()).all()
    True
    >>> (idx_max_method() == np_method()).all()
    True
    
  4. ==============================

    4.@ Jeff의 설정 사용하기

    @ Jeff의 설정 사용하기

    s = Series(list('aaabbbccddefgh')).astype('category')
    df = pd.get_dummies(s)
    

    한 줄당 하나씩

    df.dot(df.columns)
    
    0     a
    1     a
    2     a
    3     b
    4     b
    5     b
    6     c
    7     c
    8     d
    9     d
    10    e
    11    f
    12    g
    13    h
    dtype: object
    

    다시! 행당 하나만 가정

    i, j = np.where(df)
    pd.Series(df.columns[j], i)
    
    0     a
    1     a
    2     a
    3     b
    4     b
    5     b
    6     c
    7     c
    8     d
    9     d
    10    e
    11    f
    12    g
    13    h
    dtype: category
    Categories (8, object): [a, b, c, d, e, f, g, h]
    

    행당 하나씩 가정하지 않음

    i, j = np.where(df)
    pd.Series(dict(zip(zip(i, j), df.columns[j])))
    
    0   0    a
    1   0    a
    2   0    a
    3   1    b
    4   1    b
    5   1    b
    6   2    c
    7   2    c
    8   3    d
    9   3    d
    10  4    e
    11  5    f
    12  6    g
    13  7    h
    dtype: object
    

    우리가 행당 1 개를 가정하지 않고 색인을 삭제하면

    i, j = np.where(df)
    pd.Series(dict(zip(zip(i, j), df.columns[j]))).reset_index(-1, drop=True)
    
    0     a
    1     a
    2     a
    3     b
    4     b
    5     b
    6     c
    7     c
    8     d
    9     d
    10    e
    11    f
    12    g
    13    h
    dtype: object
    
  5. from https://stackoverflow.com/questions/26762100/reconstruct-a-categorical-variable-from-dummies-in-pandas by cc-by-sa and MIT license