Voici mes données:

d = {'ID': [14, 14, 14, 14, 14, 14, 15, 15], 'NAME': ['KWI', 'NED', 'RICK', 'NICH', 'DIONIC', 'RICHARD', 'ROCKY', 'CARLOS', 'SIDARTH'], 'ID_COUNTRY':[1, 2, 3,4,5,6,7,8,9], 'COUNTRY':['MEXICO', 'ITALY', 'CANADA', 'ENGLAND', 'GERMANY', 'UNITED STATES', 'JAPAN', 'SPAIN', 'BRAZIL'], 'ID_CITY':[10, 20, 21, 31, 18, 27, 36, 86, 28], 'CITY':['MX', 'IT', 'CA', 'ENG', 'GE', 'US', 'JP', 'SP', 'BZ'], 'STATUS': ['OK', 'OK', 'OK', 'OK', 'OK', 'NOT', 'OK', 'NOT', 'OK']}
df = pd.DataFrame(data=d)


df:
      ID       NAME      ID_COUNTRY     COUNTRY        ID_CITY     CITY     STATUS
0     14       KWI           1           MEXICO           10         MX        OK
1     14       NED           2           ITALY            20         IT        OK
2     14       RICK          3           CANADA           21         CA        OK
3     14       NICH          4           ENGLAND          31         ENG       OK
4     14       DIONIC        5           GERMANY          18         GE        OK 
5     14       RICHARD       6           UNITED STATES    27         US        NOT
6     14       ROCKY         7           JAPAN            36         JP        OK
7     15       CARLOS        8           SPAIN            86         SP        NOT
8     15       SIDHART       9           BRAZIL           28         BZ        OK

Le df est la donnée de base. Les données dont j'ai besoin pour comparer avec df sont df1:

d1 = {'ID': [14, 10, 14, 11, 14], 'NAME': ['Kwi', 'NED', 'riCK', 'nich', 'DIONIC'], 'ID_COUNTRY':[1, 2, 3, 6, 5], 'COUNTRY':['MXICO', 'itaLY', 'CANADA', 'ENGLAND', 'GERMANY'], 'ID_CITY':[10, 22, 21, 31, 18], 'CITY':['MX', 'AT', 'CA', 'ENG', 'EG'], 'STATUS': ['', 'OK', '', 'OK', '']}
df1 = pd.DataFrame(data=d1)

df1:
      ID       NAME    ID_COUNTRY    COUNTRY      ID_CITY    CITY     STATUS
0     14       Kwi          1         MXICO           10       MX        
1     10       NED          2         itaLY           22       AT        OK
2     14       riCK         3         CANADA          21       CA
3     11       nich         6         ENGLAND         31       ENG       OK
4     14       DIONIC       5         GERMANY         18       EG        

Sortie souhaitée 1 (les valeurs qui ne correspondent pas doivent apparaître en surbrillance):

 The data in df1 that not match with df is:
      ID       NAME    ID_COUNTRY    COUNTRY      ID_CITY    CITY     STATUS
0     14       Kwi          1         *MXICO*         10       MX        **
1    *10*      NED          2          itaLY         *22*      AT        OK
2     14       riCK         3          CANADA         21       CA        **
3    *11*      nich         6          ENGLAND        31       ENG       OK
4     14       DIONIC       5          GERMANY        18       *EG*      **
                          *TWO ROWS ARE MISSING*

Remarque: Dans cette sortie, il est nécessaire que les comparaisons ligne par ligne soient insensibles aux chaînes car itaLY, Kwi, riCK, mais que les valeurs sont correctes car sont les mêmes.

Sortie souhaitée 2:

 The data in df1 that not match with df is in :
 COUNTRY, STATUS with ID 14, NAME Kwi, ID_COUNTRY 1.
 ID, ID_CITY, CITY with ID 10, NAME NED, ID_COUNTRY 2.
 STATUS with ID 14, NAME riCK, ID_COUNTRY 3.
 ID, ID_COUNTRY with ID 11, NAME nich, ID_COUNTRY 6.
 CITY, STATUS with ID 14, NAME DIONIC, ID_COUNTRY 5.
 TWO ROWS ARE MISSING.

Le résultat doit juste être une comparaison des données qui correspondent à la longueur de df1, mais il y a aussi la possibilité que les lignes ne correspondent pas après le ID de df comme je le montre ici ( 14) les valeurs 15 dans ID ne sont pas prises en compte. Je pense que le deuxième résultat est plus spécifique et efficace et que le premier sera lent à visualiser s'il y a beaucoup de données à comparer.

J'espère que tout le monde comprendra quel est le point de cette question et trouvé et réponse. J'ai eu du mal avec ça un certain temps et je n'ai pas obtenu la solution que je voulais, c'est pourquoi je suis venu ici avec vous. Merci d'avoir lu et espérons contribuer à cette plateforme.

0
MetalJacket 28 oct. 2020 à 21:21

2 réponses

Meilleure réponse

Quand on veut une comparaison insensible à la casse entre les chaînes en python, on voudrait mettre les deux chaînes en majuscules ou minuscules et ensuite faire une comparaison traditionnelle == ou !=.

Lorsque vous utilisez des pandas, cela peut être réalisé par la méthode Series .str, qui permet l'utilisation de méthodes de chaîne telles que .upper() et .lower(). Dans votre cas, une solution possible serait:

df, df1 = df.astype(str), df1.astype(str)
_df = df1.copy()

for i in df1.index:
    comparison = df.loc[i].str.upper() != df1.loc[i].str.upper()
    _df.loc[i, comparison] = '*' + df1.loc[i, comparison].astype(str) + '*'
    

Si nous imprimons la trame de données résultante _df, nous obtenons la sortie 1 souhaitée:

     ID    NAME ID_COUNTRY  COUNTRY ID_CITY  CITY STATUS
0    14     Kwi          1  *MXICO*      10    MX     **
1  *10*     NED          2    itaLY    *22*  *AT*     OK
2    14    riCK          3   CANADA      21    CA     **
3  *11*    nich        *6*  ENGLAND      31   ENG     OK
4    14  DIONIC          5  GERMANY      18  *EG*     **

Dans ce cas, je suppose que les lignes correspondantes ont le même index sur les deux dataframes.

Pour votre deuxième sortie souhaitée, vous pouvez simplement parcourir à nouveau chaque ligne:

print("Data in df1 that does't match df:")
for i in _df.index:
    not_matching_cols = _df.loc[i].str.endswith('*')
    if not_matching_cols.any():
        print(','.join(_df.loc[i, not_matching_cols].index), end=' ')
        print('with', 'NAME', df1.loc[i, 'NAME'], 'ID_COUNTRY', df1.loc[i, 'ID_COUNTRY'])

Si vous souhaitez également imprimer le nombre de lignes manquantes sur df1, vous pouvez simplement ajouter

print(df.shape[0] - df1.shape[0], 'ROWS ARE MISSING')

Le résultat de cette dernière partie devrait être:

Data in df1 that does't match df:
COUNTRY,STATUS with NAME Kwi ID_COUNTRY 1
ID,ID_CITY,CITY with NAME NED ID_COUNTRY 2
STATUS with NAME riCK ID_COUNTRY 3
ID,ID_COUNTRY with NAME nich ID_COUNTRY 6
CITY,STATUS with NAME DIONIC ID_COUNTRY 5
4 ROWS ARE MISSING
1
Ralubrusto 29 oct. 2020 à 02:52

Je ne sais pas quel code vous avez utilisé pour le comparer ligne par ligne ou quelles sont vos conditions, mais une chose que vous pouvez essayer est de convertir toutes les lignes de chaînes en chaînes en minuscules ...

df.update(df.select_dtypes('object').applymap(str.lower))
# 'object' is used to refer to strings in pandas dtypes

Ou si vous souhaitez conserver les colonnes d'origine, vous pouvez essayer de créer de nouvelles colonnes temporaires ...

df['name_lower'] = df['name'].apply(str.lower)
df1['name_lower'] = df1['name'].apply(str.lower)
0
Andrew Pye 28 oct. 2020 à 22:16