pandas Python supprimer les colonnes en double

Quel est le moyen le plus simple de supprimer les colonnes en double d'un dataframe?

Je lis un fichier texte qui a des colonnes en double via:

import pandas as pd

df=pd.read_table(fname)

Les noms des colonnes sont:

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

Toutes les colonnes Time et Time Relative contiennent les mêmes données. Je veux:

Time, Time Relative, N2, H2

Toutes mes tentatives de suppression, de suppression, etc. telles que:

df=df.T.drop_duplicates().T

Résultat des erreurs d'index à valeur unique:

Reindexing only valid with uniquely valued index objects

Désolé d'être un Pandas noob. Toutes les Suggestions seraient apprécier.


Détails Supplémentaires

Version Pandas: 0.9.0
Version Python: 2.7.3
Windows 7
(installé via pythonxy 2.7.3.0)

Fichier de données (note: dans le fichier réel, les colonnes sont séparées par des onglets, ici elles sont séparées par 4 espaces):

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
50
demandé sur Onlyjus 2013-02-20 19:49:17

4 réponses

On dirait que vous connaissez déjà les noms de colonnes uniques. Si c'est le cas, alors df = df['Time', 'Time Relative', 'N2'] fonctionnerait.

Sinon, votre solution devrait fonctionner:

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

Vous avez probablement quelque chose de spécifique à vos données qui le gâche. Nous pourrions donner plus d'aide s'il y a plus de détails que vous pourriez nous donner sur les données.

Modifier: Comme Andy l'a dit, le problème est probablement avec les titres de colonne en double.

Pour un exemple de fichier de table 'dummy.csv " j'ai fait des en haut:

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

Utiliser read_table donne des colonnes uniques et fonctionne correctement:

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  

Si votre version ne le laisse pas, vous pouvez pirater une solution pour les rendre uniques:

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 
32
répondu beardc 2013-02-20 17:49:53

Tout ce qui précède semble inutilement lourd et fastidieux méthodes-il y a une solution d'une ligne au problème. Cela s'applique si certains noms de colonnes sont dupliqués et que vous souhaitez les supprimer:

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

[update] comment ça marche:

Supposons que les colonnes de la trame de données sont ['alpha','beta','alpha']

df.columns.duplicated() retourne un booléen tableau: un True ou False pour chaque colonne. Si c'est False alors le nom de la colonne est unique jusqu'à ce point, s'il est True alors le nom de la colonne est dupliqué plus tôt. Par exemple, en utilisant l'exemple donné, la valeur retournée serait [False,False,True].

Pandas permet d'indexer en utilisant des valeurs booléennes par lesquelles il ne sélectionne que les valeurs True. Puisque nous voulons garder les colonnes non dupliquées, nous avons besoin du tableau booléen ci-dessus pour être retourné (ie [True, True, False] = ~[False,False,True])

Enfin, df.loc[:,[True,True,False]] sélectionne uniquement les colonnes non dupliquées en utilisant la capacité d'indexation susmentionnée.

Note : ce qui précède ne vérifie que les noms de colonnes, pas colonne valeur.

144
répondu Gene Burinsky 2017-08-24 17:34:44

Si Je ne me trompe pas, ce qui suit fait ce qui a été demandé sans les problèmes de mémoire de la solution de transposition et avec moins de lignes que la fonction de @kalu, en gardant la première de toutes les colonnes nommées de la même manière.

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)
10
répondu Elliott Collins 2016-04-09 05:53:28

La transposition est inefficace pour les grandes trames de données. Voici une alternative:

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       

Utilisez-le comme ceci:

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

Modifier

Une version efficace en mémoire qui traite les Nan comme toute autre valeur:

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
9
répondu kalu 2015-10-06 18:15:09