python pandaları yinelenen sütunları kaldırır


126

Bir veri çerçevesinden yinelenen sütunları kaldırmanın en kolay yolu nedir?

Yinelenen sütunları olan bir metin dosyasını şu şekilde okuyorum:

import pandas as pd

df=pd.read_table(fname)

Sütun adları:

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

Tüm Zaman ve Zaman Göreceli sütunları aynı verileri içerir. İstiyorum:

Time, Time Relative, N2, H2

Tüm düşürme, silme, vb. Girişimlerim:

df=df.T.drop_duplicates().T

Benzersiz değerde dizin hatalarının sonucu:

Reindexing only valid with uniquely valued index objects

Pandalar noob olduğum için üzgünüm. Herhangi bir Öneriniz takdir edilecektir.


ek detaylar

Pandas sürümü: 0.9.0
Python Sürümü: 2.7.3
Windows 7
(Pythonxy 2.7.3.0 ile yüklenir)

veri dosyası (not: gerçek dosyada sütunlar sekmelerle ayrılır, burada 4 boşlukla ayrılırlar):

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

Pandaların hangi versiyonuna sahipsiniz? ( import pandas as pd; pd.__version__ )
beardc

1
@BirdJaguarIV, Pandalar 0.9.0 sürümünü kullanıyorum
Onlyjus

0.10'a yükseltmeyi deneyebilirsiniz. Benim versiyonum, oluşturduğum read_tableörnek için sütunları benzersiz kılıyor .
sakalc

Df = df.T.drop_duplicates (). T'nin sütun adını dikkate almadığına dikkat edin. Aynı verilere, ancak farklı adlara sahip iki sütununuz varsa, biri yanlışlıkla atılır.
Joylove

Yanıtlar:


392

Sorunun tek satırlık bir çözümü var. Bu, bazı sütun adlarının yinelenmesi ve bunları kaldırmak istemeniz durumunda geçerlidir:

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

Nasıl çalışır:

Veri çerçevesinin sütunlarının ['alpha','beta','alpha']

df.columns.duplicated()bir boole dizisi döndürür: a Trueveya Falseher sütun için. Öyleyse False, sütun adı o noktaya kadar benzersizdir, Trueöyleyse sütun adı daha önce çoğaltılır. Örneğin, verilen örnek kullanıldığında, döndürülen değer olacaktır [False,False,True].

PandasBoole değerlerini kullanarak indekslemeye izin verir, böylece sadece Truedeğerleri seçer . Yinelenmemiş sütunları korumak istediğimizden, yukarıdaki boole dizisinin ters çevrilmesine ihtiyacımız var (yani [True, True, False] = ~[False,False,True])

Son olarak, df.loc[:,[True,True,False]]yukarıda belirtilen indeksleme yeteneğini kullanarak yalnızca yinelenmemiş sütunları seçer.

Not : Yukarıdakiler, sütun değerlerini değil , yalnızca sütun adlarını kontrol eder .


16
İdeal bir cevap, sadece isimler için değil, yinelenen değerler için de işe yarar.
GrimSqueaker

7
@GrimSqueaker: Değerlerin yinelenip yinelenmediğini düşünmek istiyorsanız, buna benzer bir şey istersiniz df.T.drop_duplicates().T.
John Zwinck


2
@ VaidøtasIvøška lütfen bu sorunun
Gene Burinsky

2
@JohnZwinck: Sahip olabileceğiniz sütun sayısında bir sınır olduğundan, bu yalnızca küçük veri çerçeveleri için işe yarar. Benim için 100.000 satırlık bir veri çerçevesi için başarısız oldu, çünkü bu, aktarıldıktan sonra 100.000 sütun veriyor, bu mümkün değil
Eelco van Vliet

40

Benzersiz sütun adlarını zaten biliyormuşsunuz gibi görünüyor. Eğer durum buysa, o df = df['Time', 'Time Relative', 'N2']zaman işe yarar.

Değilse, çözümünüz işe yaramalıdır:

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

Muhtemelen verilerinize özel bir şeye sahipsinizdir. Veriler hakkında bize verebileceğiniz daha fazla ayrıntı varsa daha fazla yardımcı olabiliriz.

Düzenleme: Andy'nin dediği gibi, sorun muhtemelen yinelenen sütun başlıklarından kaynaklanmaktadır.

Örnek bir tablo dosyası için 'dummy.csv' oluşturdum:

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

kullanımı read_tablebenzersiz sütunlar verir ve düzgün çalışır:

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  

Sürümünüz sürümünüze izin vermiyorsa, onları benzersiz kılmak için bir çözümü birlikte kırabilirsiniz:

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
Ne yazık ki df['Time']tüm Zaman serilerini seçer (yani bir DataFrame döndürür) ve df['Time', ..]bu, tüm DataFrame'i döndürür.
Andy Hayden

Evet, oldukça sıkıcı ... umarım sadece bir versiyon farkıdır.
sakalc

2
Çift transpoze kullanmak, karışık tiplere sahip bir df'niz olması durumunda sayısal türleri nesnelere dönüştürmek gibi istenmeyen yan etkilere sahip olabilir. Bakınız: stackoverflow.com/questions/24682396/…
Petergavinkin

Bu çözüm bana büyük veri çerçevelerinde sorun yaşatıyor:RecursionError: maximum recursion depth exceeded
Scott

Büyük veri çerçevesinin aktarılması yavaş bir süreç olacak
Kush Patel

13

Aktarma, büyük DataFrame'ler için verimsizdir. İşte bir alternatif:

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       

Bunu şu şekilde kullanın:

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

Düzenle

Nans'ı diğer herhangi bir değer gibi ele alan, bellek açısından verimli bir sürüm:

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
Bir cazibe gibi çalışıyor, çok verimli! Kullanmak my_df.T.drop_duplicates().T, büyük veri çerçevelerinde asılı kalacaktır.
Will

1
Güzel çözüm ama 26 Nisan 2017'de aldım /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

değiştirilmesi if array_equivalent(ia, ja):ile if np.array_equal(ia, ja):aynı sonuçları üretmek gibi görünüyor ama çok iyi NaN'ler idare etmediğini okuyun.
George Fisher

@GeorgeFisher Temel kod array_equivalenthala halka açık depoda , muhtemelen daha eski bir şubede mevcut mu?
kalu

@kalu artık bir akım var numpy.array_equiv; Pandalar için GitHub'da daha önceki sürüm dalları görmüyorum, pandas.core.commonancak belki bakılacak başka yerler de var
George Fisher

12

Yanılmıyorsam, aşağıdakiler, devrik çözümünün bellek sorunları olmadan ve @kalu işlevinden daha az satırla, benzer şekilde adlandırılmış sütunlardan ilkini koruyarak istenen şeyi yapar.

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)

Çözümünüz benim durumumda çalışmıyor, bana şunu gösteriyor: "ValueError: etiketler ['toDROP'] son ​​satırı çalıştırdıktan sonra
NuValue

4

Görünüşe göre doğru yoldasınız. İşte aradığınız tek satırlık:

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

Ancak başvurulan hata mesajını üreten örnek bir veri çerçevesi olmadığından Reindexing only valid with uniquely valued index objects, sorunu tam olarak neyin çözeceğini söylemek zordur. orijinal dizini geri yüklemek sizin için önemliyse, şunu yapın:

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

0

İlk adım: - İlk satırı okuyun, yani tüm sütunlar, tüm yinelenen sütunları kaldırın.

İkinci adım: - Son olarak yalnızca bu sütunları okuyun.

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

0

İlk cevabın sağladığı tek satırın iyi çalıştığı bu problemle karşılaştım. Bununla birlikte, sütunun ikinci kopyasının tüm verileri içerdiği ekstra karmaşıklık yaşadım. İlk kopya olmadı.

Çözüm, olumsuzlama operatörünü değiştirerek bir veri çerçevesini bölerek iki veri çerçevesi oluşturmaktı. İki veri çerçevesine sahip olduğumda lsuffix,. Bu şekilde, sütunu veriler olmadan referans alabilir ve silebilirim.

- E


0

Aşağıdaki yöntem, veri çerçevesini orijinal olarak oluştururken neyin yanlış gittiğini incelemek için yinelenen sütunları tanımlayacaktır.

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.