python pandas는 중복 열을 제거합니다.


126

데이터 프레임에서 중복 열을 제거하는 가장 쉬운 방법은 무엇입니까?

다음을 통해 중복 열이있는 텍스트 파일을 읽고 있습니다.

import pandas as pd

df=pd.read_table(fname)

열 이름은 다음과 같습니다.

Time, Time Relative, N2, Time, Time Relative, H2, etc...

모든 시간 및 시간 관련 열에는 동일한 데이터가 포함됩니다. 내가 원하는:

Time, Time Relative, N2, H2

삭제, 삭제 등의 모든 시도 :

df=df.T.drop_duplicates().T

고유 값 인덱스 오류가 발생합니다.

Reindexing only valid with uniquely valued index objects

팬더 멍청이가되어서 미안 해요. 모든 제안을 주시면 감사하겠습니다.


추가 세부 사항

Pandas 버전 : 0.9.0
Python 버전 : 2.7.3
Windows 7
(Pythonxy 2.7.3.0을 통해 설치됨)

데이터 파일 (참고 : 실제 파일에서 열은 탭으로 구분되며 여기서는 4 개의 공백으로 구분됩니다) :

Time    Time Relative [s]    N2[%]    Time    Time Relative [s]    H2[ppm]
2/12/2013 9:20:55 AM    6.177    9.99268e+001    2/12/2013 9:20:55 AM    6.177    3.216293e-005    
2/12/2013 9:21:06 AM    17.689    9.99296e+001    2/12/2013 9:21:06 AM    17.689    3.841667e-005    
2/12/2013 9:21:18 AM    29.186    9.992954e+001    2/12/2013 9:21:18 AM    29.186    3.880365e-005    
... etc ...
2/12/2013 2:12:44 PM    17515.269    9.991756+001    2/12/2013 2:12:44 PM    17515.269    2.800279e-005    
2/12/2013 2:12:55 PM    17526.769    9.991754e+001    2/12/2013 2:12:55 PM    17526.769    2.880386e-005
2/12/2013 2:13:07 PM    17538.273    9.991797e+001    2/12/2013 2:13:07 PM    17538.273    3.131447e-005

어떤 버전의 팬더가 있습니까? ( import pandas as pd; pd.__version__ )
beardc 2013

1
@BirdJaguarIV, 저는 팬더 버전 0.9.0을 사용하고 있습니다
Onlyjus

0.10으로 업그레이드 할 수 있습니다. 내 버전은 read_table내가 만든 예제 에서 열을 고유하게 만듭니다 .
beardc

df = df.T.drop_duplicates (). T는 열 이름을 고려하지 않습니다. 데이터는 같지만 이름이 다른 두 개의 열이있는 경우 하나는 잘못 삭제됩니다.
Joylove

답변:


392

문제에 대한 한 줄 해결책이 있습니다. 이것은 일부 열 이름이 중복되어 제거하려는 경우에 적용됩니다.

df = df.loc[:,~df.columns.duplicated()]

작동 원리 :

데이터 프레임의 열이 다음과 같다고 가정합니다. ['alpha','beta','alpha']

df.columns.duplicated()부울 배열을 반환합니다 : a True또는 False각 열에 대해. 그렇다면 False열 이름은 해당 지점까지 고유하고, 그렇다면 True열 이름은 이전에 중복됩니다. 예를 들어 주어진 예제를 사용하면 반환되는 값은입니다 [False,False,True].

Pandas부울 값을 사용하여 색인을 생성하여 값만 선택하도록 True합니다. 우리는 중복되지 열을 유지하려는 때문에, 우리는 이성을 상실하는 부울 배열 이상 (예를 필요 [True, True, False] = ~[False,False,True])

마지막으로 df.loc[:,[True,True,False]]앞서 언급 한 인덱싱 기능을 사용하여 중복되지 않은 열만 선택합니다.

참고 : 위는 열 값이 아닌 열 이름 만 확인 합니다.


16
이상적인 대답은 이름뿐만 아니라 중복 된 값에도 적용됩니다.
GrimSqueaker

7
@GrimSqueaker : 값이 중복되었는지 여부를 고려하고 싶다면 df.T.drop_duplicates().T.
John Zwinck

3
지금까지 가장 빠른 솔루션으로
AtotheSiv

2
VaidøtasIvøška @이을위한 2 번째 답변을 참조하시기 바랍니다 질문
유전자 Burinsky

2
@JohnZwinck : 보유 할 수있는 열 수에 제한이 있으므로 작은 데이터 프레임에서만 작동합니다. 예를 들어 100,000 개의 행이있는 데이터 프레임에서 실패했습니다. 이는 전치 후 100,000 개의 열을 생성하므로 불가능합니다
Eelco van Vliet

40

고유 한 열 이름을 이미 알고있는 것 같습니다. 그렇다면 df = df['Time', 'Time Relative', 'N2']작동합니다.

그렇지 않은 경우 솔루션이 작동합니다.

In [101]: vals = np.random.randint(0,20, (4,3))
          vals
Out[101]:
array([[ 3, 13,  0],
       [ 1, 15, 14],
       [14, 19, 14],
       [19,  5,  1]])

In [106]: df = pd.DataFrame(np.hstack([vals, vals]), columns=['Time', 'H1', 'N2', 'Time Relative', 'N2', 'Time'] )
          df
Out[106]:
   Time  H1  N2  Time Relative  N2  Time
0     3  13   0              3  13     0
1     1  15  14              1  15    14
2    14  19  14             14  19    14
3    19   5   1             19   5     1

In [107]: df.T.drop_duplicates().T
Out[107]:
   Time  H1  N2
0     3  13   0
1     1  15  14
2    14  19  14
3    19   5   1

데이터를 엉망으로 만드는 특정 데이터가있을 수 있습니다. 데이터에 대해 더 자세한 정보를 제공해 주시면 더 많은 도움을 드릴 수 있습니다.

편집 : Andy가 말했듯이 문제는 중복 된 열 제목에있을 수 있습니다.

샘플 테이블 파일 'dummy.csv'의 경우 다음과 같이 구성했습니다.

Time    H1  N2  Time    N2  Time Relative
3   13  13  3   13  0
1   15  15  1   15  14
14  19  19  14  19  14
19  5   5   19  5   1

사용 read_table하면 고유 한 열이 제공되고 제대로 작동합니다.

In [151]: df2 = pd.read_table('dummy.csv')
          df2
Out[151]:
         Time  H1  N2  Time.1  N2.1  Time Relative
      0     3  13  13       3    13              0
      1     1  15  15       1    15             14
      2    14  19  19      14    19             14
      3    19   5   5      19     5              1
In [152]: df2.T.drop_duplicates().T
Out[152]:
             Time  H1  Time Relative
          0     3  13              0
          1     1  15             14
          2    14  19             14
          3    19   5              1  

귀하의 버전이 허용하지 않는 경우 솔루션을 함께 해킹하여 고유하게 만들 수 있습니다.

In [169]: df2 = pd.read_table('dummy.csv', header=None)
          df2
Out[169]:
              0   1   2     3   4              5
        0  Time  H1  N2  Time  N2  Time Relative
        1     3  13  13     3  13              0
        2     1  15  15     1  15             14
        3    14  19  19    14  19             14
        4    19   5   5    19   5              1
In [171]: from collections import defaultdict
          col_counts = defaultdict(int)
          col_ix = df2.first_valid_index()
In [172]: cols = []
          for col in df2.ix[col_ix]:
              cnt = col_counts[col]
              col_counts[col] += 1
              suf = '_' + str(cnt) if cnt else ''
              cols.append(col + suf)
          cols
Out[172]:
          ['Time', 'H1', 'N2', 'Time_1', 'N2_1', 'Time Relative']
In [174]: df2.columns = cols
          df2 = df2.drop([col_ix])
In [177]: df2
Out[177]:
          Time  H1  N2 Time_1 N2_1 Time Relative
        1    3  13  13      3   13             0
        2    1  15  15      1   15            14
        3   14  19  19     14   19            14
        4   19   5   5     19    5             1
In [178]: df2.T.drop_duplicates().T
Out[178]:
          Time  H1 Time Relative
        1    3  13             0
        2    1  15            14
        3   14  19            14
        4   19   5             1 

5
불행히도 df['Time']모든 시계열을 선택 (즉, DataFrame df['Time', ..]반환)하면 전체 DataFrame이 반환됩니다.
Andy Hayden 2013

예, 꽤 지루합니다. 버전 차이 일뿐입니다.
beardc

2
이중 전치를 사용하면 유형이 혼합 된 df가있는 경우 숫자 유형을 객체로 변환하는 것과 같은 의도하지 않은 부작용이 발생할 수 있습니다. 참조 : stackoverflow.com/questions/24682396/…
Petergavinkin

이 솔루션은 대용량 데이터 프레임에 문제를 제공합니다. RecursionError: maximum recursion depth exceeded
Scott

큰 데이터 프레임의 조옮김 프로세스가 느려집니다
Kush Patel

13

큰 DataFrame의 경우 전치가 비효율적입니다. 다음은 대안입니다.

def duplicate_columns(frame):
    groups = frame.columns.to_series().groupby(frame.dtypes).groups
    dups = []
    for t, v in groups.items():
        dcols = frame[v].to_dict(orient="list")

        vs = dcols.values()
        ks = dcols.keys()
        lvs = len(vs)

        for i in range(lvs):
            for j in range(i+1,lvs):
                if vs[i] == vs[j]: 
                    dups.append(ks[i])
                    break

    return dups       

다음과 같이 사용하십시오.

dups = duplicate_columns(frame)
frame = frame.drop(dups, axis=1)

편집하다

nan을 다른 값처럼 처리하는 메모리 효율적인 버전 :

from pandas.core.common import array_equivalent

def duplicate_columns(frame):
    groups = frame.columns.to_series().groupby(frame.dtypes).groups
    dups = []

    for t, v in groups.items():

        cs = frame[v].columns
        vs = frame[v]
        lcs = len(cs)

        for i in range(lcs):
            ia = vs.iloc[:,i].values
            for j in range(i+1, lcs):
                ja = vs.iloc[:,j].values
                if array_equivalent(ia, ja):
                    dups.append(cs[i])
                    break

    return dups

3
매력처럼 작동하고 매우 효율적입니다! 사용하면 my_df.T.drop_duplicates().T큰 데이터 프레임이 중단됩니다.

1
멋진 솔루션이지만 2017 년 4 월 26 일에 나는/usr/local/lib/python3.5/dist-packages/ipykernel_launcher.py:17: DeprecationWarning: 'pandas.core.common.array_equivalent' is deprecated and is no longer public API
George Fisher

교체 if array_equivalent(ia, ja):로하는 것은 if np.array_equal(ia, ja):동일한 결과를 가져 오는 것 같습니다하지만 난 그것을 잘 NaN을 처리하지 않습니다 읽어 보시기 바랍니다.
George Fisher

@GeorgeFisher에 대한 기본 코드 array_equivalent가 이전 브랜치의 공용 저장소에서 계속 사용 가능합니까?
kalu

@kalu 이제 현재가 있습니다 numpy.array_equiv. 팬더, 나는을 위해 GitHub의에 이전의 모든 릴리스 지점이 표시되지 않는 pandas.core.common그러나 아마 보는 다른 장소가있다
조지 피셔

11

내가 착각하지 않았다면, 다음은 전치 솔루션의 메모리 문제없이 @kalu의 함수보다 적은 줄로 요청 된 것을 수행하여 비슷한 이름의 열 중 첫 번째 열을 유지합니다.

Cols = list(df.columns)
for i,item in enumerate(df.columns):
    if item in df.columns[:i]: Cols[i] = "toDROP"
df.columns = Cols
df = df.drop("toDROP",1)

내 경우에는 솔루션이 작동하지 않습니다. 마지막 줄을 실행 한 후 "ValueError : labels [ 'toDROP'] not included in axis"라는 메시지가 표시됩니다.
NuValue

4

올바른 길을 가고있는 것 같습니다. 당신이 찾고 있던 원 라이너는 다음과 같습니다.

df.reset_index().T.drop_duplicates().T

그러나 참조 된 오류 메시지를 생성하는 예제 데이터 프레임이 없기 때문에 Reindexing only valid with uniquely valued index objects정확히 무엇이 문제를 해결할 것인지 말하기는 어렵습니다. 원래 색인 복원이 중요한 경우 다음을 수행하십시오.

original_index = df.index.names
df.reset_index().T.drop_duplicates().reset_index(original_index).T

0

첫 번째 단계 :-첫 번째 행 즉 모든 열을 읽고 모든 중복 열을 제거합니다.

두 번째 단계 :-마지막으로 해당 열만 읽으십시오.

cols = pd.read_csv("file.csv", header=None, nrows=1).iloc[0].drop_duplicates()
df = pd.read_csv("file.csv", usecols=cols)

0

첫 번째 답변에서 제공 한 하나의 라이너가 잘 작동하는이 문제가 발생했습니다. 그러나 열의 두 번째 복사본에 모든 데이터가있는 추가 복잡함이있었습니다. 첫 번째 사본은 그렇지 않았습니다.

해결책은 부정 연산자를 토글하여 하나의 데이터 프레임을 분할하여 두 개의 데이터 프레임을 만드는 것이 었습니다. 두 개의 데이터 프레임이 있으면 lsuffix. 이렇게하면 데이터없이 열을 참조하고 삭제할 수 있습니다.

-E


0

아래 방법은 중복 열을 식별하여 원래 데이터 프레임을 구축하는 데 무엇이 잘못되었는지 검토합니다.

dupes = pd.DataFrame(df.columns)
dupes[dupes.duplicated()]

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.