2016-05-26 2 views
1

У меня есть код, который имеет userID, categoryID и date в качестве входных значений. Я хочу проверить, действительны ли записи, например. если userID действительно существует в моем наборе данных. Он работает так, как я это делаю, но мне нужно подождать несколько секунд (!), Пока не будет выполнена основная программа.Как сделать «значение в столбце даты» быстрее

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 

Я знаю, stackoverflow не для выполнения работы, и на самом деле мой код работает. Тем не менее, могли бы вы хотя бы дать какие-то намеки на то, что было бы более быстрыми реализациями? В DataFrame есть строки 230 тыс., И это, конечно, не самый лучший способ, если моя программа должна работать над ним при каждом условии if.

Я думал, что могу извлечь, например. уникальные значения моего столбца UserID, сохраните его в списке и проверьте его с помощью предложения if. Но

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

не работает.

Спасибо за любую помощь.

/EDIT: Вот df_data.info() и 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 

Руководитель:

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

Не могли бы вы опубликовать 'df_data.info()' и 'df.head()', чтобы увидеть пример исходных данных? – aldanor

+0

вы можете просто проверить это так: 'df_data [(df_data ['UserID'] == var_uid) & (df_data ['CategoryID'] == var_catid)]' – MaxU

+0

Спасибо за ответ. Но если я напишу '' if (df_data [(df_data ['UserID']! = Var_uid)]: '' Я получаю сообщение об ошибке из-за неоднозначных значений истинности. – Paprikamann

ответ

1

Рассмотрим создание индексов поиска, то вы получите доступ к лог-скорости. Вот пример:

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), 
}) 

Медленнее версия:

>>> %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 

Однако вы можете предварительно вычислить индекс:

>>> 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, это быстро. Давайте посмотрим, как долго это берет, чтобы создать индекс:

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

Вы можете также использовать set (хотя для Интс как UserID его быстрее использовать панд Index), например, для CategoryID можно предвычисления:

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

, а затем проверить

>>> catid in catids 

, которая собирается быть намного быстрее.

+0

Спасибо! Ваш ответ является наиболее полным. – Paprikamann

1

Что вы имеете в виду

Но df_data [ 'UserID'] unique.tolist (.) не работает.

?

Вы имеете в виду команду не работает? Вероятно, это уникальная функция, вы должны называть ее

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

Или вы имеете в виду ее еще слишком медленно? В этом случае вы, вероятно, не хотите использовать список python, так как ему все равно придется перебирать каждую запись. Если вместо этого вы используете набор, вы получите наихудшее время вывода O (logn). Так

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

Теперь, когда делает поиск пользователя быстрее, но если категориям нужно что-то более сложное, называемое на них (как str.contains), вам все равно нужно идти по списку. Но если категории имеют гораздо меньшую мощность, вы, вероятно, могли бы просто применить к ней уникальный и иметь дело с меньшим списком.

1

Для таких удерживающих проверок вы должны сделать пользователь (и Категория) индекс:

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

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

когда они находятся в индексе (Примечание: это должно быть сделано за пределами этого блока, а не каждый раз) :

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

, то вы можете посмотреть в O (1):

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) 

Вы можете создать их вручную, вы снова должны иметь, чтобы сделать это раз, а не для каждого запроса, чтобы получить выгоду:

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

Большое спасибо всем участникам! Для моего UserID я использовал решение, установив его как индекс. Для моего CategoryID я создал набор и сохранил его в моей программе.

Плюс, я нашел еще узкое место, которое было еще хуже:

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

Он преобразует мой 'UTCtime' столбец объектов даты и времени ... 230K итераций с ним ... ^^ я просто сделал это один раз и хранить теперь новый кадр данных. Просто нужно каждый раз загружать .csv, но это намного быстрее.