J'ai regardé une vidéo de conférence Python par Keith Galli, un youtubeur étranger, et j'ai essayé le travail.
Résolvons de vrais problèmes de science des données en utilisant la bibliothèque Pandas de Python! ] Solving real world data science tasks with Python Pandas! Le niveau de difficulté n'est pas élevé et c'est un anglais simple, alors jetez un œil.
Il s'agit d'une vidéo d'une heure et demie environ. C'est une explication très polie. Chez stackoverflow (site de questions-réponses sur la programmation de la version étrangère) sur Google Il montre également le processus de recherche d'une solution.
C'est une tâche à analyser à l'aide de données CSV Excel. Les données peuvent être téléchargées depuis son Github.
Je cours sur un notebook jupyter.
Je le fais en ajoutant des suppléments au code en japonais.
Si vous regardez la vidéo et que vous la touchez, je pense que c'est la meilleure façon de pratiquer les pandas.
Vous pouvez avoir une idée de l'atmosphère en lisant simplement cet article.
Chargez la bibliothèque pandas, os
import pandas as pd
import os
Tout d'abord, vérifiez quel type de données est inclus (obtenez la liste des noms de fichiers)
files = [file for file in os.listdir("Sales_Data")]
for file in files:
print(file)
Sales_April_2019.csv
Sales_August_2019.csv
Sales_December_2019.csv
Sales_February_2019.csv
Sales_January_2019.csv
Sales_July_2019.csv
Sales_June_2019.csv
Sales_March_2019.csv
Sales_May_2019.csv
Sales_November_2019.csv
Sales_October_2019.csv
Sales_September_2019.csv
Il semble que les données du nom du fichier à janvier-décembre 2019 soient incluses, je souhaite combiner les données pour analyse
Tout d'abord, créez un bloc de données vide pour stocker toutes les données
all_months_data = pd.DataFrame()
Afin de combiner toutes les données du mois, nous placerons le fichier csv de chaque mois dans le bloc de données vide l'un après l'autre.
for file in files:
df = pd.read_csv("Sales_Data/" + file)
all_months_data = pd.concat([all_months_data,df])
Eh bien, les 5 premières lignes de données ressemblent à ceci
all_months_data.head()
Order ID | Product | Quantity Ordered | Price Each | Order Date | Purchase Address | |
---|---|---|---|---|---|---|
0 | 176558 | USB-C Charging Cable | 2 | 11.95 | 04/19/19 08:46 | 917 1st St, Dallas, TX 75001 |
1 | NaN | NaN | NaN | NaN | NaN | NaN |
2 | 176559 | Bose SoundSport Headphones | 1 | 99.99 | 04/07/19 22:30 | 682 Chestnut St, Boston, MA 02215 |
3 | 176560 | Google Phone | 1 | 600 | 04/12/19 14:38 | 669 Spruce St, Los Angeles, CA 90001 |
4 | 176560 | Wired Headphones | 1 | 11.99 | 04/12/19 14:38 | 669 Spruce St, Los Angeles, CA 90001 |
Sortie des données combinées (À ce stade, puisque le numéro de série n'est pas requis, ajoutez index = False à l'argument)
all_months_data.to_csv("all_data.csv",index=False)
Après avoir confirmé les données de sortie, essayez à nouveau de lire les données combinées.
all_data = pd.read_csv("all_data.csv")
all_data.head()
Order ID | Product | Quantity Ordered | Price Each | Order Date | Purchase Address | |
---|---|---|---|---|---|---|
0 | 176558 | USB-C Charging Cable | 2 | 11.95 | 04/19/19 08:46 | 917 1st St, Dallas, TX 75001 |
1 | NaN | NaN | NaN | NaN | NaN | NaN |
2 | 176559 | Bose SoundSport Headphones | 1 | 99.99 | 04/07/19 22:30 | 682 Chestnut St, Boston, MA 02215 |
3 | 176560 | Google Phone | 1 | 600 | 04/12/19 14:38 | 669 Spruce St, Los Angeles, CA 90001 |
4 | 176560 | Wired Headphones | 1 | 11.99 | 04/12/19 14:38 | 669 Spruce St, Los Angeles, CA 90001 |
En regardant la colonne, il y a une colonne Date de commande = date de commande, mais il n'y a pas de données uniquement pour le mois, alors créons-en une nouvelle
Les deux premiers caractères de la colonne de date de commande sont probablement les données du mois
all_data['Month'] = all_data['Order Date'].str[0:2]
Puisqu'il a été converti en chaîne de caractères, retournons-le à nouveau à la valeur numérique
all_data['Month'] = all_data['Month'].astype('int32')
all_data.head()
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-77-ffc394ccb2ad> in <module>
----> 1 all_data['Month'] = all_data['Month'].astype('int32')
2 all_data.head()
/opt/anaconda3/lib/python3.7/site-packages/pandas/core/generic.py in astype(self, dtype, copy, errors, **kwargs)
5880 # else, only a single dtype is given
5881 new_data = self._data.astype(
-> 5882 dtype=dtype, copy=copy, errors=errors, **kwargs
5883 )
5884 return self._constructor(new_data).__finalize__(self)
/opt/anaconda3/lib/python3.7/site-packages/pandas/core/internals/managers.py in astype(self, dtype, **kwargs)
579
580 def astype(self, dtype, **kwargs):
--> 581 return self.apply("astype", dtype=dtype, **kwargs)
582
583 def convert(self, **kwargs):
/opt/anaconda3/lib/python3.7/site-packages/pandas/core/internals/managers.py in apply(self, f, axes, filter, do_integrity_check, consolidate, **kwargs)
436 kwargs[k] = obj.reindex(b_items, axis=axis, copy=align_copy)
437
--> 438 applied = getattr(b, f)(**kwargs)
439 result_blocks = _extend_blocks(applied, result_blocks)
440
/opt/anaconda3/lib/python3.7/site-packages/pandas/core/internals/blocks.py in astype(self, dtype, copy, errors, values, **kwargs)
557
558 def astype(self, dtype, copy=False, errors="raise", values=None, **kwargs):
--> 559 return self._astype(dtype, copy=copy, errors=errors, values=values, **kwargs)
560
561 def _astype(self, dtype, copy=False, errors="raise", values=None, **kwargs):
/opt/anaconda3/lib/python3.7/site-packages/pandas/core/internals/blocks.py in _astype(self, dtype, copy, errors, values, **kwargs)
641 # _astype_nansafe works fine with 1-d only
642 vals1d = values.ravel()
--> 643 values = astype_nansafe(vals1d, dtype, copy=True, **kwargs)
644
645 # TODO(extension)
/opt/anaconda3/lib/python3.7/site-packages/pandas/core/dtypes/cast.py in astype_nansafe(arr, dtype, copy, skipna)
705 # work around NumPy brokenness, #1987
706 if np.issubdtype(dtype.type, np.integer):
--> 707 return lib.astype_intsafe(arr.ravel(), dtype).reshape(arr.shape)
708
709 # if we have a datetime/timedelta array of objects
pandas/_libs/lib.pyx in pandas._libs.lib.astype_intsafe()
ValueError: cannot convert float NaN to integer
J'ai une erreur
Quand je lis la déclaration d'erreur, il dit que NaN ne peut pas être quantifié.
La combinaison de is_na et de toutes les fonctions renverra True s'il y a au moins un NaN.
axis = 1 est une fonction qui retourne le traitement ligne par ligne
Demandez-leur de renvoyer toutes les lignes contenant NaN
nan_df = all_data[all_data.isna().any(axis=1)]
nan_df
Order ID | Product | Quantity Ordered | Price Each | Order Date | Purchase Address | Month | |
---|---|---|---|---|---|---|---|
1 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
356 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
735 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1433 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1553 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
... | ... | ... | ... | ... | ... | ... | ... |
185176 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
185438 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
186042 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
186548 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
186826 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
545 rows × 7 columns
Il y avait aussi 545 lignes
Effacer les données contenant NaN
all_data = all_data.dropna(how='all')
all_data.head()
Order ID | Product | Quantity Ordered | Price Each | Order Date | Purchase Address | Month | |
---|---|---|---|---|---|---|---|
0 | 176558 | USB-C Charging Cable | 2 | 11.95 | 04/19/19 08:46 | 917 1st St, Dallas, TX 75001 | 04 |
2 | 176559 | Bose SoundSport Headphones | 1 | 99.99 | 04/07/19 22:30 | 682 Chestnut St, Boston, MA 02215 | 04 |
3 | 176560 | Google Phone | 1 | 600 | 04/12/19 14:38 | 669 Spruce St, Los Angeles, CA 90001 | 04 |
4 | 176560 | Wired Headphones | 1 | 11.99 | 04/12/19 14:38 | 669 Spruce St, Los Angeles, CA 90001 | 04 |
5 | 176561 | Wired Headphones | 1 | 11.99 | 04/30/19 09:27 | 333 8th St, Los Angeles, CA 90001 | 04 |
Très bien, revenons au mois précédent et réessayons
all_data['Month'] = all_data['Month'].astype('int32')
all_data.head()
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-80-ffc394ccb2ad> in <module>
----> 1 all_data['Month'] = all_data['Month'].astype('int32')
2 all_data.head()
/opt/anaconda3/lib/python3.7/site-packages/pandas/core/generic.py in astype(self, dtype, copy, errors, **kwargs)
5880 # else, only a single dtype is given
5881 new_data = self._data.astype(
-> 5882 dtype=dtype, copy=copy, errors=errors, **kwargs
5883 )
5884 return self._constructor(new_data).__finalize__(self)
/opt/anaconda3/lib/python3.7/site-packages/pandas/core/internals/managers.py in astype(self, dtype, **kwargs)
579
580 def astype(self, dtype, **kwargs):
--> 581 return self.apply("astype", dtype=dtype, **kwargs)
582
583 def convert(self, **kwargs):
/opt/anaconda3/lib/python3.7/site-packages/pandas/core/internals/managers.py in apply(self, f, axes, filter, do_integrity_check, consolidate, **kwargs)
436 kwargs[k] = obj.reindex(b_items, axis=axis, copy=align_copy)
437
--> 438 applied = getattr(b, f)(**kwargs)
439 result_blocks = _extend_blocks(applied, result_blocks)
440
/opt/anaconda3/lib/python3.7/site-packages/pandas/core/internals/blocks.py in astype(self, dtype, copy, errors, values, **kwargs)
557
558 def astype(self, dtype, copy=False, errors="raise", values=None, **kwargs):
--> 559 return self._astype(dtype, copy=copy, errors=errors, values=values, **kwargs)
560
561 def _astype(self, dtype, copy=False, errors="raise", values=None, **kwargs):
/opt/anaconda3/lib/python3.7/site-packages/pandas/core/internals/blocks.py in _astype(self, dtype, copy, errors, values, **kwargs)
641 # _astype_nansafe works fine with 1-d only
642 vals1d = values.ravel()
--> 643 values = astype_nansafe(vals1d, dtype, copy=True, **kwargs)
644
645 # TODO(extension)
/opt/anaconda3/lib/python3.7/site-packages/pandas/core/dtypes/cast.py in astype_nansafe(arr, dtype, copy, skipna)
705 # work around NumPy brokenness, #1987
706 if np.issubdtype(dtype.type, np.integer):
--> 707 return lib.astype_intsafe(arr.ravel(), dtype).reshape(arr.shape)
708
709 # if we have a datetime/timedelta array of objects
pandas/_libs/lib.pyx in pandas._libs.lib.astype_intsafe()
ValueError: invalid literal for int() with base 10: 'Or'
Ensuite, je reçois à nouveau une nouvelle erreur
Il semble que le mot «Ou» était inclus
Regardons la ligne qui contient "Ou"
temp_df = all_data[all_data['Order Date'].str[0:2] == "Or"]
temp_df.head()
Order ID | Product | Quantity Ordered | Price Each | Order Date | Purchase Address | Month | |
---|---|---|---|---|---|---|---|
519 | Order ID | Product | Quantity Ordered | Price Each | Order Date | Purchase Address | Or |
1149 | Order ID | Product | Quantity Ordered | Price Each | Order Date | Purchase Address | Or |
1155 | Order ID | Product | Quantity Ordered | Price Each | Order Date | Purchase Address | Or |
2878 | Order ID | Product | Quantity Ordered | Price Each | Order Date | Purchase Address | Or |
2893 | Order ID | Product | Quantity Ordered | Price Each | Order Date | Purchase Address | Or |
Il semble que l'identité de "Ou" était "Date de commande".
Rafraîchissons les données en extrayant les données autres que les données contenant le mot "Date de commande"
all_data = all_data[all_data['Order Date'].str[0:2] != "Or"]
all_data.head()
Order ID | Product | Quantity Ordered | Price Each | Order Date | Purchase Address | Month | |
---|---|---|---|---|---|---|---|
0 | 176558 | USB-C Charging Cable | 2 | 11.95 | 04/19/19 08:46 | 917 1st St, Dallas, TX 75001 | 04 |
2 | 176559 | Bose SoundSport Headphones | 1 | 99.99 | 04/07/19 22:30 | 682 Chestnut St, Boston, MA 02215 | 04 |
3 | 176560 | Google Phone | 1 | 600 | 04/12/19 14:38 | 669 Spruce St, Los Angeles, CA 90001 | 04 |
4 | 176560 | Wired Headphones | 1 | 11.99 | 04/12/19 14:38 | 669 Spruce St, Los Angeles, CA 90001 | 04 |
5 | 176561 | Wired Headphones | 1 | 11.99 | 04/30/19 09:27 | 333 8th St, Los Angeles, CA 90001 | 04 |
Soyons honnêtes pour la troisième fois et effectuons une quantification
all_data['Month'] = all_data['Order Date'].str[0:2]
all_data['Month'] = all_data['Month'].astype('int32')
all_data.head()
Order ID | Product | Quantity Ordered | Price Each | Order Date | Purchase Address | Month | |
---|---|---|---|---|---|---|---|
0 | 176558 | USB-C Charging Cable | 2 | 11.95 | 04/19/19 08:46 | 917 1st St, Dallas, TX 75001 | 4 |
2 | 176559 | Bose SoundSport Headphones | 1 | 99.99 | 04/07/19 22:30 | 682 Chestnut St, Boston, MA 02215 | 4 |
3 | 176560 | Google Phone | 1 | 600 | 04/12/19 14:38 | 669 Spruce St, Los Angeles, CA 90001 | 4 |
4 | 176560 | Wired Headphones | 1 | 11.99 | 04/12/19 14:38 | 669 Spruce St, Los Angeles, CA 90001 | 4 |
5 | 176561 | Wired Headphones | 1 | 11.99 | 04/30/19 09:27 | 333 8th St, Los Angeles, CA 90001 | 4 |
J? ai compris
Ensuite, bien qu'il y ait Quantité commandée et Prix chacun, il n'y a pas de ventes essentielles.
Puisque PQ (ventes) = P (prix) x Q (quantité), ajoutez une colonne qui correspond à PQ.
all_data['Sales'] = all_data['Quantity Ordered'] * all_data['Price Each']
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
/opt/anaconda3/lib/python3.7/site-packages/pandas/core/ops/__init__.py in na_op(x, y)
967 try:
--> 968 result = expressions.evaluate(op, str_rep, x, y, **eval_kwargs)
969 except TypeError:
/opt/anaconda3/lib/python3.7/site-packages/pandas/core/computation/expressions.py in evaluate(op, op_str, a, b, use_numexpr, **eval_kwargs)
220 if use_numexpr:
--> 221 return _evaluate(op, op_str, a, b, **eval_kwargs)
222 return _evaluate_standard(op, op_str, a, b)
/opt/anaconda3/lib/python3.7/site-packages/pandas/core/computation/expressions.py in _evaluate_numexpr(op, op_str, a, b, truediv, reversed, **eval_kwargs)
126 if result is None:
--> 127 result = _evaluate_standard(op, op_str, a, b)
128
/opt/anaconda3/lib/python3.7/site-packages/pandas/core/computation/expressions.py in _evaluate_standard(op, op_str, a, b, **eval_kwargs)
69 with np.errstate(all="ignore"):
---> 70 return op(a, b)
71
TypeError: can't multiply sequence by non-int of type 'str'
During handling of the above exception, another exception occurred:
TypeError Traceback (most recent call last)
<ipython-input-84-7c1e2b69cbe2> in <module>
----> 1 all_data['Sales'] = all_data['Quantity Ordered'] * all_data['Price Each']
/opt/anaconda3/lib/python3.7/site-packages/pandas/core/ops/__init__.py in wrapper(left, right)
1046
1047 with np.errstate(all="ignore"):
-> 1048 result = na_op(lvalues, rvalues)
1049 return construct_result(
1050 left, result, index=left.index, name=res_name, dtype=None
/opt/anaconda3/lib/python3.7/site-packages/pandas/core/ops/__init__.py in na_op(x, y)
968 result = expressions.evaluate(op, str_rep, x, y, **eval_kwargs)
969 except TypeError:
--> 970 result = masked_arith_op(x, y, op)
971
972 return missing.dispatch_fill_zeros(op, x, y, result)
/opt/anaconda3/lib/python3.7/site-packages/pandas/core/ops/__init__.py in masked_arith_op(x, y, op)
445 if mask.any():
446 with np.errstate(all="ignore"):
--> 447 result[mask] = op(xrav[mask], com.values_from_object(yrav[mask]))
448
449 else:
TypeError: can't multiply sequence by non-int of type 'str'
Encore une fois, il contenait une chaîne
Je veux le réécrire sous une forme qui peut être calculée pour le moment, donc j'utiliserai la fonction "to_numeric"
all_data['Quantity Ordered'] = pd.to_numeric(all_data['Quantity Ordered'])
all_data['Price Each'] = pd.to_numeric(all_data['Price Each'])
Je vais essayer à nouveau
all_data['Sales'] = all_data['Quantity Ordered'] * all_data['Price Each']
all_data.head()
Order ID | Product | Quantity Ordered | Price Each | Order Date | Purchase Address | Month | Sales | |
---|---|---|---|---|---|---|---|---|
0 | 176558 | USB-C Charging Cable | 2 | 11.95 | 04/19/19 08:46 | 917 1st St, Dallas, TX 75001 | 4 | 23.90 |
2 | 176559 | Bose SoundSport Headphones | 1 | 99.99 | 04/07/19 22:30 | 682 Chestnut St, Boston, MA 02215 | 4 | 99.99 |
3 | 176560 | Google Phone | 1 | 600.00 | 04/12/19 14:38 | 669 Spruce St, Los Angeles, CA 90001 | 4 | 600.00 |
4 | 176560 | Wired Headphones | 1 | 11.99 | 04/12/19 14:38 | 669 Spruce St, Los Angeles, CA 90001 | 4 | 11.99 |
5 | 176561 | Wired Headphones | 1 | 11.99 | 04/30/19 09:27 | 333 8th St, Los Angeles, CA 90001 | 4 | 11.99 |
C'est sorti. Il semble que la réponse à la question sortira enfin
Pour le moment, je republierai la question.
all_data.groupby('Month').sum()
Quantity Ordered | Price Each | Sales | |
---|---|---|---|
Month | |||
1 | 10903 | 1.811768e+06 | 1.822257e+06 |
2 | 13449 | 2.188885e+06 | 2.202022e+06 |
3 | 17005 | 2.791208e+06 | 2.807100e+06 |
4 | 20558 | 3.367671e+06 | 3.390670e+06 |
5 | 18667 | 3.135125e+06 | 3.152607e+06 |
6 | 15253 | 2.562026e+06 | 2.577802e+06 |
7 | 16072 | 2.632540e+06 | 2.647776e+06 |
8 | 13448 | 2.230345e+06 | 2.244468e+06 |
9 | 13109 | 2.084992e+06 | 2.097560e+06 |
10 | 22703 | 3.715555e+06 | 3.736727e+06 |
11 | 19798 | 3.180601e+06 | 3.199603e+06 |
12 | 28114 | 4.588415e+06 | 4.613443e+06 |
Je ne connais pas Pat, alors montrons-le
Installez la bibliothèque pour illustration
import matplotlib.pyplot as plt
Graphique tout en décidant de la plage de l'axe X
months = range(1,13)
results = all_data.groupby('Month').sum()
plt.bar(months,results['Sales'])
plt.xticks(months)
plt.xlabel('Month')
plt.ylabel('Sales')
plt.show()
C'était le travail 1.
Maintenant que nous avons une ligne de vente, le travail semble facile, mais faisons-le
Avant cela, revoyons à quoi ressemblaient les données.
all_data.head()
Order ID | Product | Quantity Ordered | Price Each | Order Date | Purchase Address | Month | Sales | |
---|---|---|---|---|---|---|---|---|
0 | 176558 | USB-C Charging Cable | 2 | 11.95 | 04/19/19 08:46 | 917 1st St, Dallas, TX 75001 | 4 | 23.90 |
2 | 176559 | Bose SoundSport Headphones | 1 | 99.99 | 04/07/19 22:30 | 682 Chestnut St, Boston, MA 02215 | 4 | 99.99 |
3 | 176560 | Google Phone | 1 | 600.00 | 04/12/19 14:38 | 669 Spruce St, Los Angeles, CA 90001 | 4 | 600.00 |
4 | 176560 | Wired Headphones | 1 | 11.99 | 04/12/19 14:38 | 669 Spruce St, Los Angeles, CA 90001 | 4 | 11.99 |
5 | 176561 | Wired Headphones | 1 | 11.99 | 04/30/19 09:27 | 333 8th St, Los Angeles, CA 90001 | 4 | 11.99 |
C'est comme extraire une partie des données dans la partie Adresse d'achat et la totaliser.
Créons une colonne City comme nous l'avons fait dans Sales
Je dois extraire une partie d'Adresse, mais quand je regarde les données d'Adress, je veux extraire uniquement le deuxième nom de ville comme "adresse, nom de ville, code postal".
Utilisez la fonction Apply pour fractionner par "," dans la fonction de fractionnement et appliquez-la à toutes les colonnes de la même colonne
all_data['City'] = all_data['Purchase Address'].apply(lambda x: x.split(',')[1])
all_data.head()
Order ID | Product | Quantity Ordered | Price Each | Order Date | Purchase Address | Month | Sales | City | |
---|---|---|---|---|---|---|---|---|---|
0 | 176558 | USB-C Charging Cable | 2 | 11.95 | 04/19/19 08:46 | 917 1st St, Dallas, TX 75001 | 4 | 23.90 | Dallas |
2 | 176559 | Bose SoundSport Headphones | 1 | 99.99 | 04/07/19 22:30 | 682 Chestnut St, Boston, MA 02215 | 4 | 99.99 | Boston |
3 | 176560 | Google Phone | 1 | 600.00 | 04/12/19 14:38 | 669 Spruce St, Los Angeles, CA 90001 | 4 | 600.00 | Los Angeles |
4 | 176560 | Wired Headphones | 1 | 11.99 | 04/12/19 14:38 | 669 Spruce St, Los Angeles, CA 90001 | 4 | 11.99 | Los Angeles |
5 | 176561 | Wired Headphones | 1 | 11.99 | 04/30/19 09:27 | 333 8th St, Los Angeles, CA 90001 | 4 | 11.99 | Los Angeles |
Seule la ville a été divisée avec succès!
À propos, il y a un problème qui doit être pris en compte ici lors du total de City.
C'est le cas où City a le même nom mais d'autres pays ont le même nom. Si cela n'est pas pris en compte, ils seront additionnés et des résultats d'agrégation involontaires seront obtenus. (Exemple: Portlands dans l'Oregon et le Maine)
Cependant, il n'est pas nécessaire de créer une nouvelle colonne pour le nom du pays. Il vous suffit de mettre l'état (2 caractères) dans la cellule de la colonne Ville car il s'agrège uniquement. Cette fois, ce sera sous la forme de Ville (État). ex: Dallas (TX)
Plus tôt, je l'ai écrit en une seule ligne avec la fonction lambda, mais comme c'est un gros problème, créons une fonction pour obtenir respectivement le nom de la ville et le nom du pays. Il est également gentil avec le lecteur.
def get_city(address):
return address.split(',')[1]
def get_state(address):
return address.split(',')[2].split(' ')[1]
#Les données d'adresse d'achat sont des virgules(,)Vide après(" ")Parce qu'il y a, couper avec fente pour qu'il ne devienne pas artificiel une fois uni
all_data['City'] = all_data['Purchase Address'].apply(lambda x: f"{get_city(x)} ({get_state(x)})")
all_data.drop("State",axis=1)
Order ID | Product | Quantity Ordered | Price Each | Order Date | Purchase Address | Month | Sales | City | |
---|---|---|---|---|---|---|---|---|---|
0 | 176558 | USB-C Charging Cable | 2 | 11.95 | 04/19/19 08:46 | 917 1st St, Dallas, TX 75001 | 4 | 23.90 | Dallas (TX) |
2 | 176559 | Bose SoundSport Headphones | 1 | 99.99 | 04/07/19 22:30 | 682 Chestnut St, Boston, MA 02215 | 4 | 99.99 | Boston (MA) |
3 | 176560 | Google Phone | 1 | 600.00 | 04/12/19 14:38 | 669 Spruce St, Los Angeles, CA 90001 | 4 | 600.00 | Los Angeles (CA) |
4 | 176560 | Wired Headphones | 1 | 11.99 | 04/12/19 14:38 | 669 Spruce St, Los Angeles, CA 90001 | 4 | 11.99 | Los Angeles (CA) |
5 | 176561 | Wired Headphones | 1 | 11.99 | 04/30/19 09:27 | 333 8th St, Los Angeles, CA 90001 | 4 | 11.99 | Los Angeles (CA) |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
186845 | 259353 | AAA Batteries (4-pack) | 3 | 2.99 | 09/17/19 20:56 | 840 Highland St, Los Angeles, CA 90001 | 9 | 8.97 | Los Angeles (CA) |
186846 | 259354 | iPhone | 1 | 700.00 | 09/01/19 16:00 | 216 Dogwood St, San Francisco, CA 94016 | 9 | 700.00 | San Francisco (CA) |
186847 | 259355 | iPhone | 1 | 700.00 | 09/23/19 07:39 | 220 12th St, San Francisco, CA 94016 | 9 | 700.00 | San Francisco (CA) |
186848 | 259356 | 34in Ultrawide Monitor | 1 | 379.99 | 09/19/19 17:30 | 511 Forest St, San Francisco, CA 94016 | 9 | 379.99 | San Francisco (CA) |
186849 | 259357 | USB-C Charging Cable | 1 | 11.95 | 09/30/19 00:18 | 250 Meadow St, San Francisco, CA 94016 | 9 | 11.95 | San Francisco (CA) |
185950 rows × 9 columns
C'est bon, tout ce que vous avez à faire est de faire la somme normalement
all_data.groupby('City').sum()
Quantity Ordered | Price Each | Month | Sales | |
---|---|---|---|---|
City | ||||
Atlanta (GA) | 16602 | 2.779908e+06 | 104794 | 2.795499e+06 |
Austin (TX) | 11153 | 1.809874e+06 | 69829 | 1.819582e+06 |
Boston (MA) | 22528 | 3.637410e+06 | 141112 | 3.661642e+06 |
Dallas (TX) | 16730 | 2.752628e+06 | 104620 | 2.767975e+06 |
Los Angeles (CA) | 33289 | 5.421435e+06 | 208325 | 5.452571e+06 |
New York City (NY) | 27932 | 4.635371e+06 | 175741 | 4.664317e+06 |
Portland (ME) | 2750 | 4.471893e+05 | 17144 | 4.497583e+05 |
Portland (OR) | 11303 | 1.860558e+06 | 70621 | 1.870732e+06 |
San Francisco (CA) | 50239 | 8.211462e+06 | 315520 | 8.262204e+06 |
Seattle (WA) | 16553 | 2.733296e+06 | 104941 | 2.747755e+06 |
San Francisco est le numéro un. En outre, vous pouvez voir que Portland est également correctement divisée.
Organisez le code utilisé le mois précédent
results = all_data.groupby('City').sum()
cities = [city for city, df in all_data.groupby('City')]
#Ville pour les étiquettes de l'axe des x: les nombres et les étiquettes seront disjoints à moins qu'ils ne soient dans le même ordre que lorsqu'ils sont rainurés ci-dessus.
plt.bar(cities,results['Sales'])
plt.xticks(cities,rotation="vertical")
#Si les villes sont affichées telles quelles, elles seront encombrantes, alors affichez-les verticalement.
plt.ylabel('Sales')
plt.xlabel('City name')
plt.show()
C'est fait!
Le travail est devenu comme la science des données à la fois (cependant, la conclusion n'est pas si logique d'abord)
Maintenant, comme d'habitude, revenons sur les données
all_data.head()
Order ID | Product | Quantity Ordered | Price Each | Order Date | Purchase Address | Month | Sales | City | State | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 176558 | USB-C Charging Cable | 2 | 11.95 | 04/19/19 08:46 | 917 1st St, Dallas, TX 75001 | 4 | 23.90 | Dallas (TX) | TX 75001 |
2 | 176559 | Bose SoundSport Headphones | 1 | 99.99 | 04/07/19 22:30 | 682 Chestnut St, Boston, MA 02215 | 4 | 99.99 | Boston (MA) | MA 02215 |
3 | 176560 | Google Phone | 1 | 600.00 | 04/12/19 14:38 | 669 Spruce St, Los Angeles, CA 90001 | 4 | 600.00 | Los Angeles (CA) | CA 90001 |
4 | 176560 | Wired Headphones | 1 | 11.99 | 04/12/19 14:38 | 669 Spruce St, Los Angeles, CA 90001 | 4 | 11.99 | Los Angeles (CA) | CA 90001 |
5 | 176561 | Wired Headphones | 1 | 11.99 | 04/30/19 09:27 | 333 8th St, Los Angeles, CA 90001 | 4 | 11.99 | Los Angeles (CA) | CA 90001 |
Il serait peut-être intéressant d'examiner la relation entre la colonne Données de la commande et la colonne Ventes.
Modifions le type de données afin que la date de commande puisse être facilement traitée comme des données de date.
all_data['Order Date'] = pd.to_datetime(all_data['Order Date'])
all_data.head()
Order ID | Product | Quantity Ordered | Price Each | Order Date | Purchase Address | Month | Sales | City | State | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 176558 | USB-C Charging Cable | 2 | 11.95 | 2019-04-19 08:46:00 | 917 1st St, Dallas, TX 75001 | 4 | 23.90 | Dallas (TX) | TX 75001 |
2 | 176559 | Bose SoundSport Headphones | 1 | 99.99 | 2019-04-07 22:30:00 | 682 Chestnut St, Boston, MA 02215 | 4 | 99.99 | Boston (MA) | MA 02215 |
3 | 176560 | Google Phone | 1 | 600.00 | 2019-04-12 14:38:00 | 669 Spruce St, Los Angeles, CA 90001 | 4 | 600.00 | Los Angeles (CA) | CA 90001 |
4 | 176560 | Wired Headphones | 1 | 11.99 | 2019-04-12 14:38:00 | 669 Spruce St, Los Angeles, CA 90001 | 4 | 11.99 | Los Angeles (CA) | CA 90001 |
5 | 176561 | Wired Headphones | 1 | 11.99 | 2019-04-30 09:27:00 | 333 8th St, Los Angeles, CA 90001 | 4 | 11.99 | Los Angeles (CA) | CA 90001 |
Le format des données a changé
Faisons une ligne d'heure, minute
Quand j'ai créé une colonne dans Month ou Sales, c'était une chaîne de caractères, j'ai donc utilisé Split etc., mais grâce à la modification du type de données plus tôt
all_data['Hour'] = all_data['Order Date'].dt.hour
all_data['Minute'] = all_data['Order Date'].dt.minute
all_data.head()
Order ID | Product | Quantity Ordered | Price Each | Order Date | Purchase Address | Month | Sales | City | State | Hour | Minute | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 176558 | USB-C Charging Cable | 2 | 11.95 | 2019-04-19 08:46:00 | 917 1st St, Dallas, TX 75001 | 4 | 23.90 | Dallas (TX) | TX 75001 | 8 | 46 |
2 | 176559 | Bose SoundSport Headphones | 1 | 99.99 | 2019-04-07 22:30:00 | 682 Chestnut St, Boston, MA 02215 | 4 | 99.99 | Boston (MA) | MA 02215 | 22 | 30 |
3 | 176560 | Google Phone | 1 | 600.00 | 2019-04-12 14:38:00 | 669 Spruce St, Los Angeles, CA 90001 | 4 | 600.00 | Los Angeles (CA) | CA 90001 | 14 | 38 |
4 | 176560 | Wired Headphones | 1 | 11.99 | 2019-04-12 14:38:00 | 669 Spruce St, Los Angeles, CA 90001 | 4 | 11.99 | Los Angeles (CA) | CA 90001 | 14 | 38 |
5 | 176561 | Wired Headphones | 1 | 11.99 | 2019-04-30 09:27:00 | 333 8th St, Los Angeles, CA 90001 | 4 | 11.99 | Los Angeles (CA) | CA 90001 | 9 | 27 |
Visualisons une fois pour saisir les données
hours = [hour for hour, df in all_data.groupby('Hour')]
plt.plot(hours,all_data.groupby(['Hour']).count())
#Nombre de commandes par heure avec le temps sur l'axe X(Nombre de lignes)Agrégat
plt.xticks(hours)
plt.grid()
#Je veux voir une tendance claire pour chaque heure autant que possible, donc je vais ajouter une grille
plt.xlabel('Hour')
plt.ylabel('Orders')
plt.show()
Le pic est vers AM: 11 et PM: 7. Par conséquent, il semble bon d'afficher des publicités pendant cette période où le nombre de commandes (clients) est le plus élevé.
all_data.head()
Order ID | Product | Quantity Ordered | Price Each | Order Date | Purchase Address | Month | Sales | City | State | Hour | Minute | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 176558 | USB-C Charging Cable | 2 | 11.95 | 2019-04-19 08:46:00 | 917 1st St, Dallas, TX 75001 | 4 | 23.90 | Dallas (TX) | TX 75001 | 8 | 46 |
2 | 176559 | Bose SoundSport Headphones | 1 | 99.99 | 2019-04-07 22:30:00 | 682 Chestnut St, Boston, MA 02215 | 4 | 99.99 | Boston (MA) | MA 02215 | 22 | 30 |
3 | 176560 | Google Phone | 1 | 600.00 | 2019-04-12 14:38:00 | 669 Spruce St, Los Angeles, CA 90001 | 4 | 600.00 | Los Angeles (CA) | CA 90001 | 14 | 38 |
4 | 176560 | Wired Headphones | 1 | 11.99 | 2019-04-12 14:38:00 | 669 Spruce St, Los Angeles, CA 90001 | 4 | 11.99 | Los Angeles (CA) | CA 90001 | 14 | 38 |
5 | 176561 | Wired Headphones | 1 | 11.99 | 2019-04-30 09:27:00 | 333 8th St, Los Angeles, CA 90001 | 4 | 11.99 | Los Angeles (CA) | CA 90001 | 9 | 27 |
Il semble que vous puissiez comprendre si vous groupez par le même ID de commande
Vous pouvez facilement trier les valeurs que vous portez en utilisant la fonction dupliquée.
df = all_data[all_data['Order ID'].duplicated(keep=False)]
df.head(20)
Order ID | Product | Quantity Ordered | Price Each | Order Date | Purchase Address | Month | Sales | City | State | Hour | Minute | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
3 | 176560 | Google Phone | 1 | 600.00 | 2019-04-12 14:38:00 | 669 Spruce St, Los Angeles, CA 90001 | 4 | 600.00 | Los Angeles (CA) | CA 90001 | 14 | 38 |
4 | 176560 | Wired Headphones | 1 | 11.99 | 2019-04-12 14:38:00 | 669 Spruce St, Los Angeles, CA 90001 | 4 | 11.99 | Los Angeles (CA) | CA 90001 | 14 | 38 |
18 | 176574 | Google Phone | 1 | 600.00 | 2019-04-03 19:42:00 | 20 Hill St, Los Angeles, CA 90001 | 4 | 600.00 | Los Angeles (CA) | CA 90001 | 19 | 42 |
19 | 176574 | USB-C Charging Cable | 1 | 11.95 | 2019-04-03 19:42:00 | 20 Hill St, Los Angeles, CA 90001 | 4 | 11.95 | Los Angeles (CA) | CA 90001 | 19 | 42 |
30 | 176585 | Bose SoundSport Headphones | 1 | 99.99 | 2019-04-07 11:31:00 | 823 Highland St, Boston, MA 02215 | 4 | 99.99 | Boston (MA) | MA 02215 | 11 | 31 |
31 | 176585 | Bose SoundSport Headphones | 1 | 99.99 | 2019-04-07 11:31:00 | 823 Highland St, Boston, MA 02215 | 4 | 99.99 | Boston (MA) | MA 02215 | 11 | 31 |
32 | 176586 | AAA Batteries (4-pack) | 2 | 2.99 | 2019-04-10 17:00:00 | 365 Center St, San Francisco, CA 94016 | 4 | 5.98 | San Francisco (CA) | CA 94016 | 17 | 0 |
33 | 176586 | Google Phone | 1 | 600.00 | 2019-04-10 17:00:00 | 365 Center St, San Francisco, CA 94016 | 4 | 600.00 | San Francisco (CA) | CA 94016 | 17 | 0 |
119 | 176672 | Lightning Charging Cable | 1 | 14.95 | 2019-04-12 11:07:00 | 778 Maple St, New York City, NY 10001 | 4 | 14.95 | New York City (NY) | NY 10001 | 11 | 7 |
120 | 176672 | USB-C Charging Cable | 1 | 11.95 | 2019-04-12 11:07:00 | 778 Maple St, New York City, NY 10001 | 4 | 11.95 | New York City (NY) | NY 10001 | 11 | 7 |
129 | 176681 | Apple Airpods Headphones | 1 | 150.00 | 2019-04-20 10:39:00 | 331 Cherry St, Seattle, WA 98101 | 4 | 150.00 | Seattle (WA) | WA 98101 | 10 | 39 |
130 | 176681 | ThinkPad Laptop | 1 | 999.99 | 2019-04-20 10:39:00 | 331 Cherry St, Seattle, WA 98101 | 4 | 999.99 | Seattle (WA) | WA 98101 | 10 | 39 |
138 | 176689 | Bose SoundSport Headphones | 1 | 99.99 | 2019-04-24 17:15:00 | 659 Lincoln St, New York City, NY 10001 | 4 | 99.99 | New York City (NY) | NY 10001 | 17 | 15 |
139 | 176689 | AAA Batteries (4-pack) | 2 | 2.99 | 2019-04-24 17:15:00 | 659 Lincoln St, New York City, NY 10001 | 4 | 5.98 | New York City (NY) | NY 10001 | 17 | 15 |
189 | 176739 | 34in Ultrawide Monitor | 1 | 379.99 | 2019-04-05 17:38:00 | 730 6th St, Austin, TX 73301 | 4 | 379.99 | Austin (TX) | TX 73301 | 17 | 38 |
190 | 176739 | Google Phone | 1 | 600.00 | 2019-04-05 17:38:00 | 730 6th St, Austin, TX 73301 | 4 | 600.00 | Austin (TX) | TX 73301 | 17 | 38 |
225 | 176774 | Lightning Charging Cable | 1 | 14.95 | 2019-04-25 15:06:00 | 372 Church St, Los Angeles, CA 90001 | 4 | 14.95 | Los Angeles (CA) | CA 90001 | 15 | 6 |
226 | 176774 | USB-C Charging Cable | 1 | 11.95 | 2019-04-25 15:06:00 | 372 Church St, Los Angeles, CA 90001 | 4 | 11.95 | Los Angeles (CA) | CA 90001 | 15 | 6 |
233 | 176781 | iPhone | 1 | 700.00 | 2019-04-03 07:37:00 | 976 Hickory St, Dallas, TX 75001 | 4 | 700.00 | Dallas (TX) | TX 75001 | 7 | 37 |
234 | 176781 | Lightning Charging Cable | 1 | 14.95 | 2019-04-03 07:37:00 | 976 Hickory St, Dallas, TX 75001 | 4 | 14.95 | Dallas (TX) | TX 75001 | 7 | 37 |
Les données avec le même identifiant sont désormais alignées sur une ligne
L'ensemble de données ci-dessus est la commande avec l'ID (≒ rien d'autre que la commande achetée en tant qu'ensemble)
Après le regroupement par ID, créez une colonne qui stocke les commandes achetées par cet ID. (Exemple ID: 1111 → Commande: pomme, banane, orange)
df = all_data[all_data['Order ID'].duplicated(keep=False)]
df['Grouped'] = df.groupby('Order ID')['Product'].transform(lambda x: ','.join(x))
#transform est comme une fonction Apply. Je vais omettre l'explication ici.
df = df[['Order ID','Grouped']].drop_duplicates()
df.head(10)
/opt/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:2: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
Order ID | Grouped | |
---|---|---|
3 | 176560 | Google Phone,Wired Headphones |
18 | 176574 | Google Phone,USB-C Charging Cable |
30 | 176585 | Bose SoundSport Headphones,Bose SoundSport Hea... |
32 | 176586 | AAA Batteries (4-pack),Google Phone |
119 | 176672 | Lightning Charging Cable,USB-C Charging Cable |
129 | 176681 | Apple Airpods Headphones,ThinkPad Laptop |
138 | 176689 | Bose SoundSport Headphones,AAA Batteries (4-pack) |
189 | 176739 | 34in Ultrawide Monitor,Google Phone |
225 | 176774 | Lightning Charging Cable,USB-C Charging Cable |
233 | 176781 | iPhone,Lightning Charging Cable |
Ça fait du bien. Les données sont bien organisées.
Dans cette colonne groupée, vous devez rechercher "qui, qui, dans quelle combinaison, combien de fois" etc.
Agrégons tout en utilisant une bibliothèque pratique. Voir stackoverflow ci-dessous pour une image concrète de la bibliothèque.
from itertools import combinations
from collections import Counter
count = Counter()
for row in df['Grouped']:
row_list = row.split(',')
count.update(Counter(combinations(row_list,2)))
count.most_common(10)
[(('iPhone', 'Lightning Charging Cable'), 1005),
(('Google Phone', 'USB-C Charging Cable'), 987),
(('iPhone', 'Wired Headphones'), 447),
(('Google Phone', 'Wired Headphones'), 414),
(('Vareebadd Phone', 'USB-C Charging Cable'), 361),
(('iPhone', 'Apple Airpods Headphones'), 360),
(('Google Phone', 'Bose SoundSport Headphones'), 220),
(('USB-C Charging Cable', 'Wired Headphones'), 160),
(('Vareebadd Phone', 'Wired Headphones'), 143),
(('Lightning Charging Cable', 'Wired Headphones'), 92)]
La sortie est un peu sale, donc je vais faire des corrections mineures
for key,value in count.most_common(10):
print(key,value)
('iPhone', 'Lightning Charging Cable') 1005
('Google Phone', 'USB-C Charging Cable') 987
('iPhone', 'Wired Headphones') 447
('Google Phone', 'Wired Headphones') 414
('Vareebadd Phone', 'USB-C Charging Cable') 361
('iPhone', 'Apple Airpods Headphones') 360
('Google Phone', 'Bose SoundSport Headphones') 220
('USB-C Charging Cable', 'Wired Headphones') 160
('Vareebadd Phone', 'Wired Headphones') 143
('Lightning Charging Cable', 'Wired Headphones') 92
iPhone et câble de charge sont les plus
C'est le dernier travail. Vous en êtes venu à penser par vous-même (partie hypothèse). Visualisons les données.
Pensez en quantité
product_group = all_data.groupby('Product')
quantity_ordered = product_group.sum()['Quantity Ordered']
products = [product for product,df in product_group]
plt.bar(products,quantity_ordered)
plt.xlabel('Product')
plt.ylabel('Quantity Ordered')
plt.xticks(products,rotation="vertical",size=8)
plt.show()
Y a-t-il beaucoup de câbles de batterie?
Je suppose que c'est parce que le prix est bon marché. Vérifiez les prix et les ventes.
prices = all_data.groupby('Product').mean()['Price Each']
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
#Génération de graphique commune à l'axe x et ayant différentes valeurs d'axe y
ax1.bar(products,quantity_ordered)
ax2.plot(products,prices,'b-')
ax1.set_xlabel('Product Name')
ax1.set_ylabel('Quanity Ordered', color="g")
ax2.set_ylabel('Price', color="b")
ax1.set_xticklabels(products,rotation="vertical",size=8)
plt.show()
C'est tout.