DictReader en dictionnaire

L'auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Bonjour,

J'utilise actuellement le module csv de python. J'utilise la méthode DictReader() qui me retourne un objet qui ressemble à un dico mais qui n'en est pas un. Je voudrais donc transformer cet objet en vrai dictionnaire. Voici à quoi ressemble ma fonction pour le moment :

1
2
3
4
5
6
def read_one_week(csv_file):
    with open(csv_file, 'rb') as data:
        reader = csv.DictReader(data)

        for row in reader:
            print row

J'ai bien essayé de faire ça :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
def read_one_week(csv_file):
    with open(csv_file, 'rb') as data:
        reader = csv.DictReader(data)

        result = []

        for row in reader:
            for key, value in row.items():
                dico = {}
                dico[key] = int(value)
            result.append(dico)

        for row in result:
            print row

read_one_week('test.csv')

Mais j'obtient :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
{'time': 10}
{'time': 11}
{'time': 12}
{'time': 13}
{'time': 14}
{'time': 15}
{'time': 16}
{'time': 17}
{'time': 7}
{'time': 8}
{'time': 10}
{'time': 15}
{'time': 16}
{'time': 20}
{'time': 22}
{'time': 23}
{'time': 3}
{'time': 6}
{'time': 8}

....
Voici ce que me renvoie ma première fonction :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
{'weekday': '0', 'moisture': '434', 'time': '10'}
{'weekday': '0', 'moisture': '560', 'time': '11'}
{'weekday': '0', 'moisture': '650', 'time': '12'}
{'weekday': '0', 'moisture': '340', 'time': '13'}
{'weekday': '0', 'moisture': '980', 'time': '14'}
{'weekday': '0', 'moisture': '880', 'time': '15'}
{'weekday': '0', 'moisture': '434', 'time': '16'}
{'weekday': '0', 'moisture': '434', 'time': '17'}
{'weekday': '1', 'moisture': '434', 'time': '07'}
{'weekday': '1', 'moisture': '560', 'time': '08'}
{'weekday': '1', 'moisture': '650', 'time': '10'}
{'weekday': '1', 'moisture': '340', 'time': '15'}
{'weekday': '1', 'moisture': '980', 'time': '16'}
{'weekday': '1', 'moisture': '880', 'time': '20'}
{'weekday': '1', 'moisture': '434', 'time': '22'}
{'weekday': '1', 'moisture': '434', 'time': '23'}
{'weekday': '2', 'moisture': '434', 'time': '03'}

Il y a déjà pas mal de sujet sur stackoverflow avec cette question, mais aucunes des solutions proposés n'a fonctionné (même en essayant d'adapter!).

Du coup, je me tourne vers vous. Merci de votre aide et bonne journée!

Édité par Wizix

Mon projet : OpenPlane, un utilitaire en Java pour les pilotes, les vrais !

+0 -0
Staff

Cette réponse a aidé l'auteur du sujet

Un truc comme ça devrait fonctionner sur les deux versions de python :

1
result = [dict(row.items()) for row in reader]

PS: ton problème viens de ta ligne 9 qui devrait être entre les lignes 7 et 8

Édité par Kje

+0 -0

J'utilise la méthode DictReader() qui me retourne un objet qui ressemble à un dico mais qui n'en est pas un.

Si c'est bien un vrai dictionnaire, d'ailleurs le code source de csv.py le prouve…

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class DictReader:
    def __init__(self, f, fieldnames=None, restkey=None, restval=None,
                 dialect="excel", *args, **kwds):
        self._fieldnames = fieldnames   # list of keys for the dict
        self.restkey = restkey          # key to catch long rows
        self.restval = restval          # default value for short rows
        self.reader = reader(f, dialect, *args, **kwds)
        self.dialect = dialect
        self.line_num = 0

    def __iter__(self):
        return self

    @property
    def fieldnames(self):
        if self._fieldnames is None:
            try:
                self._fieldnames = self.reader.next()
            except StopIteration:
                pass
        self.line_num = self.reader.line_num
        return self._fieldnames

    @fieldnames.setter
    def fieldnames(self, value):
        self._fieldnames = value

    def next(self):
        if self.line_num == 0:
            # Used only for its side effect.
            self.fieldnames
        row = self.reader.next()
        self.line_num = self.reader.line_num

        # unlike the basic reader, we prefer not to return blanks,
        # because we will typically wind up with a dict full of None
        # values
        while row == []:
            row = self.reader.next()
        d = dict(zip(self.fieldnames, row))
        lf = len(self.fieldnames)
        lr = len(row)
        if lf < lr:
            d[self.restkey] = row[lf:]
        elif lf > lr:
            for key in self.fieldnames[lr:]:
                d[key] = self.restval
        return d

Comme on peut le voir, quand on itère sur un objet DictReader, sa méthode next crée un vrai dictionnaire

1
d = dict(zip(self.fieldnames, row))

et retourne ce dictionnaire

1
return d

Pour ta question je ne comprend pas sous quelle forme tu souhaites l'avoir, mais avec ce type de retour, il n'y a pas de réel intérêt à retransformer ce type de résultat.

+1 -0
Auteur du sujet

Merci de vos réponses.
J'ai corrigé mon code, qui fonctionne exactement comme je le voulais, voici à quoi il ressemble :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
def csv2dict(csv_file):
    """
        Converti un fichier csv en une liste de dictionnaires sous la forme :
        [
            {'key' : value, 'key' : value, 'key' : value, ...},
            {'key' : value, 'key' : value, 'key' : value, ...},
            {'key' : value, 'key' : value, 'key' : value, ...},
            ...
        ]
    """

    with open(csv_file, 'rb') as data:
        reader = csv.DictReader(data)

        result = []

        for row in reader:
            dico = {}  # Le dictionnaire de chaque ligne
            for key, value in row.items():
                if value == None:
                    value = 0  # Si il n'y a pas de valeur, on la met à 0

                # On converti en int les données qui doivent être converties
                if key in ['moisture', 'time', 'weekday']:
                    dico[key] = int(value)
                else:
                    dico[key] = value
            result.append(dico)  # Puis on ajoute la ligne au résultat final

        return result

@fred1599 : Je ne savais pas que c'était un vrai dictionnaire ! En faite j'avais essayé une manip dessus qui fonctionne avec les dict de python et qui n'avais pas fonctionné sur les DictReader. Mais maintenant que tu le dis, ce n'était peut être qu'une faute de frappe…
En tout cas je dois réécrire un dict car je modifie des valeurs dedans (je ne converti que certaines valeurs, je met les None à 0…).

Après , si il y a moyen d'alléger le code, je suis preneur, car c'est un raspberry pi qui va faire tourner ça une fois par semaine en plus d'autres Threads

Mon projet : OpenPlane, un utilitaire en Java pour les pilotes, les vrais !

+0 -0

On peut l'alléger, ne touche pas aux dictionnaires, interprète les selon tes critères tout simplement, je ne vois pas ce qui t'embête. Si on pouvait connaître l'objectif par la suite, on pourrait aider sur l'idée à concevoir.

+0 -0
Auteur du sujet

Explication du projet.
Je viens de m'acheter une plante (magnifique bonsaï). Seulement je n'ai pas forcément la main verte et j'adore les données. J'ai donc acheté 3 capteurs, un d'humidité du sol, un de luminosité et un de température et d'humidité ambiante (oui il fait les deux).

Ces capteurs prennent des données toutes les heures et les enregistres dans un fichier csv qui possède cette forme :

1
id,moisture,perc,temp,humidity,brightness,brightness_volt,date,time,weekday

On a :

  • id : qui est l'id du relevé
  • moisture : qui est la valeur du capteur d'humidité du sol (environ entre 300 et 1024)
  • perc : qui est moisture transformé en pourcentage
  • temp : qui est la température
  • humidity : qui est l'humidité de l'air ambiant
  • brightness : qui est la luminosité
  • brightness_volt : qui est la luminosité en volt
  • date : qui est la date de la mesure de la forme dd.mm.yyyy
  • time : qui est l'heure de la mesure (0 étant minuit et 23, 23h)
  • weekday : qui est le jour de la semaine (0 étant lundi et 6 dimanche)

L'objectif de ces données est d'en faire des stats. Par exemple sur ce sujet j'ai cherché à fait une heat map à partir des valeurs de moisture.

Je cherche maintenant à extraire les données de moisture afin d'en faire cette heat map. Mais il y a des conditions :

  • Les valeurs doivent aller du lundi à 1h du matin au dimanche à minuit.
  • Si il manque une heure (si une ligne n'existe pas) on ajoute cette ligne avec toutes les valeurs à 0 (sauf date, time, weekday et id)
  • Si plusieurs lignes on la même heure on fait une moyenne de ces lignes

Pour la heat map il me faut une list sous cette forme :

1
2
3
4
5
6
7
8
9
[
    [0,0,0,0,0,0,0,0,0,0,434,560,650,340,980,880,434,434,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,434,560,0,650,0,0,0,0,340,980,0,0,0,880,0,434,343],
    [0,0,0,0,0,0,0,0,0,0,434,560,650,340,980,880,434,434,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,434,560,0,650,0,0,0,0,340,980,0,0,0,880,0,434,343],
    [0,0,0,0,0,0,0,0,0,0,434,560,650,340,980,880,434,434,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,434,560,0,650,0,0,0,0,340,980,0,0,0,880,0,434,343],
    [0,0,0,0,0,0,0,0,0,0,434,560,650,340,980,880,434,434,0,0,0,0,0,0]
]

Ce sont des valeurs au pif, donc normal qu'il y ait beaucoup de 0. En tout cas, une list contient 7 list (une pour chaque jour) avec 24 valeurs (une pour chaque heure). Ces valeurs vont être traduite pour une heat map.

En espérant que j'ai été assez clair !

Édité par Wizix

Mon projet : OpenPlane, un utilitaire en Java pour les pilotes, les vrais !

+0 -0

En fait je ne demandais pas tant de détails, mais tant qu'à faire, on a le problème maintenant…

Il est donc comme je l'avais dis possible de travailler avec chaque dictionnaire créé par ton DictReader, et sans tester je dirais qu'un truc comme ci-dessous doit pas être infaisable.

1
2
3
4
5
6
7
8
9
def getMoisture(reader, weekday):
    '''return mosture for a day'''
    myDicts = [row for row in reader if row['weekday'] == str(weekday)]
    times = [0 for i in range(24)] # 24 hours
    for row in myDicts:
        myTime = int(row['time'])
        mosture = row['mosture']
        times[myTime] = mosture
    return times

Enfin faut sûrement adapté, par exemple, pour minuit, son indice est 0 en considérant que row['time'] vaudrait '00'. Dans mes posts précédents, je voulais surtout que tu te rendes compte que les données reçu par ton DictReader sont interprétables sans passer par une nouvelle création de dictionnaire. J'espère avoir aidé.

+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte