pandas python xóa các cột trùng lặp


125

Cách dễ nhất để xóa các cột trùng lặp khỏi khung dữ liệu là gì?

Tôi đang đọc một tệp văn bản có các cột trùng lặp qua:

import pandas as pd

df=pd.read_table(fname)

Tên cột là:

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

Tất cả các cột Thời gian và Thời gian Tương đối đều chứa cùng một dữ liệu. Tôi muốn:

Time, Time Relative, N2, H2

Tất cả những nỗ lực của tôi trong việc xóa, xóa, v.v. chẳng hạn như:

df=df.T.drop_duplicates().T

Dẫn đến lỗi chỉ mục có giá trị duy nhất:

Reindexing only valid with uniquely valued index objects

Xin lỗi vì đã là một con gấu trúc. Mọi lơi đê nghị đêu nên được đanh gia cao.


Chi tiết bổ sung

Phiên bản Pandas: 0.9.0
Phiên bản Python: 2.7.3
Windows 7
(cài đặt qua Pythonxy 2.7.3.0)

tệp dữ liệu (lưu ý: trong tệp thực, các cột được phân tách bằng tab, ở đây chúng được phân tách bằng 4 dấu cách):

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

Bạn có phiên bản gấu trúc nào? ( import pandas as pd; pd.__version__ )
râuc

1
@BirdJaguarIV, Tôi đang sử dụng phiên bản 0.9.0 gấu trúc
Onlyjus

Bạn có thể muốn thử nâng cấp lên 0,10. Phiên bản của tôi làm cho các cột trở nên độc đáo với read_tableví dụ mà tôi đã tạo.
râuc

Lưu ý rằng df = df.T.drop_duplicates (). T không xem xét tên cột. Nếu bạn có hai cột có cùng dữ liệu nhưng tên khác nhau, một cột sẽ bị xóa nhầm.
Joylove

Câu trả lời:


391

Có một giải pháp đơn giản cho vấn đề. Điều này áp dụng nếu một số tên cột bị trùng lặp và bạn muốn xóa chúng:

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

Làm thế nào nó hoạt động:

Giả sử các cột của khung dữ liệu là ['alpha','beta','alpha']

df.columns.duplicated()trả về một mảng boolean: a Truehoặc Falsecho mỗi cột. Nếu đúng Falsethì tên cột là duy nhất cho đến thời điểm đó, nếu đúng Truethì tên cột được nhân đôi trước đó. Ví dụ, sử dụng ví dụ đã cho, giá trị trả về sẽ là [False,False,True].

Pandascho phép một chỉ mục bằng cách sử dụng các giá trị boolean, theo đó nó chỉ chọn các Truegiá trị. Vì chúng ta muốn giữ các cột không trùng lặp, chúng ta cần lật mảng boolean ở trên (tức là [True, True, False] = ~[False,False,True])

Cuối cùng, df.loc[:,[True,True,False]]chỉ chọn các cột không trùng lặp bằng khả năng lập chỉ mục đã nói ở trên.

Lưu ý : ở trên chỉ kiểm tra tên cột, không kiểm tra giá trị cột.


16
Một câu trả lời lý tưởng cũng sẽ phù hợp với các giá trị trùng lặp, không chỉ tên.
GrimSqueaker

7
@GrimSqueaker: Nếu bạn muốn xem xét liệu các giá trị có bị trùng lặp hay không, bạn muốn một cái gì đó như thế df.T.drop_duplicates().T.
John Zwinck

3
Cho đến nay, giải pháp nhanh nhất
AtotheSiv

2
@ VaidøtasIvøška xin vui lòng xem câu trả lời thứ 2 cho điều này câu hỏi
Gene Burinsky

2
@JohnZwinck: điều này chỉ hoạt động với các khung dữ liệu nhỏ, vì có giới hạn về số lượng cột bạn có thể có. Đối với tôi, nó không thành công đối với khung dữ liệu có 100.000 hàng, vì điều này tạo ra 100.000 cột sau khi chuyển đổi, điều này là không thể
Eelco van Vliet

40

Có vẻ như bạn đã biết các tên cột duy nhất. Nếu đó là trường hợp, sau đó df = df['Time', 'Time Relative', 'N2']sẽ làm việc.

Nếu không, giải pháp của bạn sẽ hoạt động:

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

Bạn có thể có một cái gì đó cụ thể cho dữ liệu của bạn đang làm rối tung nó. Chúng tôi có thể trợ giúp thêm nếu bạn có thể cung cấp thêm chi tiết về dữ liệu cho chúng tôi.

Chỉnh sửa: Giống như Andy đã nói, vấn đề có lẽ là với các tiêu đề cột trùng lặp.

Đối với tệp bảng mẫu 'dummy.csv', tôi đã tạo:

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

sử dụng read_tablecung cấp các cột duy nhất và hoạt động bình thường:

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  

Nếu phiên bản của bạn không cho phép của bạn, bạn có thể kết hợp một giải pháp để biến chúng thành duy nhất:

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
Thật không may khi df['Time']chọn tất cả chuỗi Thời gian (tức là trả về một DataFrame) và df['Time', ..]điều này sẽ trả về toàn bộ DataFrame.
Andy Hayden

Vâng, nó khá tẻ nhạt ... hy vọng đó chỉ là một sự khác biệt về phiên bản.
râuc

2
Sử dụng phép chuyển vị kép có thể có những tác dụng phụ không mong muốn như chuyển đổi kiểu số thành đối tượng trong trường hợp bạn có df với kiểu hỗn hợp. Xem: stackoverflow.com/questions/24682396/…
Petergavinkin

Giải pháp này cho tôi vấn đề trên dataframes lớn: RecursionError: maximum recursion depth exceeded
Scott

Transpose của khung dữ liệu lớn sẽ làm chậm quá trình
Kush Patel

13

Việc chuyển đổi không hiệu quả đối với các DataFrame lớn. Đây là một giải pháp thay thế:

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       

Sử dụng nó như thế này:

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

Biên tập

Một phiên bản hiệu quả về bộ nhớ xử lý nans giống như bất kỳ giá trị nào khác:

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
Hoạt động như một sự quyến rũ, rất hiệu quả! Việc sử dụng my_df.T.drop_duplicates().Tsẽ bị treo trên các khung dữ liệu lớn.
Will

1
Giải pháp tuyệt vời nhưng vào ngày 26 tháng 4 năm 2017 tôi đã nhận được/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

thay thế if array_equivalent(ia, ja):bằng if np.array_equal(ia, ja):dường như tạo ra kết quả tương tự nhưng tôi đọc rằng nó không xử lý tốt các NaN.
George Fisher

@GeorgeFisher Có phải mã cơ bản cho array_equivalentvẫn có sẵn trong repo công khai, có thể trên một chi nhánh cũ hơn không?
kalu

@kalu hiện có một dòng điện numpy.array_equiv; đối với gấu trúc, tôi không thấy bất kỳ chi nhánh phát hành sớm hơn nào trên GitHub pandas.core.commonnhưng có lẽ có những nơi khác để xem
George Fisher

11

Nếu tôi không nhầm, phần sau thực hiện những gì được hỏi mà không gặp vấn đề về bộ nhớ của giải pháp chuyển vị và với ít dòng hơn hàm của @kalu, giữ lại cột đầu tiên của bất kỳ cột nào có tên tương tự.

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)

Giải pháp của bạn không hoạt động trong trường hợp của tôi, nó hiển thị cho tôi: "ValueError: nhãn ['toDROP'] không được chứa trong trục" sau khi thực hiện dòng cuối cùng
NuValue 13/04/18

4

Có vẻ như bạn đã đi đúng đường. Đây là một lớp lót mà bạn đang tìm kiếm:

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

Nhưng vì không có khung dữ liệu mẫu nào tạo ra thông báo lỗi được tham chiếu Reindexing only valid with uniquely valued index objects, nên rất khó để nói chính xác điều gì sẽ giải quyết vấn đề. nếu việc khôi phục chỉ mục gốc là quan trọng đối với bạn, hãy làm như sau:

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

0

Bước đầu tiên: - Đọc hàng đầu tiên tức là tất cả các cột loại bỏ tất cả các cột trùng lặp.

Bước thứ hai: - Cuối cùng chỉ đọc các cột đó.

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

0

Tôi gặp phải vấn đề này trong đó một lớp lót được cung cấp bởi câu trả lời đầu tiên hoạt động tốt. Tuy nhiên, tôi có thêm một vấn đề phức tạp khi bản sao thứ hai của cột có tất cả dữ liệu. Bản sao đầu tiên thì không.

Giải pháp là tạo hai khung dữ liệu bằng cách tách một khung dữ liệu bằng cách chuyển đổi toán tử phủ định. Khi tôi đã có hai khung dữ liệu, tôi chạy một câu lệnh kết hợp bằng cách sử dụnglsuffix . Bằng cách này, tôi có thể tham chiếu và xóa cột mà không có dữ liệu.

- E


0

Cách dưới đây sẽ xác định các cột dupe để xem lại điều gì đang xảy ra khi xây dựng khung dữ liệu ban đầu.

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.