2016-05-26 8 views
1

Ich habe Code, der userID, categoryID und date als Eingabewerte hat. Ich möchte überprüfen, ob die Einträge gültig sind, z. wenn die userID sogar in meinem Dataset vorhanden ist. Es funktioniert so, wie ich es mache, aber ich muss ein paar Sekunden (!) Warten, bis das Hauptprogramm ausgeführt wird.Wie man "value is in dateframe column" schneller macht

var_uid = int(input("Please enter a user ID: ")) 
var_catid = input("Please enter a category ID: ") 
var_date = input("Please enter a date to restrict the considered data (YYYY-MM-DD): ") 


if (~var_uid in df_data['UserID'].values) : 
    print("There is no such user with this UserID. Please enter a different UserID.") 
elif (~df_data['CategoryID'].str.contains(var_catid).any()) : 
    print("There is no such category with this CategoryID. Please enter a different CategoryID") 
else: 
    ### I convert my date to datetime object to be able to do some operations with it. ### 
date = pd.to_datetime(var_date) 

s_all = df_data[df_data.columns[7]] 
s_all_datetime = pd.to_datetime(s_all) 
df_data['UTCtime'] = s_all_datetime 

min_date_str = "2012-04-03" 
min_date = pd.to_datetime(min_date_str) 
max_date_str = "2013-02-16" 
max_date = pd.to_datetime(max_date_str) 


if (date < min_date or date > max_date) : 
    print("There is noch such date. Please enter a different date from 2012-04-03 until 2013-02-16") 
else: 
    some code 

Ich weiß, Stackoverflow ist nicht für die Arbeit und in der Tat funktioniert mein Code. Könnten Sie doch zumindest ein paar Tipps geben, was schnellere Implementierungen wären? Der Datenrahmen hat 230k Zeilen und es ist natürlich nicht der beste Weg, wenn mein Programm mit jeder if-Klausel darüber laufen muss.

Ich dachte, ich könnte z. die eindeutigen Werte meiner UserID Spalte, speichern Sie es in einer Liste und überprüfen Sie es mit meiner if-Klausel. Aber

df_data['UserID'].unique.tolist() 

funktioniert nicht.

Danke für jede Hilfe.

/EDIT: Hier ist df_data.info() und df_data.head()

<class 'pandas.core.frame.DataFrame'> 
RangeIndex: 227428 entries, 0 to 227427 
Data columns (total 8 columns): 
UserID   227428 non-null int64 
VenueID   227428 non-null object 
CategoryID  227428 non-null object 
CategoryName  227428 non-null object 
Latitude   227428 non-null float64 
Longitude   227428 non-null float64 
TimezoneOffset 227428 non-null int64 
UTCtime   227428 non-null object 
dtypes: float64(2), int64(2), object(4) 
memory usage: 13.9+ MB 
None 

Kopf:

UserID     VenueID    CategoryID   CategoryName Latitude Longitude TimezoneOffset       UTCtime 
0  470 49bbd6c0f964a520f4531fe3 4bf58dd8d48988d127951735 Arts & Crafts Store 40.719810 -74.002581   -240 Tue Apr 03 18:00:09 +0000 2012 
1  979 4a43c0aef964a520c6a61fe3 4bf58dd8d48988d1df941735    Bridge 40.606800 -74.044170   -240 Tue Apr 03 18:00:25 +0000 2012 
2  69 4c5cc7b485a1e21e00d35711 4bf58dd8d48988d103941735  Home (private) 40.716162 -73.883070   -240 Tue Apr 03 18:02:24 +0000 2012 
3  395 4bc7086715a7ef3bef9878da 4bf58dd8d48988d104941735  Medical Center 40.745164 -73.982519   -240 Tue Apr 03 18:02:41 +0000 2012 
4  87 4cf2c5321d18a143951b5cec 4bf58dd8d48988d1cb941735   Food Truck 40.740104 -73.989658   -240 Tue Apr 03 18:03:00 +0000 2012 
+0

Könnten Sie vielleicht 'df_data.info()' und 'df.head()' posten, um das Beispiel der Quelldaten zu sehen? – aldanor

+0

Sie können es einfach so überprüfen 'df_data [(df_data ['UserID'] == var_uid) & (df_data ['KategorieID'] == var_catid)]' – MaxU

+0

Danke für die Antwort. Aber wenn ich '' if (df_data [(df_data ['UserID']! = Var_uid)]) schreibe: '' Ich bekomme einen Fehler wegen mehrdeutiger Wahrheitswerte. – Paprikamann

Antwort

1

Betrachten Lookup-Indizes zu erstellen, erhalten Sie log-Speed-Zugang. Hier ein Beispiel:

import pandas as pd 
import numpy as np 

n = int(1e6) 
np.random.seed(0) 
df = pd.DataFrame({ 
    'uid': np.arange(n), 
    'catid': np.repeat('foo bar baz', n), 
}) 

Die langsamere Version:

>>> %timeit for i in range(n // 2, n // 2 + 1000): i in df.uid.values 
1 loop, best of 3: 2.32 s per loop 

Allerdings können Sie den Index-pre berechnen:

>>> uids = pd.Index(df.uid.values) 
>>> %timeit for i in range(n // 2, n//2 + 1000): i in uids 
1000 loops, best of 3: 412 µs per loop 

Whoah, das ist schnell. Mal sehen, wie lange es dauert, um den Index zu erstellen:

>>> %timeit uids = pd.Index(df.uid.values) 
10000 loops, best of 3: 22.5 µs per loop 

Sie auch set verwenden könnte (obwohl für ints wie UserID seiner schnelleren Pandas Index verwenden), z.B. für CategoryID könnten Sie precompute:

>>> catids = set(s for catid in df.catid.values for s in catid.split()) 

und dann

>>> catid in catids 

überprüfen, die viel schneller sein wird.

+0

Danke! Ihre Antwort ist die vollständigste. – Paprikamann

1

Was meinst du mit

Aber df_data [ 'UserID'] unique.tolist (.) funktioniert nicht.

?

Meinst du, der Befehl schlägt fehl? Das ist wahrscheinlich, weil einzigartig ist eine Funktion, müssen Sie es anrufen

df_data['UserID'].unique().tolist() 

Oder meinst du es ist immer noch zu langsam? In diesem Fall möchten Sie wahrscheinlich keine Python-Liste verwenden, da sie immer noch über jeden Eintrag gehen muss. Wenn Sie stattdessen einen Satz verwenden, haben Sie die Worst-Case-O-Abrufzeit (logn). So

set(df['UserID'].tolist()) 

Jetzt macht, dass der Benutzer schneller nach oben, aber wenn die Kategorien auf ihnen etwas komplexere genannt brauchen (wie str.contains), werden Sie noch über die Liste zu gehen. Aber wenn Kategorien eine viel kleinere Kardinalität haben, könnten Sie wahrscheinlich nur einmal darauf anwenden und mit der kleineren Liste umgehen.

1

Für diese Art von Eindämmungs Kontrollen sollten Sie Benutzer (und Kategorie) einen Index machen:

if (~var_uid in df_data['UserID'].values) : 

elif (~df_data['CategoryID'].str.contains(var_catid).any()) : 

einmal diese sind im Index (Hinweis: Dies sollte außerhalb dieses Blockes durchgeführt wird, nicht jedes Mal) :

user_id in df.index.levels[0] 
category_id in df.index.levels[1] # granted this doesn't do the str contains (but that'll always be inefficient) 

:

df = df_data.set_index(["UserId", "CategoryID"]) 

dann können Sie in O (1) nachschlagen 210

Sie können diese manuell erstellen, wieder müssen Sie diese einmal eher zu tun haben, als für jede Referenz, um den Nutzen zu erhalten:

pd.Index(df_date["UserID"]) 
# if lots of non-unique users this will be more space efficient 
pd.Index(df_date["UserID"].unique()) 
0

Vielen Dank an alle Mitwirkenden! Für meine UserID habe ich die Lösung mit der Einstellung als Index verwendet. Für meine CategoryID habe ich das Set erstellt und in meinem Programm gespeichert.

Plus fand ich eine andere Engpass, der noch schlimmer war:

s_all = df_data[df_data.columns[7]] 
s_all_datetime = pd.to_datetime(s_all) 
df_data['UTCtime'] = s_all_datetime 

Es wandelt meine 'UTCtime' Spalte Datetime-Objekte ... 230k Iterationen mit ihm ... ^^ ich es nur einmal gemacht und gespeichert der neue Datenrahmen jetzt. Muss die .csv jedes Mal laden, aber das ist viel schneller.

Verwandte Themen