[PYTHON] Mémorandum de développement ~ pandas, prévisions, structure de données ~

Aperçu

Récemment, j'ai eu l'opportunité d'automatiser mon travail. Quant au contenu,

--Utilisez la bibliothèque gspread pour extraire les horaires sur les feuilles de calcul Google

C'était une chose relativement simple. Le degré actuel de perfection est d'environ 80%. C'était plus difficile que ce à quoi je m'attendais et j'ai eu beaucoup de choses, alors j'écris cet article pour pouvoir le résumer pour l'avenir. C'est peut-être un peu brouillon, mais j'espère que vous pouvez le voir avec des yeux chaleureux.

Connaissance

Ce qui suit est un résumé de l'apprentissage des connaissances, principalement des bibliothèques et des spécifications de programmes.

1.) Attribution de pandas.DataFrame pointe vers le même objet

Je pense que c'est une évidence pour ceux qui connaissent les bases de données. J'ai fait la même erreur en traitant des listes avant, mais je n'y ai pas pensé et je l'ai refaite.

La situation est que vous essayez d'initialiser un dictionnaire avec un type datetime comme clé avec un bloc de données vide comme indiqué ci-dessous. J'ai fait comme "Je veux regrouper les personnes qui utilisent des sections par date, alors enregistrez un bloc de données vide pour le moment!"

python


import pandas as pd
import datetime


empty_user = dict(Section1=['', '', ''], Section2=['', '', ''], Section3=['', '', ''])
hour = ['9:00', '10:00', '11:00']
df = pd.DataFrame(data=empty_user, index=hour)

five_days_list = [(datetime.datetime(2020, 9, 1) + datetime.timedelta(days=1) * i) for i in range(5)]
dict_of_dataframe = {date_key : df for date_key in five_days_list}

Le dictionnaire terminé ressemble à ceci.

date_key : 2020-09-01 00:00:00
value :
      Section1 Section2 Section3
9:00                            
10:00                           
11:00                           
date_key : 2020-09-02 00:00:00
#Omis ci-dessous

Il y a environ une semaine, je n'avais aucun doute à ce sujet et je suis passé à la tâche suivante. Cependant, lorsque je commence à enregistrer les données agrégées, cela ne fonctionne pas du tout. De l'horaire d'environ un mois, le troisième jour et les suivants sont foirés.

La raison est simple quand j'y pense maintenant. Cette méthode de création réutilise simplement la même trame de données encore et encore. Ce sera plus visible si vous sortez en utilisant id ().

python


for date_key, dataframe in dict_of_dataframe.items():
    print(f"date_key : {date_key}")
    print(f"dataframe_id : {id(dataframe)}")
date_key : 2020-09-01 00:00:00
dataframe_id : 2124838088520
date_key : 2020-09-02 00:00:00
dataframe_id : 2124838088520
date_key : 2020-09-03 00:00:00
#Omis ci-dessous

Pour être correct, j'ai dû utiliser copy (), une méthode de pandas.DataFrame.

python


dict_of_dataframe = {date_key : df.copy() for date_key in five_days_list}
date_key : 2020-09-01 00:00:00
dataframe_id : 2124838588936
date_key : 2020-09-02 00:00:00
dataframe_id : 2124838590152
date_key : 2020-09-03 00:00:00

Document officiel Pandas, mais il s'agit d'une copie de la base de données. La méthode () prend par défaut la valeur deep = True, une copie profonde. Si vous souhaitez simplement l'utiliser comme modèle, vous devez l'utiliser comme objet. Quand je l'ai remarqué, j'ai ressenti le choc d'être frappé.

Comme cela sera décrit plus loin, ce travail s'est accompagné d'une structure de données assez profonde et de la structure multi-boucles associée. Au début, je n'étais préoccupé que par cette personne, donc je pense que j'ai souffert pendant environ deux jours à cause de la lutte de cela et de cela, comme la sortie des progrès, la lecture du document sur les pandas, l'écriture de la structure de la boucle sur papier, etc. Je vais.

2.) pour: else: c'est très pratique

Je pensais connaître un peu la grammaire de base de Python, mais j'ai rencontré cet enfant pour la première fois pendant le développement. Ou je le savais mais je l'ai oublié. Si vous utilisez l'instruction else avec l'instruction for, l'instruction else ne sera exécutée ** que si vous ne pouvez pas interrompre la boucle de l'instruction for **.

Je pense qu'il y a d'innombrables utilisations, mais je l'ai utilisé pour obtenir une notification de journal lorsqu'il n'y a pas de section gratuite comme indiqué ci-dessous.

python


client_salesman_dict = {datetime.datetime(2020, 9, 1, 9, 0) :  [('M. Yamada', 'Takahashi'), ('M. Yoshizawa', 'Ito')],
                        datetime.datetime(2020, 9, 1, 10, 0) : [('M. Sasaki', 'Momoyama')],
                        datetime.datetime(2020, 9, 1, 11, 0) : [('M. Yokota', 'Takahashi'), ('Fukuchi', 'grand arbre'), ('M. Nakayama', 'Ito'), ('M. Gonda', 'Ozawa')],}

section_list = ['Section1', 'Section2', 'Section3',]

for date_dt, client_salesman_tuples in client_salesman_dict.items():
    date_str = f"{date_dt.hour}:{date_dt.minute:02}"
    
    for client_salesman_tuple in client_salesman_tuples:
        client = client_salesman_tuple[0]
        salesman = client_salesman_tuple[1]
        
        for section in section_list:
            section_status = df.loc[date_str, section]
            print(f"client : {client}, salesman : {salesman}")
            print(f"time is {date_str}")
            print(f"section is {section}")
            print(f"section_status is {section_status}")
            if section_status:
                print(f"bool of section_status is {bool(section_status)}.")
                print("I will skip writing phase.")
                continue
            print(f"I have applied {client},{salesman} to {section}")
            df.loc[date_str, section] = f"{client} {salesman}"
            break
            
        else:
            print(f"There is no empty section for{client}, {salesman}.Please recheck schedule.")
client :M. Yamada, salesman :Takahashi
time is 9:00
section is Section1
section_status is 
J'ai appliqué M. Yamada,Takahashi à la section 1
client :M. Yoshizawa, salesman :Ito
time is 9:00
section is Section1
section_le statut est M. Yamada Takahashi
bool of section_status is True.
I will skip writing phase.
#Omission
Il n'y a pas de section vide pour Gonda,Ozawa.Please recheck schedule.

Il était une fois, quand je faisais un traitement similaire en langage C ou Java, je pense que je faisais de mon mieux avec un drapeau défini à l'intérieur, mais cela semble inutile pour Python. C'est sobre, mais il existe de nombreuses possibilités d'utiliser la phrase for elle-même, alors j'aimerais continuer à l'utiliser le cas échéant.

3.) Un _ avant l'attribut est une déclaration privée habituelle, deux _ le rendent inaccessible de la manière habituelle

Je savais qu'il existait depuis longtemps, mais je n'y ai pas prêté attention et je l'ai utilisé moi-même. Si vous testez correctement le comportement, vous verrez quelque chose comme ça.

python


class TestClass:
    def __init__(self):
        self.hoge = 1
        self._fuga = 2
        self.__monge = 3
    
    def _foo1(self):
        print("_foo1 is called")
    
    def __foo2(self):
        print("__foo2 is called")

t = TestClass()

#Variable d'instance
print(t.hoge)
print(t._fuga)
# print(t.__monge)← Je ne peux pas appeler
print(t._TestClass__monge)

#Méthode de classe
t._foo1()
# t.__foo2()← Je ne peux pas appeler
t._TestClass__foo2()
1
2
3
_foo1 is called
__foo2 is called

Si vous ajoutez deux traits de soulignement au début, vous ne pourrez pas appeler les variables d'instance ou les méthodes de classe comme d'habitude. Cependant, ce n'est pas un attribut privé robuste comme en Java.

python


instance.__ClassName_AttributeName

Il est possible de l'appeler avec.

De plus, si vous mettez un trait de soulignement au début ... Vous pouvez également l'appeler. De plus, normalement. Quand je me suis demandé: "Eh bien, à quoi ça sert?", J'ai trouvé le site suivant.

[Python] Comment utiliser le trait de soulignement (_) (attribut spécial, dunders)

Selon cela, apparemment

――Lorsqu'il en est un, cela suggère uniquement qu'il est à usage interne, et le fonctionnement ne change pas en particulier. Cependant, il ne sera pas chargé uniquement lorsqu'il est appelé en utilisant des caractères génériques comme module. ――Quand il y en a deux, le nom sera mutilé (modification du nom), vous ne pourrez donc pas y accéder tel quel. Cependant, il n'est pas destiné à être privé, mais est utilisé pour éviter les conflits de noms entre les classes ayant une relation parent-enfant.

Il semble. En premier lieu, il était étrange de reconnaître que c'était pour rendre privé. Cette fois, j'ai créé le programme sans hériter de la classe, donc utiliser un trait de soulignement était suffisant.

4.) docstring est une bonne culture

Je savais en quelque sorte qu'il existait aussi, mais c'était la première fois que je l'utilisais. Je me réfère aux articles suivants lors de la création.

[Python] Apprenez à écrire une docstring pour améliorer la lisibilité (style NumPy)

Puisque ce programme a été développé pour moi-même, je l'ai écrit en pensant "Est-ce nécessaire?", Mais par conséquent, "quoi utiliser", "pour quoi", et "quoi faire" C'était l'occasion de réfléchir fermement. Jusqu'à présent, c'était une façon ad hoc de commencer à écrire d'une manière ou d'une autre, de la déplacer une fois, puis de la corriger, mais je pense que l'écriture d'une docstring l'a un peu amélioré.

Façon de penser

Ce qui suit est le point que j'ai appris empiriquement: «Je pense que c'est mieux» que la connaissance.

1.) Les structures de données trop profondes sont absentes

Quand j'ai commencé à organiser mon emploi du temps, j'organisais mes données dans un dictionnaire comme celui-ci:

python


from datetime import datetime

from datetime import datetime

schedule_dict = {'1week': {datetime(2020, 9, 1) : {datetime(2020, 9, 1, 9, 0): [('M. Yamada', 'Terada'),('M. Yoshiki', 'Endo'),],
                                                    datetime(2020, 9, 1, 10, 0): [('M. Kudo', 'Yamashita'),],},
                            datetime(2020, 9, 2) : {datetime(2020, 9, 2, 10, 0): [('M. Tsurukawa', 'Honda'),],
                                                    datetime(2020, 9, 2, 11, 0): [('M. Endo', 'Aizawa'),],},
                            datetime(2020, 9, 2) : {datetime(2020, 9, 3, 9, 0): [('M. Shimoda', 'Terada'), ('M. Yoshikawa', 'Goda')],
                                                   }
                           }
                '2week': ....}

Cela ressemble à ceci lors de l'accès.

python


schedule_dict['2week'][datetime(2020, 9, 8)][datetime(2020, 9, 8, 10, 0)]

Les données côté feuille de calcul étaient disposées côte à côte chaque semaine, donc je ne pensais à rien de particulier, mais c'était inutilement profond. C'est toujours cool d'accéder, et la hiérarchie des boucles devient de plus en plus profonde lors de l'expansion avec une instruction for lors de son utilisation.

Après tout, j'ai pris racine au milieu du travail, j'ai perdu la clé de la semaine et je l'ai rendue moins profonde d'un niveau. Quand je le relis, je sens que je n'ai même pas besoin de la clé de date 0 heures. Si vous en avez besoin, vous pouvez accéder à chacun des attributs year, month et day du type datetime.datetime et les recréer.

On dit souvent que "les boucles inutilement profondes devraient être évitées", mais j'ai appris qu '"il faut aussi éviter de créer des couches de données inutilement profondes" qui en sont la cause. Je sens que la charge par processus est doublée ** à chaque fois que la hiérarchie s'approfondit. La mémoire du cerveau est aspirée durement ...

2.) Donnez un nom décent même s'il s'allonge un peu

Au début du développement, le nom utilisé lors du test de la partie partielle a été utilisé tel quel pour le nom de la variable. Le traitement étant classé en fonction de la cible, il n'y a pas de conflit de nom. J'ai essayé d'écrire le plus court possible, comme df pour les cadres de données, la date pour les dates et dct pour les dictionnaires.

Cependant, j'ai immédiatement heurté le mur. Il s'agit plus de la mémoire du cerveau que du problème des spécifications du programme. Au fur et à mesure que le processus se complique, "Oh, que contient ce dictionnaire?" "Je lance une erreur, mais cette date n'est-elle pas un type de chaîne?" "Index hors de portée ??? Des problèmes tels que "La liste du nombre d'éléments que j'utilisais n'est-elle pas?"

Jusqu'à présent, je n'écrivais qu'un exemple de programme pour comprendre les spécifications à la légère, donc je m'en fichais beaucoup, mais ** le nom devrait être donné afin qu'il puisse être compris où qu'il vole **. .. Cela semble naturel dans les mots, et je n'y avais pas vraiment pensé.

date_dt pour les dates de type datetime, date_str pour les dates de type str. Après cela, nommez-le client_salesman_tuples_list pour indiquer ce qui est stocké, et utilisez le nom utilisé lors du développement dans l'instruction for, comme pour client_salesman_tuple dans client_salesman_tuples_list:, en considérant la forme singulière et la forme plurielle. Je l'ai fait.

Grâce à vous, c'est un peu plus facile à comprendre qu'au début. En premier lieu, il serait idéal de ne pas faire de traitement qui perturberait le cerveau, mais si vous n'avez pas assez de compétences pour cela, vous ne serez pas suffisant, et je tiens à garder à l'esprit que le nom sera inventé.

3.) Orienté objet imagine un bureau gouvernemental ou une entreprise

Je ne suis pas sûr que ce soit vraiment correct. Cependant, il y a environ deux semaines, quand je l'ai assemblé de la partie au tout, j'ai écrit environ 100 lignes à plat et je suis revenu à moi-même. Ce serait un gros problème s'il était dans cet état. J'ai eu une petite révélation du site suivant qui est sortie après quelques recherches.

Qu'est-ce qu'un espace de noms?

Je pense que l'orientation objet est la tâche de diviser correctement l'espace de noms self à travers la classe.

J'ai été surpris pendant un moment quand j'ai vu le mot «division appropriée», mais tout à coup j'ai eu l'idée «** N'est-ce pas la même chose que le bureau du gouvernement? **».

Il y a quelque temps, j'ai dû me rendre à la mairie pour obtenir une carte de résident et attendre un moment. Pendant que j'attendais, je regardais le site du bureau du gouvernement sans aucune raison, mais il était vraiment finement divisé. Citoyens, tourisme d'affaires et industriels, construction, urbanisme etc etc ... À première vue, certains peuvent penser: «La construction et l'urbanisme ne sont-ils pas les mêmes?», Mais en réalité, ils sont divisés par la section △△ du département ○○. Je ne connais pas le contenu de l'œuvre, mais il semble qu'ils soient bien partagés. C'est la même chose que "** Classification **".

Parfois, une collaboration ministérielle peut être nécessaire, mais toutes les informations ne seront pas transmises. Le papier et les données seront inondés. Il est plus logique que la personne responsable apporte et discute autant d'informations que nécessaire pour le travail. C'est la même chose que "** Synthétiser à partir de l'héritage **".

De plus, «moi» qui a demandé l'acquisition du certificat de résidence ne sait pas quel type de traitement est effectué à l'intérieur. J'imagine que le responsable remplit les documents en saisissant diverses choses sur l'ordinateur, mais je ne fais que rédiger le formulaire de demande et le payer. Ensuite, vous pouvez recevoir le certificat de résidence sans aucun problème. Peut-être même ceux qui travaillent au comptoir ne savent pas tout sur ce à quoi servent les documents spécifiquement écrits et les données saisies et comment ils sont stockés. C'est la même chose que "** Masquage d'informations **".

Avec ce genre de sentiment, quand j'ai imaginé un bureau gouvernemental dans mon esprit, j'ai réussi à le classer. Même si je l'écris moi-même, je ne suis pas sûr que cela corresponde vraiment à cette compréhension, mais j'ai pu l'écrire de manière courbe, donc je suis provisoirement OK.

J'ai pensé, Qiita avait un article opportun. Je pense que c'est une explication beaucoup plus simple, alors veuillez vous y référer.

Prescription de conception orientée objet parlée par un oncle orienté objet avec 25 ans d'histoire orientée objet

Je veux apprendre ici dans le futur

Enfin, j'écrirai que j'avais des connaissances et des idées, mais je ne pouvais pas les utiliser correctement après tout.

Utilisation d'itertools pour faire des déclarations superficielles

Je ne le savais plus, mais il existe une bibliothèque appelée itertools dans la bibliothèque Python standard. Pour une explication facile à comprendre, reportez-vous à ce post, mais ce sur quoi je me suis concentré ici, c'est la méthode du produit dans itertools.

Ce produit produit une sortie similaire à une boucle multiple typique, comme décrit dans la documentation officielle (https://docs.python.org/3/library/itertools.html#itertools.product). Te donnera.

python


import itertools

section_list = ['Section1', 'Section2', 'Section3']
time_list = ['9:00', '10:00', '11:00']

for section in section_list:
    for time in time_list:
        print(section, time)

print("------------")
        
for section, time in list(itertools.product(section_list, time_list)):
    print(section, time)

La sortie est la même.

Section1 9:00
Section1 10:00
Section1 11:00
Section2 9:00
Section2 10:00
Section2 11:00
Section3 9:00
Section3 10:00
Section3 11:00
------------
Section1 9:00
Section1 10:00
Section1 11:00
Section2 9:00
Section2 10:00
Section2 11:00
Section3 9:00
Section3 10:00
Section3 11:00

Vous pouvez également le recevoir sous forme de taple.

python


for tpl in list(itertools.product(section_list, time_list)):
    print(tpl)
('Section1', '9:00')
('Section1', '10:00')
('Section1', '11:00')
('Section2', '9:00')
('Section2', '10:00')
('Section2', '11:00')
('Section3', '9:00')
('Section3', '10:00')
('Section3', '11:00')

Je voulais vraiment l'utiliser pour réduire la hiérarchie des boucles, mais cela n'a pas fonctionné. Comme mentionné ci-dessus, j'ai douloureusement compris qu'une augmentation de la hiérarchie des boucles conduit directement à une augmentation de la charge sur le cerveau, je voudrais donc utiliser itertools ainsi que l'idée de la structure des données à l'avenir.

Résumé

En tant que conseil pour les débutants en programmation, j'entends souvent "Pourquoi n'essayez-vous pas de faire quelque chose pour le moment?", Mais je comprends que c'est un conseil vraiment raisonnable. J'ai eu des difficultés environ 10 fois plus que ce que j'imaginais, mais je sens que j'ai beaucoup de choses.

Si vous avez des opinions ou des conseils, veuillez les laisser dans la section commentaires.

Recommended Posts

Mémorandum de développement ~ pandas, prévisions, structure de données ~
Mémorandum de Pandas
mémorandum pandas
lecture de données pandas
Mémorandum d'opération Pandas
[Pour enregistrement] Mémorandum Pandas
Visualisation des données avec les pandas
Manipulation des données avec les Pandas!
Mélangez les données avec les pandas
[Tutoriel Python] Structure des données
structure de données Python push pop
Traitement des données 3 (développement) À propos du format des données
Mémorandum (pseudo Vlookup par pandas)
Mémorandum @ Python OU Séminaire: Pandas
Analyse de données à l'aide de pandas python
Conseils de traitement des données avec Pandas