Wir werden das Python-Problem von [Data Science 100 Knock (Strukturierte Datenverarbeitung)] lösen (https://github.com/The-Japan-DataScientist-Society/100knocks-preprocess). Diese Gruppe von Fragen verwendet Pandas für die Datenverarbeitung in der Modellantwort, aber wir werden sie nach dem Studium mit NumPy verarbeiten.
: arrow_up: Erster Artikel (# 1) : arrow_backward: Vorheriger Artikel (# 4) : arrow_forward: Nächster Artikel (# 6)
Als Studie von NumPy werde ich das Python-Problem von [Data Science 100 Knock (Strukturierte Datenverarbeitung)] lösen (https://github.com/The-Japan-DataScientist-Society/100knocks-preprocess).
Viele Leute, die in Python datenwissenschaftliche Dinge tun, mögen Pandas-Liebhaber sein, aber tatsächlich können Sie dasselbe mit NumPy tun, ohne ** Pandas ** zu verwenden. Und NumPy ist normalerweise schneller. Als eine Person, die Pandas liebt, bin ich es immer noch nicht gewohnt, NumPy zu betreiben. Daher möchte ich versuchen, einen Abschluss von Pandas zu machen, indem ich diesen "Data Science 100 Knock" mit NumPy betreibe.
Dieses Mal werde ich die 36. bis 44. Frage stellen. Es scheint das Thema des Zusammenführens mehrerer Datenrahmen zu sein. Die Ausgangsdaten wurden wie folgt gelesen (Datentypspezifikation wird vorerst verschoben).
import numpy as np
import pandas as pd
from numpy.lib import recfunctions as rfn
#Für Modellantwort
df_category = pd.read_csv('data/category.csv', dtype='string')
df_customer = pd.read_csv('data/customer.csv')
df_product = pd.read_csv(
'data/product.csv',
dtype={col: 'string' for col in
['category_major_cd', 'category_medium_cd', 'category_small_cd']})
df_receipt = pd.read_csv('data/receipt.csv')
df_store = pd.read_csv('data/store.csv')
#Daten, mit denen wir umgehen
arr_category = np.genfromtxt(
'data/category.csv', delimiter=',', encoding='utf-8-sig',
names=True, dtype=tuple(['<U15']*6))
arr_customer = np.genfromtxt(
'data/customer.csv', delimiter=',', encoding='utf-8',
names=True, dtype=None)
arr_product = np.genfromtxt(
'data/product.csv', delimiter=',', encoding='utf-8-sig',
names=True, dtype=tuple(['<U10']*4+['<i4']*2))
arr_receipt = np.genfromtxt(
'data/receipt.csv', delimiter=',', encoding='utf-8',
names=True, dtype=None)
arr_store = np.genfromtxt(
'data/store.csv', delimiter=',', encoding='utf-8',
names=True, dtype=None)
Schließlich eine Funktion zum Ausgeben des Berechnungsergebnisses als strukturiertes Array
def make_array(size, **kwargs):
arr = np.empty(size, dtype=[(colname, subarr.dtype)
for colname, subarr in kwargs.items()])
for colname, subarr in kwargs.items():
arr[colname] = subarr
return arr
P_036
P-036: Kombinieren Sie intern den Belegdetaildatenrahmen (df_receipt) und den Geschäftsdatenrahmen (df_store) und zeigen Sie alle Elemente im Belegdetaildatenrahmen und 10 Geschäftsnamen (Geschäftsname) im Geschäftsdatenrahmen an.
Obwohl es sich um eine innere Verknüpfung handelt, lautet der Inhalt VLOOKUP. Führen Sie zunächst np.unique ()
für die kombinierte Matrix der Schlüsselzeichenfolgen beider Frames aus, um sie in numerische Daten zu konvertieren. Verwenden Sie dann "np.searchsorted ()", um die Speichercode-Spalte in der Empfangsbestätigung zu ersetzen.
In[023]
_, inv = np.unique(np.concatenate([arr_store['store_cd'],
arr_receipt['store_cd']]),
return_inverse=True)
inv_map, inv_arr = inv[:arr_store.size], inv[arr_store.size:]
sorter_index = np.argsort(inv_map)
idx = np.searchsorted(inv_map, inv_arr, sorter=sorter_index)
store_name = arr_store['store_name'][sorter_index[idx]]
new_arr = make_array(arr_receipt.size, **{col: arr_receipt[col]
for col in arr_receipt.dtype.names},
store_name=store_name)
new_arr[:10]
Out[023]
array([(20181103, 1257206400, 'S14006', 112, 1, 'CS006214000001', 'P070305012', 1, 158, 'Kuzugaya Laden'),
(20181118, 1258502400, 'S13008', 1132, 2, 'CS008415000097', 'P070701017', 1, 81, 'Naruki-Laden'),
(20170712, 1215820800, 'S14028', 1102, 1, 'CS028414000014', 'P060101005', 1, 170, 'Futatsubashi-Laden'),
(20190205, 1265328000, 'S14042', 1132, 1, 'ZZ000000000000', 'P050301001', 1, 25, 'Shin Yamashita Laden'),
(20180821, 1250812800, 'S14025', 1102, 2, 'CS025415000050', 'P060102007', 1, 90, 'Yamato-Laden'),
(20190605, 1275696000, 'S13003', 1112, 1, 'CS003515000195', 'P050102002', 1, 138, 'Komae-Laden'),
(20181205, 1259971200, 'S14024', 1102, 2, 'CS024514000042', 'P080101005', 1, 30, 'Mita-Laden'),
(20190922, 1285113600, 'S14040', 1102, 1, 'CS040415000178', 'P070501004', 1, 128, 'Nagatsuda-Laden'),
(20170504, 1209859200, 'S13020', 1112, 2, 'ZZ000000000000', 'P071302010', 1, 770, 'Jujo Nakahara Laden'),
(20191010, 1286668800, 'S14027', 1102, 1, 'CS027514000015', 'P071101003', 1, 680, 'Minami Fujisawa Laden')],
dtype=[('sales_ymd', '<i4'), ('sales_epoch', '<i4'), ('store_cd', '<U6'), ('receipt_no', '<i4'), ('receipt_sub_no', '<i4'), ('customer_id', '<U14'), ('product_cd', '<U10'), ('quantity', '<i4'), ('amount', '<i4'), ('store_name', '<U6')])
Bei der Methode mit "pd.merge ()" der Modellantwort wird sie zwangsweise nach der Schlüsselspalte sortiert (da die Schlüsselspalte nicht eindeutig ist). Wenn dies das Problem ist, wenn Sie es mit Pandas tun
store_name = df_receipt['store_cd'].map(
df_store.set_index('store_cd')['store_name'])
df = df_receipt.assign(store_name=store_name)
Es sollte getan werden.
P_037
P-037: Kombinieren Sie intern den Produktdatenrahmen (df_product) und den Kategoriedatenrahmen (df_category) und zeigen Sie alle Elemente des Produktdatenrahmens und 10 Unterkategorienamen (category_small_name) des Kategoriedatenrahmens an.
das Gleiche.
In[037]
_, inv = np.unique(np.concatenate([arr_category['category_small_cd'],
arr_product['category_small_cd']]),
return_inverse=True)
inv_map, inv_arr = inv[:arr_category.size], inv[arr_category.size:]
sorter_index = np.argsort(inv_map)
idx = np.searchsorted(inv_map, inv_arr, sorter=sorter_index)
store_name = arr_category['category_small_name'][sorter_index[idx]]
new_arr = make_array(arr_product.size, **{col: arr_product[col]
for col in arr_product.dtype.names},
store_name=store_name)
new_arr[:10]
Out[037]
array([('P040101001', '04', '0401', '040101', 198, 149, 'Bento'),
('P040101002', '04', '0401', '040101', 218, 164, 'Bento'),
('P040101003', '04', '0401', '040101', 230, 173, 'Bento'),
('P040101004', '04', '0401', '040101', 248, 186, 'Bento'),
('P040101005', '04', '0401', '040101', 268, 201, 'Bento'),
('P040101006', '04', '0401', '040101', 298, 224, 'Bento'),
('P040101007', '04', '0401', '040101', 338, 254, 'Bento'),
('P040101008', '04', '0401', '040101', 420, 315, 'Bento'),
('P040101009', '04', '0401', '040101', 498, 374, 'Bento'),
('P040101010', '04', '0401', '040101', 580, 435, 'Bento')],
dtype=[('product_cd', '<U10'), ('category_major_cd', '<U10'), ('category_medium_cd', '<U10'), ('category_small_cd', '<U10'), ('unit_price', '<i4'), ('unit_cost', '<i4'), ('store_name', '<U15')])
P_038
P-038: Ermitteln Sie den Gesamtumsatz für jeden Kunden aus dem Kundendatenrahmen (df_customer) und dem Belegdetaildatenrahmen (df_receipt). Für Kunden ohne Einkaufsaufzeichnung sollte der Verkaufsbetrag jedoch als 0 angezeigt werden. Darüber hinaus sollten Kunden diejenigen ansprechen, deren Geschlechtscode (gender_cd) weiblich ist (1), und Nichtmitglieder ausschließen (Kunden-IDs beginnend mit 'Z'). Es müssen nur 10 Ergebnisse angezeigt werden.
Kombinieren Sie in ähnlicher Weise zuerst die Schlüsselzeichenfolgen beider Frames und konvertieren Sie sie dann in numerische Daten. Verwenden Sie als Nächstes "np.bincount ()", um die Gesamtsumme für jeden Kunden zu berechnen. Wenn Sie jedoch zu diesem Zeitpunkt das dritte Argument "minlength" verwenden, hat die Ausgabematrix eine beliebige Größe, also "unq.size" Angegeben. Schließlich wird der Wert durch Indizieren der Belegartendatenseite der digitalisierten Schlüsselspalte erhalten.
In[038]
is_member_receipt = arr_receipt['customer_id'].astype('<U1') != 'Z'
is_member_customer = ((arr_customer['customer_id'].astype('<U1') != 'Z')
& (arr_customer['gender_cd'] == 1))
customer = arr_customer['customer_id'][is_member_customer]
unq, inv = np.unique(
np.concatenate([customer, arr_receipt['customer_id'][is_member_receipt]]),
return_inverse=True)
customer_size = customer.size
amount_sum = np.bincount(
inv[customer_size:], arr_receipt['amount'][is_member_receipt], unq.size)
new_arr = make_array(customer_size,
customer_id=customer,
amount=amount_sum[inv[:customer_size]])
new_arr[:10]
Out[038]
array([('CS021313000114', 0.), ('CS031415000172', 5088.),
('CS028811000001', 0.), ('CS001215000145', 875.),
('CS015414000103', 3122.), ('CS033513000180', 868.),
('CS035614000014', 0.), ('CS011215000048', 3444.),
('CS009413000079', 0.), ('CS040412000191', 210.)],
dtype=[('customer_id', '<U14'), ('amount', '<f8')])
P_039
P-039: Extrahieren Sie die Top-20-Kunden mit der höchsten Anzahl von Verkaufstagen und die Top-20-Kunden mit dem höchsten Gesamtumsatz aus dem Datenrahmen für Belegauszüge (df_receipt) und führen Sie eine vollständige äußere Verknüpfung durch. Nichtmitglieder (Kunden-IDs, die mit 'Z' beginnen) sollten jedoch ausgeschlossen werden.
Verwenden Sie np.partition ()
, um den 20. Wert zu erhalten, ersetzen Sie den Wert, der nicht in den Top 20 liegt, durch np.nan
und rufen Sie dann den Index ab.
In[039]
is_member = arr_receipt['customer_id'].astype('<U1') != 'Z'
unq, inv = np.unique(arr_receipt['customer_id'][is_member],
return_inverse=True)
sums = np.bincount(inv, arr_receipt['amount'][is_member], unq.size)
is_sum_top = sums >= -np.partition(-sums, 20)[20]
sums[~is_sum_top] = np.nan
unq2 = np.unique([inv, arr_receipt['sales_ymd'][is_member]], axis=-1)
counts = np.bincount(unq2[0]).astype(float)
is_cnt_top = counts >= -np.partition(-counts, 20)[20]
counts[~is_cnt_top] = np.nan
interserction = is_cnt_top | is_sum_top
make_array(interserction.sum(),
customer_id=unq[interserction],
amount=sums[interserction],
sales_ymd=counts[interserction])
Out[039]
array([('CS001605000009', 18925., nan), ('CS006515000023', 18372., nan),
('CS007514000094', 15735., nan), ('CS007515000107', nan, 18.),
('CS009414000059', 15492., nan), ('CS010214000002', nan, 21.),
('CS010214000010', 18585., 22.), ('CS011414000106', 18338., nan),
('CS011415000006', 16094., nan), ('CS014214000023', nan, 19.),
('CS014415000077', nan, 18.), ('CS015415000185', 20153., 22.),
('CS015515000034', 15300., nan), ('CS016415000101', 16348., nan),
('CS016415000141', 18372., 20.), ('CS017415000097', 23086., 20.),
('CS021514000045', nan, 19.), ('CS021515000056', nan, 18.),
('CS021515000089', 17580., nan), ('CS021515000172', nan, 19.),
('CS021515000211', nan, 18.), ('CS022515000028', nan, 18.),
('CS022515000226', nan, 19.), ('CS026414000059', 15153., nan),
('CS028415000007', 19127., 21.), ('CS030214000008', nan, 18.),
('CS030415000034', 15468., nan), ('CS031414000051', 19202., 19.),
('CS031414000073', nan, 18.), ('CS032414000072', 16563., nan),
('CS032415000209', nan, 18.), ('CS034415000047', 16083., nan),
('CS035414000024', 17615., nan), ('CS038415000104', 17847., nan),
('CS039414000052', nan, 19.), ('CS040214000008', nan, 23.)],
dtype=[('customer_id', '<U14'), ('amount', '<f8'), ('sales_ymd', '<f8')])
P_040
P-040: Ich möchte untersuchen, wie viele Daten durch die Kombination aller Geschäfte und Produkte erhalten werden. Berechnen Sie die Anzahl der direkten Produkte von Geschäften (df_store) und Produkten (df_product).
Ich verstehe die Absicht des Problems nicht ...
In[040]
arr_store.size * arr_product.size
Out[040]
531590
Time[040]
#Musterantwort
%%timeit
df_store_tmp = df_store.copy()
df_product_tmp = df_product.copy()
df_store_tmp['key'] = 0
df_product_tmp['key'] = 0
len(pd.merge(df_store_tmp, df_product_tmp, how='outer', on='key'))
# 277 ms ± 6.09 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
# NumPy
%timeit arr_store.size * arr_product.size
# 136 ns ± 1.69 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
P_041
P-041: Aggregieren Sie den Verkaufsbetrag (Betrag) des Belegdetail-Datenrahmens (df_receipt) für jedes Datum (sales_ymd) und berechnen Sie die Zunahme / Abnahme des Verkaufsbetrags gegenüber dem Vortag. Es reicht aus, 10 Berechnungsergebnisse anzuzeigen.
Verwenden Sie np.ediff1d ()
, um die Differenz vorher und nachher im Array zu erhalten.
In[041]
unq, inv = np.unique(arr_receipt['sales_ymd'], return_inverse=True)
diff_amount = np.ediff1d(np.bincount(inv, arr_receipt['amount']))
make_array(unq.size, sales_ymd=unq,
diff_amount=np.concatenate([[np.nan], diff_amount]))[:10]
Out[041]
array([(20170101, nan), (20170102, -9558.), (20170103, 3338.),
(20170104, 8662.), (20170105, 1665.), (20170106, -5443.),
(20170107, -8972.), (20170108, 1322.), (20170109, 1981.),
(20170110, -6575.)],
dtype=[('sales_ymd', '<i4'), ('diff_amount', '<f8')])
P_042
P-042: Aggregieren Sie den Verkaufsbetrag (Betrag) des Belegdetail-Datenrahmens (df_receipt) für jedes Datum (sales_ymd) und kombinieren Sie die Daten von vor 1 Tag, 2 Tagen und 3 Tagen mit den Daten jedes Datums. Es sollten nur 10 Ergebnisse angezeigt werden.
Nimm es in Scheiben.
In[042]
unq, inv = np.unique(arr_receipt['sales_ymd'], return_inverse=True)
amount = np.bincount(inv, arr_receipt['amount'])
make_array(unq.size - 3,
sales_ymd=unq[3:], amount=amount[3:],
lag_ymd_1=unq[2:-1], lag_amount_1=amount[2:-1],
lag_ymd_2=unq[1:-2], lag_amount_2=amount[1:-2],
lag_ymd_3=unq[:-3], lag_amount_3=amount[:-3])[:10]
Out[042]
array([(20170104, 36165., 20170103, 27503., 20170102, 24165., 20170101, 33723.),
(20170105, 37830., 20170104, 36165., 20170103, 27503., 20170102, 24165.),
(20170106, 32387., 20170105, 37830., 20170104, 36165., 20170103, 27503.),
(20170107, 23415., 20170106, 32387., 20170105, 37830., 20170104, 36165.),
(20170108, 24737., 20170107, 23415., 20170106, 32387., 20170105, 37830.),
(20170109, 26718., 20170108, 24737., 20170107, 23415., 20170106, 32387.),
(20170110, 20143., 20170109, 26718., 20170108, 24737., 20170107, 23415.),
(20170111, 24287., 20170110, 20143., 20170109, 26718., 20170108, 24737.),
(20170112, 23526., 20170111, 24287., 20170110, 20143., 20170109, 26718.),
(20170113, 28004., 20170112, 23526., 20170111, 24287., 20170110, 20143.)],
dtype=[('sales_ymd', '<i4'), ('amount', '<f8'), ('lag_ymd_1', '<i4'), ('lag_amount_1', '<f8'), ('lag_ymd_2', '<i4'), ('lag_amount_2', '<f8'), ('lag_ymd_3', '<i4'), ('lag_amount_3', '<f8')])
P_043
P-043: Verkaufsübersichtsdatenrahmen (df_sales_summary), der den Belegdetaildatenrahmen (df_receipt) und den Kundendatenrahmen (df_customer) kombiniert und den Verkaufsbetrag (Betrag) für jedes Geschlecht (Geschlecht) und Alter (berechnet aus dem Alter) summiert. ). Das Geschlecht ist 0 für Männer, 1 für Frauen und 9 für Unbekannte.
Die Artikelzusammensetzung sollte jedoch vier Artikel umfassen: Alter, Verkaufsbetrag für Frauen, Verkaufsbetrag für Männer und Verkaufsbetrag für unbekanntes Geschlecht (Kreuztabelle von Alter vertikal und Geschlecht horizontal). Außerdem sollte die Altersgruppe alle 10 Jahre alt sein.
Zuerst werden die Schlüsselzeichenfolgen beider Frames kombiniert und dann in numerische Daten konvertiert. Erstellen Sie als Nächstes eine Matrix "map_array" mit fehlenden Werten und fügen Sie Alter und Geschlecht in die Matrix ein, wobei Sie die digitalisierte Kunden-ID auf der Kundendatenseite als Index verwenden. Danach wird die quantifizierte Kunden-ID auf der Seite mit den Belegartendaten als Index zur Erfassung von Alter und Geschlecht verwendet. Erstellen Sie schließlich eine zweidimensionale Ebene aus Alter und Geschlecht, indizieren Sie Geschlecht und Alter und addieren Sie den Verkaufsbetrag.
In[043]
#Kunden-ID in numerische Daten umwandeln
unq, inv = np.unique(np.concatenate([arr_customer['customer_id'],
arr_receipt['customer_id']]),
return_inverse=True)
inv_map, inv_arr = inv[:arr_customer.size], inv[arr_customer.size:]
#Erwerb des Alters (fehlender Wert=0)
map_array = np.zeros(unq.size, dtype=int)
map_array[inv_map] = arr_customer['age']//10
arr_age = map_array[inv_arr]
max_age = arr_age.max()+1
#Gender-Akquisition (fehlender Wert=9)
# map_array = np.full(unq.size, 9, dtype=int)
map_array[:] = 9
map_array[inv_map] = arr_customer['gender_cd']
arr_gender = map_array[inv_arr]
#Gesamtumsatz auf einer zweidimensionalen Ebene von Alter und Geschlecht
arr_sales_summary = np.zeros((max_age, arr_gender.max()+1), dtype=int)
np.add.at(arr_sales_summary, (arr_age, arr_gender), arr_receipt['amount'])
#In ein strukturiertes Array konvertieren
make_array(max_age,
era=np.arange(max_age)*10,
male=arr_sales_summary[:, 0],
female=arr_sales_summary[:, 1],
unknown=arr_sales_summary[:, 9])
Out[043]
array([( 0, 0, 0, 12395003), (10, 1591, 149836, 4317),
(20, 72940, 1363724, 44328), (30, 177322, 693047, 50441),
(40, 19355, 9320791, 483512), (50, 54320, 6685192, 342923),
(60, 272469, 987741, 71418), (70, 13435, 29764, 2427),
(80, 46360, 262923, 5111), (90, 0, 6260, 0)],
dtype=[('era', '<i4'), ('male', '<i4'), ('female', '<i4'), ('unknown', '<i4')])
Time[043]
Modellantwort: 177 ms ± 3.45 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
NumPy:66.4 ms ± 1.28 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
P_044
P-044: Der in der vorherigen Frage erstellte Datenrahmen für die Verkaufszusammenfassung (df_sales_summary) war ein Side-by-Side-Verkauf des Geschlechts. Lassen Sie uns das Geschlecht vertikal aus diesem Datenrahmen heraushalten und es in drei Elemente konvertieren: Alter, Geschlechtscode und Verkaufsbetrag. Der Geschlechtscode lautet jedoch "00" für Männer, "01" für Frauen und "99" für Unbekannte.
In[044]
arr_amount = arr_sales_summary[:, [0, 1, 9]].ravel()
make_array(arr_amount.size,
era=(np.arange(max_age)*10).repeat(3),
gender_cd=np.tile(np.array(['00', '01', '99']), max_age),
amount=arr_amount)
Out[044]
array([( 0, '00', 0), ( 0, '01', 0), ( 0, '99', 12395003),
(10, '00', 1591), (10, '01', 149836), (10, '99', 4317),
(20, '00', 72940), (20, '01', 1363724), (20, '99', 44328),
(30, '00', 177322), (30, '01', 693047), (30, '99', 50441),
(40, '00', 19355), (40, '01', 9320791), (40, '99', 483512),
(50, '00', 54320), (50, '01', 6685192), (50, '99', 342923),
(60, '00', 272469), (60, '01', 987741), (60, '99', 71418),
(70, '00', 13435), (70, '01', 29764), (70, '99', 2427),
(80, '00', 46360), (80, '01', 262923), (80, '99', 5111),
(90, '00', 0), (90, '01', 6260), (90, '99', 0)],
dtype=[('era', '<i4'), ('gender_cd', '<U2'), ('amount', '<i4')])
Recommended Posts