Je suis nouveau sur Python.

J'essaie d'ajouter un préfixe (numéro de série) à un élément dans une trame de données en utilisant la boucle for, à voir avec le nettoyage / la préparation des données avant l'analyse.

Le code est

a=pd.read_excel('C:/Users/HP/Desktop/WFH/PowerBI/CMM data.xlsx','CMM_unclean')
a['Serial Number'] = a['Serial Number'].apply(str)
print(a.iloc[72,1])

for index,row in a.iterrows():
    if len(row['Serial Number']) == 6:
        row['Serial Number'] = 'SR0' + row['Serial Number']
        print(row['Serial Number'])

print(a.iloc[72,1])

La sortie est

C:\Users\HP\anaconda3\envs\test\python.exe C:/Users/HP/PycharmProjects/test/first.py
101306
SR0101306
101306

Je ne comprends pas pourquoi cela se produit à l'intérieur de la boucle for, la valeur change, mais à l'extérieur, c'est la même chose.

2
Saurabh Arya 9 mai 2020 à 14:47

4 réponses

Meilleure réponse

Cela ne modifiera jamais la trame de données réelle nommée a.

TL; DR: les lignes que vous récupérez à partir des iterrows sont des copies qui ne sont plus connectées à la trame de données d'origine, donc les modifications ne modifient pas votre trame de données. Cependant, vous pouvez utiliser l'index pour accéder et modifier la ligne appropriée du dataframe.


EXPLICATION

Pourquoi?

Les lignes que vous récupérez iterrows sont des copies qui ne sont plus plus connectées au bloc de données d'origine , donc les modifications ne modifient pas votre dataframe. Cependant, vous pouvez utiliser index pour accéder et modifier la ligne appropriée du dataframe.


La solution est la suivante:

import pandas as pd

a = pd.read_excel("Book1.xlsx")
a['Serial Number'] = a['Serial Number'].apply(str)

a.head()
#    ID    Serial Number
# 0   1     SR0101306
# 1   2       1101306

print(a.iloc[0,1])
#101306

for index,row in a.iterrows():
    row = row.copy()
    if len(row['Serial Number']) == 6:
        # use the index and .loc method to alter the dataframe
        a.loc[index, 'Serial Number'] = 'SR0' + row['Serial Number']

print(a.iloc[0,1])
#SR0101306
1
seralouk 9 mai 2020 à 12:13

Dans la documentation, j'ai lu (souligné à partir de là)

Vous ne devez jamais modifier quelque chose que vous répétez. Ce n'est pas garanti de fonctionner dans tous les cas. Selon les types de données, l'itérateur renvoie une copie et non une vue, et l'écriture dessus n'aura aucun effet.

Peut-être que cela signifie dans votre cas qu'une copie est faite et qu'aucune référence n'est utilisée. Ainsi, le changement s'applique temporairement à la copie mais pas aux données de la trame de données.

1
Wolf 9 mai 2020 à 12:00

Un changement de valeur se fait ici:

    if len(row['Serial Number']) == 6:
        row['Serial Number'] = 'SR0' + row['Serial Number']
        print(row['Serial Number'])

Ou, pour être précis row['Serial Number'] = 'SR0' + row['Serial Number'] ici.

row['Serial Number'] est 101306, donc la condition ci-dessus est vraie, la longueur est de 6. Vous modifiez la valeur manuellement.

Pour le changer globalement, définissez simplement les variables index et row comme des variables global.

0
Muhammadrasul 9 mai 2020 à 11:54

Puisque vous utilisez déjà apply, vous pouvez le faire directement dans la fonction que vous appelez apply avec:

def fix_serial(n):
    n_s = str(n)

    if len(n_s) == 6:
        n_s = 'SR' + n_s

    return n_s

a['Serial Number'] = a['Serial Number'].apply(fix_serial)
0
MatsLindh 9 mai 2020 à 12:00