Obtención, procesamiento y almacenamiento de datos de Analytics MixPanel a SQLite -- python campo con json campo con sqlite campo con pandas camp codereview Relacionados El problema

Fetching, processing, and storing Mixpanel analytics data to SQLite


4
vote

problema

Español

Soy un programador de python autodidacta y nunca aprendí los fundamentos de la programación, por lo que quiero ver cómo mejorar este script y hacer que se adhiera a las mejores prácticas.

El script tiene tres funciones que recuperan datos de una API, limpian los datos y lo almacenan en un DB SQLite. Este script va a ejecutarse diariamente en un cron y agregar a las mesas SQLite todas las mañanas.

  1. import UIKit //liste de mot et image var imageAndWord = ["Maison": #imageLiteral(resourceName: "image 1"),"Bateau": #imageLiteral(resourceName: "image2") ,"Train": #imageLiteral(resourceName: "image 3"),"Vase": #imageLiteral(resourceName: "image 4")] //récupération des clées var theKey = Array(imageAndWord.keys) // Nombre de clé let totalKey = theKey.count + 1 //récupération des valeurs var theValue = Array(imageAndWord.values) // comptage d'image trouvé var imageFindNumber = 0 class ViewController: UIViewController { // initialisation des vues @IBOutlet var lettersButtons: [UIButton]! @IBOutlet weak var imageView: UIImageView! @IBOutlet weak var wordLabel: UILabel! @IBOutlet weak var scoreLabel: UILabel! //Quand une lettre est pressée @IBAction func lettersButtonsPressed(_ sender: UIButton) { sender.isEnabled = false let letter = sender.title(for: .normal)! let lowCasedLetter = Character(letter.lowercased()) currentGame.playerGuessed(lowCasedLetter) if currentGame.correctWord == currentGame.formatedWord { newRound() } updateUI() } // Actualisation de l'interface func updateUI() { let word = currentGame.formatedWord.map{String($0)} let spacingWord = word.joined(separator: " ") wordLabel.text = spacingWord imageView.image = currentGame.image scoreLabel.text = "Image: (imageFindNumber)/(totalKey)" } var currentGame: Game! // Initialisation de l'image et du mot func newRound() { if !theKey.isEmpty && !theValue.isEmpty { enableOrNotButton(true) let word = theKey.removeFirst().lowercased() let value = theValue.removeFirst() currentGame = Game(correctWord:word, image:value, guessedLetter: []) imageFindNumber += 1 updateUI() } else { enableOrNotButton(false) } } //Activation ou désactivation de tout les bouttons func enableOrNotButton(_ enable: Bool) { for button in lettersButtons { button.isEnabled = enable } } override func viewDidLoad() { super.viewDidLoad() newRound() print(currentGame.correctWord) // Do any additional setup after loading the view, typically from a nib. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } } 0 Fetches Los datos y lo convierten en un Frame de Pandas.

  2. import UIKit //liste de mot et image var imageAndWord = ["Maison": #imageLiteral(resourceName: "image 1"),"Bateau": #imageLiteral(resourceName: "image2") ,"Train": #imageLiteral(resourceName: "image 3"),"Vase": #imageLiteral(resourceName: "image 4")] //récupération des clées var theKey = Array(imageAndWord.keys) // Nombre de clé let totalKey = theKey.count + 1 //récupération des valeurs var theValue = Array(imageAndWord.values) // comptage d'image trouvé var imageFindNumber = 0 class ViewController: UIViewController { // initialisation des vues @IBOutlet var lettersButtons: [UIButton]! @IBOutlet weak var imageView: UIImageView! @IBOutlet weak var wordLabel: UILabel! @IBOutlet weak var scoreLabel: UILabel! //Quand une lettre est pressée @IBAction func lettersButtonsPressed(_ sender: UIButton) { sender.isEnabled = false let letter = sender.title(for: .normal)! let lowCasedLetter = Character(letter.lowercased()) currentGame.playerGuessed(lowCasedLetter) if currentGame.correctWord == currentGame.formatedWord { newRound() } updateUI() } // Actualisation de l'interface func updateUI() { let word = currentGame.formatedWord.map{String($0)} let spacingWord = word.joined(separator: " ") wordLabel.text = spacingWord imageView.image = currentGame.image scoreLabel.text = "Image: (imageFindNumber)/(totalKey)" } var currentGame: Game! // Initialisation de l'image et du mot func newRound() { if !theKey.isEmpty && !theValue.isEmpty { enableOrNotButton(true) let word = theKey.removeFirst().lowercased() let value = theValue.removeFirst() currentGame = Game(correctWord:word, image:value, guessedLetter: []) imageFindNumber += 1 updateUI() } else { enableOrNotButton(false) } } //Activation ou désactivation de tout les bouttons func enableOrNotButton(_ enable: Bool) { for button in lettersButtons { button.isEnabled = enable } } override func viewDidLoad() { super.viewDidLoad() newRound() print(currentGame.correctWord) // Do any additional setup after loading the view, typically from a nib. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } } 1 elimina algunos datos no necesarios.

  3. import UIKit //liste de mot et image var imageAndWord = ["Maison": #imageLiteral(resourceName: "image 1"),"Bateau": #imageLiteral(resourceName: "image2") ,"Train": #imageLiteral(resourceName: "image 3"),"Vase": #imageLiteral(resourceName: "image 4")] //récupération des clées var theKey = Array(imageAndWord.keys) // Nombre de clé let totalKey = theKey.count + 1 //récupération des valeurs var theValue = Array(imageAndWord.values) // comptage d'image trouvé var imageFindNumber = 0 class ViewController: UIViewController { // initialisation des vues @IBOutlet var lettersButtons: [UIButton]! @IBOutlet weak var imageView: UIImageView! @IBOutlet weak var wordLabel: UILabel! @IBOutlet weak var scoreLabel: UILabel! //Quand une lettre est pressée @IBAction func lettersButtonsPressed(_ sender: UIButton) { sender.isEnabled = false let letter = sender.title(for: .normal)! let lowCasedLetter = Character(letter.lowercased()) currentGame.playerGuessed(lowCasedLetter) if currentGame.correctWord == currentGame.formatedWord { newRound() } updateUI() } // Actualisation de l'interface func updateUI() { let word = currentGame.formatedWord.map{String($0)} let spacingWord = word.joined(separator: " ") wordLabel.text = spacingWord imageView.image = currentGame.image scoreLabel.text = "Image: (imageFindNumber)/(totalKey)" } var currentGame: Game! // Initialisation de l'image et du mot func newRound() { if !theKey.isEmpty && !theValue.isEmpty { enableOrNotButton(true) let word = theKey.removeFirst().lowercased() let value = theValue.removeFirst() currentGame = Game(correctWord:word, image:value, guessedLetter: []) imageFindNumber += 1 updateUI() } else { enableOrNotButton(false) } } //Activation ou désactivation de tout les bouttons func enableOrNotButton(_ enable: Bool) { for button in lettersButtons { button.isEnabled = enable } } override func viewDidLoad() { super.viewDidLoad() newRound() print(currentGame.correctWord) // Do any additional setup after loading the view, typically from a nib. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } } 2 envía los datos limpios a un DB SQLite, hay una tabla para cada uno de los tipos de eventos.

Todas las funciones se denominan en un 99887776655443313 -loop que itera a través de cada uno de los tipos de eventos.

Estoy abierto a cualquier sugerencia sobre cómo mejorar esto, pero aquí hay algunos pensamientos / preguntas que tengo:

  1. ¿Debería ser esta una clase? Nunca he usado uno antes porque siempre encontré funciones simples para ser menos confusas.

  2. ¿Debo estar usando un import UIKit //liste de mot et image var imageAndWord = ["Maison": #imageLiteral(resourceName: "image 1"),"Bateau": #imageLiteral(resourceName: "image2") ,"Train": #imageLiteral(resourceName: "image 3"),"Vase": #imageLiteral(resourceName: "image 4")] //récupération des clées var theKey = Array(imageAndWord.keys) // Nombre de clé let totalKey = theKey.count + 1 //récupération des valeurs var theValue = Array(imageAndWord.values) // comptage d'image trouvé var imageFindNumber = 0 class ViewController: UIViewController { // initialisation des vues @IBOutlet var lettersButtons: [UIButton]! @IBOutlet weak var imageView: UIImageView! @IBOutlet weak var wordLabel: UILabel! @IBOutlet weak var scoreLabel: UILabel! //Quand une lettre est pressée @IBAction func lettersButtonsPressed(_ sender: UIButton) { sender.isEnabled = false let letter = sender.title(for: .normal)! let lowCasedLetter = Character(letter.lowercased()) currentGame.playerGuessed(lowCasedLetter) if currentGame.correctWord == currentGame.formatedWord { newRound() } updateUI() } // Actualisation de l'interface func updateUI() { let word = currentGame.formatedWord.map{String($0)} let spacingWord = word.joined(separator: " ") wordLabel.text = spacingWord imageView.image = currentGame.image scoreLabel.text = "Image: (imageFindNumber)/(totalKey)" } var currentGame: Game! // Initialisation de l'image et du mot func newRound() { if !theKey.isEmpty && !theValue.isEmpty { enableOrNotButton(true) let word = theKey.removeFirst().lowercased() let value = theValue.removeFirst() currentGame = Game(correctWord:word, image:value, guessedLetter: []) imageFindNumber += 1 updateUI() } else { enableOrNotButton(false) } } //Activation ou désactivation de tout les bouttons func enableOrNotButton(_ enable: Bool) { for button in lettersButtons { button.isEnabled = enable } } override func viewDidLoad() { super.viewDidLoad() newRound() print(currentGame.correctWord) // Do any additional setup after loading the view, typically from a nib. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } } 4 ?

  import UIKit //liste de mot et image var imageAndWord = ["Maison": #imageLiteral(resourceName: "image 1"),"Bateau": #imageLiteral(resourceName: "image2") ,"Train": #imageLiteral(resourceName: "image 3"),"Vase": #imageLiteral(resourceName: "image 4")] //récupération des clées var theKey = Array(imageAndWord.keys) // Nombre de clé let totalKey = theKey.count + 1 //récupération des valeurs var theValue = Array(imageAndWord.values) // comptage d'image trouvé var imageFindNumber = 0 class ViewController: UIViewController {     // initialisation des vues     @IBOutlet var lettersButtons: [UIButton]!     @IBOutlet weak var imageView: UIImageView!     @IBOutlet weak var wordLabel: UILabel!     @IBOutlet weak var scoreLabel: UILabel!     //Quand une lettre est pressée     @IBAction func lettersButtonsPressed(_ sender: UIButton)     {         sender.isEnabled = false         let letter = sender.title(for: .normal)!         let lowCasedLetter = Character(letter.lowercased())         currentGame.playerGuessed(lowCasedLetter)         if currentGame.correctWord == currentGame.formatedWord         {             newRound()          }         updateUI()     }     // Actualisation de l'interface     func updateUI()     {         let word = currentGame.formatedWord.map{String($0)}         let spacingWord = word.joined(separator: " ")         wordLabel.text = spacingWord         imageView.image = currentGame.image         scoreLabel.text = "Image: (imageFindNumber)/(totalKey)"      }     var currentGame: Game!     // Initialisation de l'image et du mot     func newRound()     {         if !theKey.isEmpty && !theValue.isEmpty         {         enableOrNotButton(true)         let word = theKey.removeFirst().lowercased()         let value = theValue.removeFirst()         currentGame = Game(correctWord:word, image:value, guessedLetter: [])         imageFindNumber += 1         updateUI()         }         else         {             enableOrNotButton(false)         }     }     //Activation ou désactivation de tout les bouttons     func enableOrNotButton(_ enable: Bool)     {             for button in lettersButtons             {                 button.isEnabled = enable             }     }     override func viewDidLoad() {         super.viewDidLoad()         newRound()         print(currentGame.correctWord)         // Do any additional setup after loading the view, typically from a nib.     }      override func didReceiveMemoryWarning() {         super.didReceiveMemoryWarning()         // Dispose of any resources that can be recreated.     }   } 5  
Original en ingles

I'm a self-taught Python programmer and I never really learned the fundamentals of programming, so I want to see how to improve upon this script and make it adhere to best practices.

The script has three functions that retrieve data from an API, cleanse the data and store it in a sqlite db. This script is going to run daily on a cron and append to the sqlite tables every morning.

  1. get_data() fetches the data and turns it into a pandas dataframe.

  2. data_cleanse() removes some non-necessary data.

  3. send_to_db() sends the cleansed data to a sqlite db, there is one table for each of the event types.

All of the functions are called in a for-loop which iterates through each of the event types.

I'm open to any suggestions on how to improve this, but here are some thoughts/questions that I have:

  1. Should this be a class? I have never used one before because I always found plain functions to be less confusing.

  2. Should I be using a if __name__ == "__main__":?

import pandas as pd import json from datetime import date, timedelta from mixpanel_client_lib import Mixpanel import sqlite3 as db   def get_data(start_date, end_date, event_name):     con_data = Mixpanel(API_KEY, API_SECRET)      data = con_data.request(['export'], {         'event': [event_name],         'from_date': start_date,         'to_date': end_date     })      parameters = set()      events = []      for line in data.split('\n'):         try:             event = json.loads(line)             ev = event['properties']         except ValueError:             continue          parameters.update(ev.keys())         events.append(ev)      df = pd.DataFrame(events)        return df, event_name   def data_cleanse(df, event_name):     if event_name == "Video Played":         df = df[['$ios_ifa',                  'Groups',                  'Lifetime Number of Sessions',                  'Days Since Last Visit',                  'time',                  'Product ID',                  'Time Watched',                  'Video Length']]          df.columns = ['ios_id',                       'groups',                       'lifetime_sessions',                       'days_since',                       'time',                       'product_id',                       'time_watched',                       'video_length']          print df['lifetime_sessions'].value_counts()          df['groups'] = df['groups'].astype(str)          # remove admin users from data         idx = df['groups'].isin(['[u\'Admin-Personal\']', '[u\'Admin\']'])         df = df[~idx]          # remove '0' lifetime session users from data         idx = df['lifetime_sessions'].isin([0])         df = df[~idx]          return df, event_name      elif event_name == "Item Information Click" or 'Faved' or 'Add to Cart' or 'Tap to Replay':          print df.columns.values           df = df[['$ios_ifa',                  'Groups',                  'Lifetime Number of Sessions',                  'Days Since Last Visit',                  'time',                  'Product ID']]          df.columns = ['ios_id',                       'groups',                       'lifetime_sessions',                       'days_since',                       'time',                       'product_id']          df['groups'] = df['groups'].astype(str)          # remove admin users from data         idx = df['groups'].isin(['[u\'Admin-Personal\']', '[u\'Admin\']'])         df = df[~idx]          # remove '0' lifetime session users from data         idx = df['lifetime_sessions'].isin([0])         df = df[~idx]          return df, event_name   def send_to_db(df, event_name):       table_names = {         'Video Played': 'video_played',         'Item Information Click': 'item_info_click',         'Faved': 'faved',         'Add to Cart': 'add_to_cart',         'Tap to Replay': 'replay'     }       con = db.connect('/code/vid_score/test.db')     df.to_sql(table_names.get(event_name), con, flavor='sqlite', if_exists='append')     con.close()   ################  API_KEY = 'xxxxxxx' API_SECRET = 'xxxxxxx'  event_types = ['Video Played',                'Item Information Click',                'Faved',                'Add to Cart',                'Tap to Replay']   end_date = date.today() - timedelta(1) start_date = date.today() - timedelta(1)  for event in event_types:     df, event_name = get_data(start_date, end_date, event)     df, event_name = data_cleanse(df, event_name)     send_to_db(df, event_name) 
           

Lista de respuestas

2
 
vote
vote
La mejor respuesta
 

desde una primera mirada, el código es lo suficientemente bueno, lo que significa que puedes seguir el Flujo de control fácilmente y está claro qué hace cada función, por lo que La separación de los tres o cuatro pasos es bastante buena.

  1. Este script es bastante pequeño y no pasas demasiado datos; Yo diría que lo deje como sea, a menos que quiera tener un poco más de su reutilización. Otros scripts.
  2. sí, por favor, use Node& Node::operator=(const Node& other) { Note* newleft = nullptr; Node* newright = nullptr; // Do the dangerous stuff in isolation. // without changing the chaging the current object. try { newleft = new Node(*other.left); newright = new Node(*other.right); } catch(...) { // If there was a problem // clean up any temporary objects. delete newleft; delete newright; // Then re-throw throw; } // Now perform the exception safe change of state. // None of these operations are allowed to throw. value = other.value; std::swap(left, newLeft); std::swap(right, newRight); // Now that the object is in a consistent state. // we can delete the old data. // Do this last (in other types where the data is not in // this can potentially throw). delete newLeft; delete newRight; return *this; } 0 si solo para consistencia.

También sugeriría lo siguiente para limpiar de todos modos:

  • Mover constantes a la cima.
  • Usa los valores de Node& Node::operator=(const Node& other) { Note* newleft = nullptr; Node* newright = nullptr; // Do the dangerous stuff in isolation. // without changing the chaging the current object. try { newleft = new Node(*other.left); newright = new Node(*other.right); } catch(...) { // If there was a problem // clean up any temporary objects. delete newleft; delete newright; // Then re-throw throw; } // Now perform the exception safe change of state. // None of these operations are allowed to throw. value = other.value; std::swap(left, newLeft); std::swap(right, newRight); // Now that the object is in a consistent state. // we can delete the old data. // Do this last (in other types where the data is not in // this can potentially throw). delete newLeft; delete newRight; return *this; } 1 en lugar de Node& Node::operator=(const Node& other) { Note* newleft = nullptr; Node* newright = nullptr; // Do the dangerous stuff in isolation. // without changing the chaging the current object. try { newleft = new Node(*other.left); newright = new Node(*other.right); } catch(...) { // If there was a problem // clean up any temporary objects. delete newleft; delete newright; // Then re-throw throw; } // Now perform the exception safe change of state. // None of these operations are allowed to throw. value = other.value; std::swap(left, newLeft); std::swap(right, newRight); // Now that the object is in a consistent state. // we can delete the old data. // Do this last (in other types where the data is not in // this can potentially throw). delete newLeft; delete newRight; return *this; } 2 para que No repita las llaves todo el tiempo, por lo que terminas con una constante Node& Node::operator=(const Node& other) { Note* newleft = nullptr; Node* newright = nullptr; // Do the dangerous stuff in isolation. // without changing the chaging the current object. try { newleft = new Node(*other.left); newright = new Node(*other.right); } catch(...) { // If there was a problem // clean up any temporary objects. delete newleft; delete newright; // Then re-throw throw; } // Now perform the exception safe change of state. // None of these operations are allowed to throw. value = other.value; std::swap(left, newLeft); std::swap(right, newRight); // Now that the object is in a consistent state. // we can delete the old data. // Do this last (in other types where the data is not in // this can potentially throw). delete newLeft; delete newRight; return *this; } 3 .
  • de esa manera también puede iterar sobre los tipos de eventos y los nombres de las tablas simultáneamente, eliminando la necesidad de buscar nombres de tablas en Node& Node::operator=(const Node& other) { Note* newleft = nullptr; Node* newright = nullptr; // Do the dangerous stuff in isolation. // without changing the chaging the current object. try { newleft = new Node(*other.left); newright = new Node(*other.right); } catch(...) { // If there was a problem // clean up any temporary objects. delete newleft; delete newright; // Then re-throw throw; } // Now perform the exception safe change of state. // None of these operations are allowed to throw. value = other.value; std::swap(left, newLeft); std::swap(right, newRight); // Now that the object is in a consistent state. // we can delete the old data. // Do this last (in other types where the data is not in // this can potentially throw). delete newLeft; delete newRight; return *this; } 4 .
  • Yo usaría Node& Node::operator=(const Node& other) { Note* newleft = nullptr; Node* newright = nullptr; // Do the dangerous stuff in isolation. // without changing the chaging the current object. try { newleft = new Node(*other.left); newright = new Node(*other.right); } catch(...) { // If there was a problem // clean up any temporary objects. delete newleft; delete newright; // Then re-throw throw; } // Now perform the exception safe change of state. // None of these operations are allowed to throw. value = other.value; std::swap(left, newLeft); std::swap(right, newRight); // Now that the object is in a consistent state. // we can delete the old data. // Do this last (in other types where the data is not in // this can potentially throw). delete newLeft; delete newRight; return *this; } 5 con los argumentos con nombre, por lo que es un poco más claro que Node& Node::operator=(const Node& other) { Note* newleft = nullptr; Node* newright = nullptr; // Do the dangerous stuff in isolation. // without changing the chaging the current object. try { newleft = new Node(*other.left); newright = new Node(*other.right); } catch(...) { // If there was a problem // clean up any temporary objects. delete newleft; delete newright; // Then re-throw throw; } // Now perform the exception safe change of state. // None of these operations are allowed to throw. value = other.value; std::swap(left, newLeft); std::swap(right, newRight); // Now that the object is in a consistent state. // we can delete the old data. // Do this last (in other types where the data is not in // this can potentially throw). delete newLeft; delete newRight; return *this; } 6 significa, I.E. Uso Node& Node::operator=(const Node& other) { Note* newleft = nullptr; Node* newright = nullptr; // Do the dangerous stuff in isolation. // without changing the chaging the current object. try { newleft = new Node(*other.left); newright = new Node(*other.right); } catch(...) { // If there was a problem // clean up any temporary objects. delete newleft; delete newright; // Then re-throw throw; } // Now perform the exception safe change of state. // None of these operations are allowed to throw. value = other.value; std::swap(left, newLeft); std::swap(right, newRight); // Now that the object is in a consistent state. // we can delete the old data. // Do this last (in other types where the data is not in // this can potentially throw). delete newLeft; delete newRight; return *this; } 7 en su lugar.
  • El valor de retorno adicional para Node& Node::operator=(const Node& other) { Note* newleft = nullptr; Node* newright = nullptr; // Do the dangerous stuff in isolation. // without changing the chaging the current object. try { newleft = new Node(*other.left); newright = new Node(*other.right); } catch(...) { // If there was a problem // clean up any temporary objects. delete newleft; delete newright; // Then re-throw throw; } // Now perform the exception safe change of state. // None of these operations are allowed to throw. value = other.value; std::swap(left, newLeft); std::swap(right, newRight); // Now that the object is in a consistent state. // we can delete the old data. // Do this last (in other types where the data is not in // this can potentially throw). delete newLeft; delete newRight; return *this; } 8 de Node& Node::operator=(const Node& other) { Note* newleft = nullptr; Node* newright = nullptr; // Do the dangerous stuff in isolation. // without changing the chaging the current object. try { newleft = new Node(*other.left); newright = new Node(*other.right); } catch(...) { // If there was a problem // clean up any temporary objects. delete newleft; delete newright; // Then re-throw throw; } // Now perform the exception safe change of state. // None of these operations are allowed to throw. value = other.value; std::swap(left, newLeft); std::swap(right, newRight); // Now that the object is in a consistent state. // we can delete the old data. // Do this last (in other types where the data is not in // this can potentially throw). delete newLeft; delete newRight; return *this; } 9 y Node& Node::operator=(Node other) // Pass by value to generate a copy. { other.swap(*this); // Swap the state of this and the // copy we created in `other` return *this; } // destructor of other now // does the tidy up. 0 no tiene mucho sentido para mí. No es como tú Transforme el nombre del evento, así que simplemente dejaría caer en conjunto.
  • El espurio Node& Node::operator=(Node other) // Pass by value to generate a copy. { other.swap(*this); // Swap the state of this and the // copy we created in `other` return *this; } // destructor of other now // does the tidy up. 1 Se puede reemplazar por Node& Node::operator=(Node other) // Pass by value to generate a copy. { other.swap(*this); // Swap the state of this and the // copy we created in `other` return *this; } // destructor of other now // does the tidy up. 2 Llamadas En su lugar, ¡pero esto se parece a las declaraciones de depuración de todos modos?
  • El manejo de excepciones en Node& Node::operator=(Node other) // Pass by value to generate a copy. { other.swap(*this); // Swap the state of this and the // copy we created in `other` return *this; } // destructor of other now // does the tidy up. 3 podría ser más claro; He movido el Acceso a través de Node& Node::operator=(Node other) // Pass by value to generate a copy. { other.swap(*this); // Swap the state of this and the // copy we created in `other` return *this; } // destructor of other now // does the tidy up. 4 Después del bloque Node& Node::operator=(Node other) // Pass by value to generate a copy. { other.swap(*this); // Swap the state of this and the // copy we created in `other` return *this; } // destructor of other now // does the tidy up. 5 para que sea más claro qué operación realmente puede fallar allí.
  • Las conexiones de la base de datos probablemente deberían estar protegidas por Node& Node::operator=(Node other) // Pass by value to generate a copy. { other.swap(*this); // Swap the state of this and the // copy we created in `other` return *this; } // destructor of other now // does the tidy up. 6 En caso de que.
  • Node& Node::operator=(Node other) // Pass by value to generate a copy. { other.swap(*this); // Swap the state of this and the // copy we created in `other` return *this; } // destructor of other now // does the tidy up. 7 en Node& Node::operator=(Node other) // Pass by value to generate a copy. { other.swap(*this); // Swap the state of this and the // copy we created in `other` return *this; } // destructor of other now // does the tidy up. 8 no está utilizado.
  • Los casos en Node& Node::operator=(Node other) // Pass by value to generate a copy. { other.swap(*this); // Swap the state of this and the // copy we created in `other` return *this; } // destructor of other now // does the tidy up. 9 son duplicados y pueden condensarse.
  • La comparación Node::~Node() { if (left != nullptr ) { delete left; } if (right != nullptr) { delete right; } } 0 no hace lo que quiere decir. Comparar Node::~Node() { if (left != nullptr ) { delete left; } if (right != nullptr) { delete right; } } 11 , que es Node::~Node() { if (left != nullptr ) { delete left; } if (right != nullptr) { delete right; } } 32 , con 99887776655443333 , que devuelve Node::~Node() { if (left != nullptr ) { delete left; } if (right != nullptr) { delete right; } } 4 . En cualquier caso, esta comparación puede ser reescrita. con Node::~Node() { if (left != nullptr ) { delete left; } if (right != nullptr) { delete right; } } 5 en su lugar. También te pierdes el (actualmente imposible) Node::~Node() { if (left != nullptr ) { delete left; } if (right != nullptr) { delete right; } } 6 Case; Dependiendo de su código, prefiero simplemente tener el valor predeterminado Caso y manejo Node::~Node() { if (left != nullptr ) { delete left; } if (right != nullptr) { delete right; } } 7 Adicionalmente o plantea una excepción usted mismo.
  • la línea después de Node::~Node() { if (left != nullptr ) { delete left; } if (right != nullptr) { delete right; } } 8 se ve pescado, pero yo No sé realmente cómo mejorarlo.

y, finalmente, siempre puedes consultar con Node::~Node() { if (left != nullptr ) { delete left; } if (right != nullptr) { delete right; } } 9 y herramientas similares para Violaciones de estilo. En total:

  Node::~Node() {     delete left;     delete right; } 0  
 

From a first look the code is nice enough, meaning you can follow the control flow easily and it's clear what each function does, so the separation of the three or four steps is rather good.

  1. This script is rather small and you don't pass around too much data; I'd say leave it as is unless you want to have some more reuse in other scripts.
  2. Yes please, do use __name__ if only for consistency.

I'd also suggest the following to clean up anyway:

  • Move constants to the top.
  • Use the values from table_names instead of event_types so you don't repeat the keys all the time, so you end up with a constant EVENT_TYPES = {'Video Played': ...}.
  • That way you can also iterate over the event types and table names simultaneously, eliminating the need to look up table names in send_to_db.
  • I'd use timedelta with named arguments, so it's a bit clearer what timedelta(1) means, i.e. use timedelta(days=1) instead.
  • The additional return value for event_name from get_data and data_cleanse doesn't make much sense to me. It's not like you transform the event name, so I'd just drop that altogether.
  • The spurious print statements could be replaced by logging calls instead, but this looks just like debugging statements anyway?
  • The exception handling in get_data could be clearer; I've moved the access via 'properties' after the try block to make it clearer which operation can actually fail there.
  • Database connections should probably be protected by with closing(...) just in case.
  • parameters in get_data is unused.
  • The cases in data_cleanse are duplicated and can be condensed.
  • The comparison foo == 'x' or 'y' doesn't do what you mean. Compare 'a' == 'x' or 'y', which is 'y', with 'a' == 'x' or 'a' == 'y', which returns False. In any case, this comparison can be rewritten with x in (...) instead. You also miss the (currently impossible) else case; depending on your code I'd rather just have the default case and handle "Video Played" additionally or raise an exception yourself.
  • The line after # remove admin users from data looks fishy, but I don't really know how to improve it.

And finally you can always check with flake8 and similar tools for style violations. All in all:

import pandas as pd import json from datetime import date, timedelta from mixpanel_client_lib import Mixpanel import sqlite3 as db from contextlib import closing   API_KEY = 'xxxxxxx' API_SECRET = 'xxxxxxx'  EVENT_TYPES = {     'Video Played': 'video_played',     'Item Information Click': 'item_info_click',     'Faved': 'faved',     'Add to Cart': 'add_to_cart',     'Tap to Replay': 'replay' }  DEFAULT_COLUMNS = [     ('$ios_ifa', 'ios_id'),     ('Groups', 'groups'),     ('Lifetime Number of Sessions', 'lifetime_sessions'),     ('Days Since Last Visit', 'days_since'),     ('time', 'time'),     ('Product ID', 'product_id'), ]  VIDEO_COLUMNS = list(DEFAULT_COLUMNS).extend([     ('Time Watched', 'time_watched'),     ('Video Length', 'video_length') ])   def get_data(start_date, end_date, event_name):     con_data = Mixpanel(API_KEY, API_SECRET)      data = con_data.request(['export'], {         'event': [event_name],         'from_date': start_date,         'to_date': end_date     })      events = []      for line in data.split('\n'):         try:             event = json.loads(line)         except ValueError:             continue          events.append(event['properties'])      return pd.DataFrame(events)   def data_cleanse(df, event_name):     columns = DEFAULT_COLUMNS     if event_name == "Video Played":         columns = VIDEO_COLUMNS      df = df[[c[0] for c in columns]]     df.columns = [c[1] for c in columns]      df['groups'] = df['groups'].astype(str)      # remove admin users from data     idx = df['groups'].isin(['[u\'Admin-Personal\']', '[u\'Admin\']'])     df = df[~idx]      # remove '0' lifetime session users from data     idx = df['lifetime_sessions'].isin([0])     df = df[~idx]      return df   def send_to_db(df, table_name):     with closing(db.connect('/code/vid_score/test.db')) as con:         df.to_sql(table_name, con, flavor='sqlite', if_exists='append')   def main():     end_date = date.today() - timedelta(days=1)     start_date = end_date      for (event_name, table_name) in EVENT_TYPES.iteritems():         df = get_data(start_date, end_date, event_name)         df = data_cleanse(df, event_name)         send_to_db(df, table_name)   if __name__ == "__main__":     main() 
 
 
 
 

Relacionados problema

7  La forma más rápida de escribir un archivo CSV grande en Python  ( Fastest way to write large csv file in python ) 
Soy bastante nuevo para Python y Pandas, pero tratando de mejorar con él para analizar y procesar archivos de datos grandes. Actualmente estoy trabajando en u...

4  Cuentos acumulativos de artículos en un marco de datos Panda  ( Cumulative counts of items in a pandas dataframe ) 
Estoy usando un conteo de datos lleno de encabezados / nombres de campo para desarrollar un esquema y necesito valores únicos para cada encabezado, pero cada ...

7  Salida de parcelas de dispersión [cerrada]  ( Outputting scatter plots ) 
cerrado. Esta pregunta es off-topic . Actualmente no está aceptando respuestas. ¿Quieres ...

2  Regresión en Pandas DataFrame  ( Regression on pandas dataframe ) 
Estoy trabajando en la siguiente tarea y estoy un poco perdido: construir un modelo de regresión que predecirá la puntuación de calificación de cada Prod...

5  Automatizar un conjunto A de informes semanales, incluidos los gráficos y la entrega de informes  ( Automating a set a of weekly reports including graphs and delivery of reports ) 
He estado escribiendo código para automatizar algunos informes semanales. Tuve Ayuda sobre el desbordamiento de la pila . Tengo código que funciona en su may...

0  Manipulando los cuadros de datos en Pandas  ( Manipulating dataframes on pandas ) 
Recientemente no pudo finalizar un código para una entrevista de trabajo. Uno de los problemas es que decidí usar Pandas (tenía sentido), pero no estaba famil...

2  K_nearest_neighbors desde cero [cerrado]  ( K nearest neighbors from scratch ) 
cerrado. Esta pregunta es off-topic . Actualmente no está aceptando respuestas. ¿Quieres ...

6  Valores coincidentes de la tabla HTML para actualizar los valores en Pandas DataFrame  ( Matching values from html table for updating values in pandas dataframe ) 
Esto es más un ejercicio para que me utilice a Pandas y sus cuadros de datos. Para aquellos que no escucharon de él: Panda es un paquete de Python que prop...

8  Python CSV a XML Converter  ( Python csv to xml converter ) 
Estoy creando una aplicación que se lee en los datos de un archivo CSV y crea un archivo XML usando LXML. El siguiente código funciona como se esperaba. Sin e...

10  Tkinter GUI por hacer ediciones muy simples a Pandas DataFrames  ( Tkinter gui for making very simple edits to pandas dataframes ) 
Es parte de una aplicación separada que permite a los usuarios interactuar muy libremente con diferentes bases de datos y verificar los posibles errores y rea...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos