[PYTHON] C'est pourquoi j'ai quitté les pandas [Data Science 100 Knock (traitement des données structurées) # 3]

C'est pourquoi j'ai quitté les pandas [Data Science 100 Knock (traitement des données structurées) # 3]

Nous allons résoudre le problème Python de Data Science 100 Knock (traitement des données structurées). Ce groupe de questions utilise des pandas pour le traitement des données dans la réponse du modèle, mais nous le traiterons à l'aide de NumPy après étude.

: arrow_up: Premier article (# 1) : arrow_backward: article précédent (# 2) : arrow_forward: Article suivant (# 4)

introduction

En tant qu'étude de NumPy, je résoudrai le problème Python de Data Science 100 Knock (traitement des données structurées).

Beaucoup de gens qui font des activités de science des données en Python sont peut-être des amateurs de pandas, mais en fait, vous pouvez faire de même avec NumPy sans utiliser ** pandas **. Et NumPy est généralement plus rapide. En tant que personne qui aime les pandas, je ne suis toujours pas habitué à utiliser NumPy, donc j'aimerais essayer de sortir des pandas en exploitant ce "Data Science 100 Knock" avec NumPy.

Cette fois, je répondrai aux 17e à 22e questions. Cette zone semble être le thème du tri et du classement. Les données initiales ont été lues comme suit. C'est une politique de ne pas vectoriser les fonctions par np.vectorize () ou np.frompyfunc ().

import numpy as np
import pandas as pd
from numpy.lib import recfunctions as rfn

#Pour la réponse du modèle
df_customer = pd.read_csv('data/customer.csv')
df_receipt = pd.read_csv('data/receipt.csv')

#Données que nous traitons
arr_customer = np.genfromtxt(
    'data/customer.csv', delimiter=',', encoding='utf-8',
    names=True, dtype=None)
arr_receipt = np.genfromtxt(
    'data/receipt.csv', delimiter=',', encoding='utf-8',
    names=True, dtype=None)

P_017

P-17: Trier le bloc de données client (df_customer) par date de naissance (date_anniversaire) dans l'ordre chronologique, et afficher les 10 premiers éléments.

Si vous voulez trier le tableau, utilisez np.sort (), qui retournera le tableau trié. Cette fois, je veux l'ordre de tri, alors utilisez np.argsort () ou np.ndarray.argsort (). Il existe également un moyen de passer le nom de la colonne à l'argument ʻorder de np.sort () `, mais ce n'est pas recommandé car le comportement n'est pas bon.

In[017]


arr_customer[arr_customer['birth_day'].argsort()][:10]

Out[017]


array([('CS003813000014', 'Nanami Murayama', 1, 'Femme', '1928-11-26', 90, '182-0007', 'Kikunodai, ville de Chofu, Tokyo**********', 'S13003', 20160214, '0-00000000-0'),
       ('CS026813000004', 'Yoshimura Chaoyang', 1, 'Femme', '1928-12-14', 90, '251-0043', 'Motomachi Tsujido, ville de Fujisawa, préfecture de Kanagawa**********', 'S14026', 20150723, '0-00000000-0'),
       ('CS018811000003', 'Misato Kumazawa', 1, 'Femme', '1929-01-07', 90, '204-0004', 'Noshio, Kiyose City, Tokyo**********', 'S13018', 20150403, '0-00000000-0'),
       ('CS027803000004', 'Takuro Uchimura', 0, 'Masculin', '1929-01-12', 90, '251-0031', 'Kugenuma Fujigaya, ville de Fujisawa, préfecture de Kanagawa**********', 'S14027', 20151227, '0-00000000-0'),
       ('CS013801000003', 'Takuro Amano', 0, 'Masculin', '1929-01-15', 90, '274-0824', 'Maehara Higashi, ville de Funabashi, préfecture de Chiba**********', 'S12013', 20160120, '0-00000000-0'),
       ('CS001814000022', 'Riho Tsuruta', 1, 'Femme', '1929-01-28', 90, '144-0045', 'Minami Rokugo, Ota-ku, Tokyo**********', 'S13001', 20161012, 'A-20090415-7'),
       ('CS016815000002', 'Miki Yamamoto', 1, 'Femme', '1929-02-22', 90, '184-0005', 'Sakuramachi, ville de Koganei, Tokyo**********', 'S13016', 20150629, 'C-20090923-C'),
       ('CS009815000003', 'Riho Nakata', 1, 'Femme', '1929-04-08', 89, '154-0014', 'Shinmachi, Setagaya-ku, Tokyo**********', 'S13009', 20150421, 'D-20091021-E'),
       ('CS005813000015', 'Erika Kanaya', 1, 'Femme', '1929-04-09', 89, '165-0032', 'Sagimiya, Nakano-ku, Tokyo**********', 'S13005', 20150506, '0-00000000-0'),
       ('CS012813000013', 'Uno Minami Tomo', 1, 'Femme', '1929-04-09', 89, '231-0806', 'Honmoku-cho, Naka-ku, Yokohama-shi, Kanagawa**********', 'S14012', 20150712, '0-00000000-0')],
      dtype=[('customer_id', '<U14'), ('customer_name', '<U10'), ('gender_cd', '<i4'), ('gender', '<U2'), ('birth_day', '<U10'), ('age', '<i4'), ('postal_cd', '<U8'), ('address', '<U26'), ('application_store_cd', '<U6'), ('application_date', '<i4'), ('status_cd', '<U12')])

Time[017]


%timeit df_customer.sort_values('birth_day', ascending=True).head(10)
# 21.8 ms ± 346 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit arr_customer[arr_customer['birth_day'].argsort()][:10]
# 17.1 ms ± 473 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

P_018

P-18: Triez le bloc de données client (df_customer) par date de naissance (anniversaire_jour) dans l'ordre croissant, et affichez les 10 premiers éléments.

Inversez simplement l'ordre.

In[018]


arr_customer[arr_customer['birth_day'].argsort()][::-1][:10]

Out[018]


array([('CS035114000004', 'Misato Omura', 1, 'Femme', '2007-11-25', 11, '156-0053', 'Sakura, Setagaya-ku, Tokyo**********', 'S13035', 20150619, '6-20091205-6'),
       ('CS022103000002', 'Fukuyama Hajime', 9, 'inconnue', '2007-10-02', 11, '249-0006', 'Zushi, ville de Zushi, préfecture de Kanagawa**********', 'S14022', 20160909, '0-00000000-0'),
       ('CS002113000009', 'Mayuko Shibata', 1, 'Femme', '2007-09-17', 11, '184-0014', 'Nukii Minamimachi, ville de Koganei, Tokyo**********', 'S13002', 20160304, '0-00000000-0'),
       ('CS004115000014', 'Kyoko Matsui', 1, 'Femme', '2007-08-09', 11, '165-0031', 'Kamisagimiya, Nakano-ku, Tokyo**********', 'S13004', 20161120, '1-20081231-1'),
       ('CS002114000010', 'Haruka Yamauchi', 1, 'Femme', '2007-06-03', 11, '184-0015', 'Nukii Kitamachi, ville de Koganei, Tokyo**********', 'S13002', 20160920, '6-20100510-1'),
       ('CS025115000002', 'Natsuki Koyanagi', 1, 'Femme', '2007-04-18', 11, '245-0018', 'Ville de Kamiida, quartier d'Izumi, ville de Yokohama, préfecture de Kanagawa**********', 'S14025', 20160116, 'D-20100913-D'),
       ('CS002113000025', 'Manami Hirosue', 1, 'Femme', '2007-03-30', 12, '184-0015', 'Nukii Kitamachi, ville de Koganei, Tokyo**********', 'S13002', 20171030, '0-00000000-0'),
       ('CS033112000003', 'Miki Nagano', 1, 'Femme', '2007-03-22', 12, '245-0051', 'Ville de Nase, quartier de Totsuka, ville de Yokohama, préfecture de Kanagawa**********', 'S14033', 20150606, '0-00000000-0'),
       ('CS007115000006', 'Fukuoka Shun', 1, 'Femme', '2007-03-10', 12, '285-0845', 'Nishishizu, ville de Sakura, préfecture de Chiba**********', 'S12007', 20151118, 'F-20101016-F'),
       ('CS014113000008', 'Rio Yaguchi', 1, 'Femme', '2007-03-05', 12, '260-0041', 'Higashi Chiba, Chuo-ku, Chiba City, Préfecture de Chiba**********', 'S12014', 20150622, '3-20091108-6')],
      dtype=[('customer_id', '<U14'), ('customer_name', '<U10'), ('gender_cd', '<i4'), ('gender', '<U2'), ('birth_day', '<U10'), ('age', '<i4'), ('postal_cd', '<U8'), ('address', '<U26'), ('application_store_cd', '<U6'), ('application_date', '<i4'), ('status_cd', '<U12')])

P_019

P-19: Attribuez des rangs au bloc de données des détails du reçu (df_receipt) dans l'ordre décroissant du montant des ventes (montant) par article, et extrayez les 10 premiers articles. Les articles doivent afficher l'ID client (customer_id), le montant des ventes (montant) et le rang attribué. Si le montant (montant) des ventes est le même, le même classement sera donné.

Il est facile de trier par montant de ventes le plus élevé.

sorted_array = arr_receipt[['customer_id', 'amount']][
    arr_receipt['amount'].argsort()[::-1]]

sorted_array[:10]
# array([('CS011415000006', 10925), ('ZZ000000000000',  6800),
#        ('CS028605000002',  5780), ('ZZ000000000000',  5480),
#        ('ZZ000000000000',  5480), ('CS015515000034',  5480),
#        ('CS021515000089',  5440), ('ZZ000000000000',  5440),
#        ('ZZ000000000000',  5280), ('ZZ000000000000',  5280)],
#       dtype={'names':['customer_id','amount'], 'formats':['<U14','<i4'], 'offsets':[40,140], 'itemsize':144})

Classez ce montant de vente. Le moyen le plus simple est d'utiliser scipy.stats.rankdata (). Cette fois, nous demandons le plus, mais cette fonction renvoie le classement par ordre croissant, alors soustrayez-la de la valeur maximale et retournez-la.

import scipy.stats

rank_asc = scipy.stats.rankdata(sorted_array['amount'], 'max')
rank = rank_asc.max() - rank_asc + 1

rank[:10]
# array([1, 2, 3, 4, 4, 4, 7, 7, 9, 9], dtype=int64)

Si vous n'utilisez pas la fonction scipy.stats.rankdata (), elle vérifie l'existence de liens et dit "quelle est la plus grande valeur de chaque ligne" et "quelle est la nième valeur la plus grande". Créez un tableau pour créer un tableau de rangs.

#False si elle a le même rang que la ligne supérieure suivante, True sinon
rank_cutidx = np.concatenate(
    ([True], sorted_array['amount'][1:] != sorted_array['amount'][:-1]))

# rank_cutidx.cumsum()-1: un tableau affichant la valeur la plus élevée de chaque ligne
# rank_cutidx.nonzero(): Un tableau indiquant le nombre de chaque "nième valeur la plus grande"
rank = rank_cutidx.nonzero()[0][rank_cutidx.cumsum()-1] + 1

rank[:10]
# array([1, 2, 3, 4, 4, 4, 7, 7, 9, 9], dtype=int64)

J'utilise numpy.lib.recfunctions.append_fields () pour ajouter des colonnes, mais cette fonction était extrêmement lente (elle semble recréer un nouveau tableau à partir de zéro).

In[019]


sorted_array = arr_receipt[['customer_id', 'amount']][
    arr_receipt['amount'].argsort()[::-1]]
rank_cutidx = np.concatenate(
    ([True], sorted_array['amount'][1:] != sorted_array['amount'][:-1]))
rank = rank_cutidx.nonzero()[0][rank_cutidx.cumsum()-1]+1
rfn.append_fields(sorted_array, 'ranking', rank,
                  dtypes=rank.dtype, usemask=False)[:10]

Ensuite, vous devez préparer vous-même une table vierge ...

In[019]


sorter_index = arr_receipt['amount'].argsort()[::-1]
sorted_id = arr_receipt['customer_id'][sorter_index]
sorted_amount = arr_receipt['amount'][sorter_index]
rank_cutidx = np.concatenate(
    ([True], sorted_amount[1:] != sorted_amount[:-1]))
rank = rank_cutidx.nonzero()[0][rank_cutidx.cumsum()-1]+1

#Arrangement
new_arr = np.empty(arr_receipt.size, dtype=[('customer_id', sorted_id.dtype),
                                            ('amount', sorted_amount.dtype),
                                            ('ranking', rank.dtype)])
new_arr['customer_id'] = sorted_id
new_arr['amount'] = sorted_amount
new_arr['ranking'] = rank
new_arr[:10]

Out[019]


array([('CS011415000006', 10925, 1), ('ZZ000000000000',  6800, 2),
       ('CS028605000002',  5780, 3), ('ZZ000000000000',  5480, 4),
       ('ZZ000000000000',  5480, 4), ('CS015515000034',  5480, 4),
       ('CS021515000089',  5440, 7), ('ZZ000000000000',  5440, 7),
       ('ZZ000000000000',  5280, 9), ('ZZ000000000000',  5280, 9)],
      dtype=[('customer_id', '<U14'), ('amount', '<i4'), ('ranking', '<i8')])

Time[019]


#Le modèle de réponse
%%timeit
df_tmp = pd.concat([df_receipt[['customer_id', 'amount']],
                    df_receipt['amount'].rank(method='min', ascending=False)], axis=1)
df_tmp.columns = ['customer_id', 'amount', 'ranking']
df_tmp.sort_values('ranking', ascending=True).head(10)
# 35 ms ± 643 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

#Une petite amélioration en une ligne
%%timeit
df_receipt[['customer_id', 'amount']] \
    .assign(ranking=df_receipt['amount'].rank(method='min', ascending=False)) \
    .sort_values('ranking', ascending=True).head(10)
# 34.1 ms ± 943 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

# Numpy
%%timeit
tmp_amount = np.ascontiguousarray(arr_receipt['amount'])
sorter_index = tmp_amount.argsort()[::-1]
sorted_id = arr_receipt['customer_id'][sorter_index]
sorted_amount = tmp_amount[sorter_index]
rank_cutidx = np.concatenate(([True], sorted_amount[1:] != sorted_amount[:-1]))
rank = rank_cutidx.nonzero()[0][rank_cutidx.cumsum()-1]+1
new_arr = np.empty(arr_receipt.size, dtype=[('customer_id', sorted_id.dtype), ('amount', sorted_amount.dtype), ('ranking', rank.dtype)])
new_arr['customer_id'] = sorted_id
new_arr['amount'] = sorted_amount
new_arr['ranking'] = rank
new_arr[:10]
# 22.6 ms ± 464 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

J'ai réussi à le traiter plus rapidement que les pandas.

P_020

P-020: attribuez des rangs au bloc de données des détails du reçu (df_receipt) dans l'ordre décroissant du montant des ventes (montant) par article, et extrayez les 10 premiers articles. Les articles doivent afficher l'ID client (customer_id), le montant des ventes (montant) et le rang attribué. Même si le montant (montant) des ventes est le même, un autre classement doit être donné.

Ceci est un classement, ou juste un numéro de série avec np.arange ().

In[020]


rfn.append_fields(arr_receipt[['customer_id', 'amount']]
                  [arr_receipt['amount'].argsort()[::-1]],
                  'ranking', np.arange(1, arr_receipt.size+1),
                  dtypes='<i4', usemask=False)[:10]

In[020]


sorter_index = arr_receipt['amount'].argsort()[::-1]
sorted_id = arr_receipt['customer_id'][sorter_index]
sorted_amount = arr_receipt['amount'][sorter_index]
rank = np.arange(1, sorted_id.size+1)

#Arrangement
new_arr = np.empty(arr_receipt.size, dtype=[('customer_id', sorted_id.dtype),
                                            ('amount', sorted_amount.dtype),
                                            ('ranking', rank.dtype)])
new_arr['customer_id'] = sorted_id
new_arr['amount'] = sorted_amount
new_arr['ranking'] = rank
new_arr[:10]

Out[020]


array([('CS011415000006', 10925,  1), ('ZZ000000000000',  6800,  2),
       ('CS028605000002',  5780,  3), ('ZZ000000000000',  5480,  4),
       ('ZZ000000000000',  5480,  5), ('CS015515000034',  5480,  6),
       ('CS021515000089',  5440,  7), ('ZZ000000000000',  5440,  8),
       ('ZZ000000000000',  5280,  9), ('ZZ000000000000',  5280, 10)],
      dtype=[('customer_id', '<U14'), ('amount', '<i4'), ('ranking', '<i4')])

P_021

P-021: Comptez le nombre de caisses pour la trame de données des détails de réception (df_receipt).

In[021]


arr_receipt.size
len(arr_receipt)
arr_receipt.shape[0]

Out[021]


104681
104681
104681

P_022

P-022: Comptez le nombre de cas uniques pour l'ID client (customer_id) du bloc de données des détails du reçu (df_receipt).

Le nombre unique de données de chaîne de caractères n'est pas bon pour NumPy.

In[022]


np.unique(arr_receipt['customer_id']).size

Out[022]


8307

Ceci est connu pour être beaucoup plus rapide avec les pandas qu'avec NumPy, comme les pandas se vantent dans la documentation officielle, et nous, les pilotes de NumPy, ne pouvons probablement pas aider.

Time[022]


%timeit len(df_receipt['customer_id'].unique())
# 8.19 ms ± 204 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit np.unique(arr_receipt['customer_id']).size
# 30.9 ms ± 635 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

Recommended Posts

C'est pourquoi j'ai quitté les pandas [Data Science 100 Knock (traitement des données structurées) # 2]
C'est pourquoi j'ai quitté les pandas [Data Science 100 Knock (traitement des données structurées) # 1]
C'est pourquoi j'ai quitté les pandas [Data Science 100 Knock (traitement des données structurées) # 3]
C'est pourquoi j'ai quitté les pandas [Data Science 100 Knock (traitement des données structurées) # 5]
C'est pourquoi j'ai quitté les pandas [Data Science 100 Knock (traitement des données structurées) # 4]
C'est pourquoi j'ai quitté les pandas [Data Science 100 Knock (traitement des données structurées) # 6]
"Data Science 100 Knock (traitement de données structurées)" Explication Python-007
"Data Science 100 Knock (traitement des données structurées)" Explication Python-001
"Data Science 100 Knock (traitement des données structurées)" Explication Python-002
[Python] 100 coups sur la science des données (traitement de données structurées) 021 Explication
"Data Science 100 Knock (traitement des données structurées)" Explication Python-005
"Data Science 100 Knock (traitement de données structurées)" Explication Python-004
[Python] 100 coups sur la science des données (traitement de données structurées) 020 Explication
[Python] 100 coups sur la science des données (traitement de données structurées) 025 Explication
"Data Science 100 Knock (traitement des données structurées)" Explication Python-003
[Python] 100 coups sur la science des données (traitement de données structurées) 019 Explication
Préparation à l’essai de «Data Science 100 Knock (traitement des données structurées)»
Construction d'environnement (Windows 10) pour 100 coups de science des données (traitement de données structurées)
[Python] 100 coups sur la science des données (traitement de données structurées) 001-010 Impressions + résumé du lien de commentaire
C'est pourquoi j'ai quitté pandas [Trois façons de groupby.mean () avec juste NumPy]
[Python] 100 coups sur la science des données (traitement de données structurées) 018 Explication
[Python] 100 coups sur la science des données (traitement de données structurées) 023 Explication
[Python] 100 coups sur la science des données (traitement de données structurées) 030 Explication
[Python] 100 coups sur la science des données (traitement de données structurées) 022 Explication
100 langage de traitement knock-20 (à l'aide de pandas): lecture de données JSON
[Python] 100 coups sur la science des données (traitement de données structurées) 017 Explication
[Python] 100 coups sur la science des données (traitement de données structurées) 026 Explication
[Python] 100 coups sur la science des données (traitement de données structurées) 016 Explication
[Python] 100 coups sur la science des données (traitement de données structurées) 024 Explication
[Python] 100 coups sur la science des données (traitement de données structurées) 027 Explication
[Python] 100 coups sur la science des données (traitement de données structurées) 029 Explication
[Python] 100 coups sur la science des données (traitement de données structurées) 015 Explication
[Python] 100 coups sur la science des données (traitement de données structurées) 028 Explication
Commentaire sur la science des données à 100 coups (P021 ~ 040)
Commentaire sur la science des données à 100 coups (P061 ~ 080)
Commentaire de la science des données 100 coups (P041 ~ 060)
Commentaire sur la science des données à 100 coups (P081 ~ 100)
J'ai essayé 100 traitements linguistiques Knock 2020
Conseils de traitement des données avec Pandas
J'ai essayé 100 traitements linguistiques Knock 2020: Chapitre 3
100 traitement du langage knock-31 (en utilisant des pandas): verbe
J'ai essayé 100 traitements linguistiques Knock 2020: Chapitre 1
J'ai essayé 100 traitements linguistiques Knock 2020: Chapitre 2
J'ai essayé 100 traitements linguistiques Knock 2020: Chapitre 4
100 traitement du langage knock-38 (en utilisant des pandas): histogramme
100 Language Processing Knock-33 (en utilisant des pandas): nom sahen
100 traitement du langage knock-91: Préparation des données d'analogie
J'ai essayé la "Practical Python Data Science" d'Udemy
100 traitement du langage knock-35 (utilisant des pandas): concaténation de nomenclature
100 Language Processing Knock-39 (en utilisant des pandas): la loi de Zipf
Exemple de traitement efficace des données avec PANDAS
100 traitement de langage knock-34 (utilisant des pandas): "B of A"