J'ai ce DataFrame (df1
) Dans Pandas:
df1 = pd.DataFrame(np.random.Rand(10,4),columns=list('ABCD'))
print df1
A B C D
0.860379 0.726956 0.394529 0.833217
0.014180 0.813828 0.559891 0.339647
0.782838 0.698993 0.551252 0.361034
0.833370 0.982056 0.741821 0.006864
0.855955 0.546562 0.270425 0.136006
0.491538 0.445024 0.971603 0.690001
0.911696 0.065338 0.796946 0.853456
0.744923 0.545661 0.492739 0.337628
0.576235 0.219831 0.946772 0.752403
0.164873 0.454862 0.745890 0.437729
Je voudrais vérifier si une ligne (toutes les colonnes) d'une autre trame de données (df2
) Est présente dans df1
. Voici df2
:
df2 = df1.ix[4:8]
df2.reset_index(drop=True,inplace=True)
df2.loc[-1] = [2, 3, 4, 5]
df2.loc[-2] = [14, 15, 16, 17]
df2.reset_index(drop=True,inplace=True)
print df2
A B C D
0.855955 0.546562 0.270425 0.136006
0.491538 0.445024 0.971603 0.690001
0.911696 0.065338 0.796946 0.853456
0.744923 0.545661 0.492739 0.337628
0.576235 0.219831 0.946772 0.752403
2.000000 3.000000 4.000000 5.000000
14.000000 15.000000 16.000000 17.000000
J'ai essayé d'utiliser df.lookup
Pour rechercher une ligne à la fois. Je l'ai fait de cette façon:
list1 = df2.ix[0].tolist()
cols = df1.columns.tolist()
print df1.lookup(list1, cols)
mais j'ai reçu ce message d'erreur:
File "C:\Users\test.py", line 19, in <module>
print df1.lookup(list1, cols)
File "C:\python27\lib\site-packages\pandas\core\frame.py", line 2217, in lookup
raise KeyError('One or more row labels was not found')
KeyError: 'One or more row labels was not found'
J'ai également essayé .all()
en utilisant:
print (df2 == df1).all(1).any()
mais j'ai reçu ce message d'erreur:
File "C:\Users\test.py", line 12, in <module>
print (df2 == df1).all(1).any()
File "C:\python27\lib\site-packages\pandas\core\ops.py", line 884, in f
return self._compare_frame(other, func, str_rep)
File "C:\python27\lib\site-packages\pandas\core\frame.py", line 3010, in _compare_frame
raise ValueError('Can only compare identically-labeled '
ValueError: Can only compare identically-labeled DataFrame objects
J'ai également essayé isin()
comme ceci:
print df2.isin(df1)
mais j'ai eu False
partout, ce qui n'est pas correct:
A B C D
False False False False
False False False False
False False False False
False False False False
False False False False
False False False False
False False False False
False False False False
False False False False
False False False False
Est-il possible de rechercher un ensemble de lignes dans un DataFrame, en le comparant aux lignes d'un autre dataframe?
EDIT: Est-il possible de supprimer df2
Lignes si ces lignes sont également présentes dans df1
?
Une solution possible à votre problème serait d'utiliser merge . Vérifier si une ligne (toutes les colonnes) d'une autre trame de données (df2) est présente dans df1 équivaut à déterminer l'intersection des deux trames de données. Cela peut être accompli en utilisant la fonction suivante:
pd.merge(df1, df2, on=['A', 'B', 'C', 'D'], how='inner')
Par exemple, si df1 était
A B C D
0 0.403846 0.312230 0.209882 0.397923
1 0.934957 0.731730 0.484712 0.734747
2 0.588245 0.961589 0.910292 0.382072
3 0.534226 0.276908 0.323282 0.629398
4 0.259533 0.277465 0.043652 0.925743
5 0.667415 0.051182 0.928655 0.737673
6 0.217923 0.665446 0.224268 0.772592
7 0.023578 0.561884 0.615515 0.362084
8 0.346373 0.375366 0.083003 0.663622
9 0.352584 0.103263 0.661686 0.246862
et df2 a été défini comme:
A B C D
0 0.259533 0.277465 0.043652 0.925743
1 0.667415 0.051182 0.928655 0.737673
2 0.217923 0.665446 0.224268 0.772592
3 0.023578 0.561884 0.615515 0.362084
4 0.346373 0.375366 0.083003 0.663622
5 2.000000 3.000000 4.000000 5.000000
6 14.000000 15.000000 16.000000 17.000000
La fonction pd.merge(df1, df2, on=['A', 'B', 'C', 'D'], how='inner')
produit:
A B C D
0 0.259533 0.277465 0.043652 0.925743
1 0.667415 0.051182 0.928655 0.737673
2 0.217923 0.665446 0.224268 0.772592
3 0.023578 0.561884 0.615515 0.362084
4 0.346373 0.375366 0.083003 0.663622
Les résultats sont toutes les lignes (toutes les colonnes) qui sont à la fois dans df1 et df2.
Nous pouvons également modifier cet exemple si les colonnes ne sont pas les mêmes dans df1 et df2 et comparer simplement les valeurs de ligne qui sont les mêmes pour un sous-ensemble des colonnes. Si nous modifions l'exemple d'origine:
df1 = pd.DataFrame(np.random.Rand(10,4),columns=list('ABCD'))
df2 = df1.ix[4:8]
df2.reset_index(drop=True,inplace=True)
df2.loc[-1] = [2, 3, 4, 5]
df2.loc[-2] = [14, 15, 16, 17]
df2.reset_index(drop=True,inplace=True)
df2 = df2[['A', 'B', 'C']] # df2 has only columns A B C
Ensuite, nous pouvons regarder les colonnes communes en utilisant common_cols = list(set(df1.columns) & set(df2.columns))
entre les deux dataframes puis fusionner:
pd.merge(df1, df2, on=common_cols, how='inner')
EDIT: Nouvelle question (commentaires), après avoir identifié les lignes de df2 qui étaient également présentes dans la première trame de données (df1), est-il possible de prendre la résultat de pd.merge (), puis de supprimer les lignes de df2 qui sont également présentes dans df1
Je ne connais pas de moyen simple d'accomplir la tâche de suppression des lignes de df2 qui sont également présentes dans df1. Cela dit, vous pouvez utiliser les éléments suivants:
ds1 = set(Tuple(line) for line in df1.values)
ds2 = set(Tuple(line) for line in df2.values)
df = pd.DataFrame(list(ds2.difference(ds1)), columns=df2.columns)
Il existe probablement un meilleur moyen d'accomplir cette tâche, mais je ne connais pas une telle méthode/fonction.
EDIT 2: Comment supprimer les lignes de df2 qui sont également présentes dans df1 comme indiqué dans la réponse @WR.
La méthode fournie df2[~df2['A'].isin(df12['A'])]
ne prend pas en compte tous les types de situations. Tenez compte des DataFrames suivants:
df1:
A B C D
0 6 4 1 6
1 7 6 6 8
2 1 6 2 7
3 8 0 4 1
4 1 0 2 3
5 8 4 7 5
6 4 7 1 1
7 3 7 3 4
8 5 2 8 8
9 3 2 8 4
df2:
A B C D
0 1 0 2 3
1 8 4 7 5
2 4 7 1 1
3 3 7 3 4
4 5 2 8 8
5 1 1 1 1
6 2 2 2 2
df12:
A B C D
0 1 0 2 3
1 8 4 7 5
2 4 7 1 1
3 3 7 3 4
4 5 2 8 8
L'utilisation des DataFrames ci-dessus dans le but de supprimer des lignes de df2 également présentes dans df1 entraînerait les conséquences suivantes:
A B C D
0 1 1 1 1
1 2 2 2 2
Les lignes (1, 1, 1, 1) et (2, 2, 2, 2) sont en df2 et non en df1. Malheureusement, l'utilisation de la méthode fournie (df2[~df2['A'].isin(df12['A'])]
) entraîne:
A B C D
6 2 2 2 2
Cela se produit car la valeur de 1 dans la colonne A se trouve à la fois dans l'intersection DataFrame (c'est-à-dire (1, 0, 2, 3)) et df2 et supprime ainsi à la fois (1, 0, 2, 3) et (1, 1, 1, 1). Cela n'est pas voulu car la ligne (1, 1, 1, 1) n'est pas dans df1 et ne doit pas être supprimée.
Je pense que ce qui suit fournira une solution. Il crée une colonne factice qui est ensuite utilisée pour sous-définir le DataFrame aux résultats souhaités:
df12['key'] = 'x'
temp_df = pd.merge(df2, df12, on=df2.columns.tolist(), how='left')
temp_df[temp_df['key'].isnull()].drop('key', axis=1)
@Andrew: Je pense avoir trouvé un moyen de supprimer les lignes d'une trame de données qui sont déjà présentes dans une autre (c'est-à-dire pour répondre à mon EDIT) sans utiliser de boucles - faites-moi savoir si vous n'êtes pas d'accord et/ou si mon OP + EDIT ne l'a pas clairement fait énoncer ceci:
CECI FONCTIONNE
Les colonnes des deux trames de données sont toujours les mêmes - A
, B
, C
et D
. Dans cet esprit, basé fortement sur l'approche d'Andrew, voici comment supprimer les lignes de df2
Qui sont également présentes dans df1
:
common_cols = df1.columns.tolist() #generate list of column names
df12 = pd.merge(df1, df2, on=common_cols, how='inner') #extract common rows with merge
df2 = df2[~df2['A'].isin(df12['A'])]
La ligne 3 fait ce qui suit:
df2
Qui ne correspondent pas aux lignes de df1
:A
pour faire cette comparaison - c'estREMARQUE: cette méthode est essentiellement l'équivalent de SQL NOT IN()
.