Numpy и Pandas используют разные алгоритмы для isin
. В некоторых случаях версия Numpy быстрее, а для некоторых панд. Для вашего теста NumPy кажется быстрее.
Версия Pandas, однако, имеет лучшее асимптотическое время выполнения, она выиграет для больших наборов данных.
Предположим, что в серии данных есть n
элементов (в вашем примере df
) и в запросе m
(в вашем примере vals
).
Обычно алгоритм Numpy выполняет следующие действия:
np.unique(..)
, чтобы найти все уникальные элементы в ряду. Таким образом, выполняется сортировка, т. Е. O(n*log(n))
, может быть N<=n
уникальных элементов. O(m*log(N))
в целом. Что приводит к общему времени работы O(n*log(n) + m*log(N))
.
Существуют некоторые жестко запрограммированные оптимизации для случаев, когда vals
только несколько элементов, и для этих случаев действительно блестит numpy.
Панды делают что-то другое:
khash
-функция), чтобы найти все уникальные элементы, которая занимает O(n)
. O(1)
для каждого запроса, т. Е. O(m)
в целом. В целом, время работы составляет O(n)+O(m)
, что намного лучше, чем у Нампи.
Однако, для меньших входных данных постоянные факторы, а не асимптотическое поведение - это то, что имеет значение, и это просто намного лучше для Numpy. Есть и другие соображения, такие как потребление памяти (которое выше у панд), которое может сыграть свою роль.
Но если мы возьмем больший набор запросов, ситуация будет совершенно другой:
import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.randint(0,10,(10**6),dtype='int8'),columns=['A'])
vals = np.array([5,7],dtype='int64')
vals2 = np.random.randint(0,10,(10**6),dtype='int64')
И теперь:
%timeit df['A'].isin(vals) # 17.0 ms
%timeit df['A'].isin(vals2) # 16.8 ms
%timeit pd.np.in1d(df['A'],vals) # 1.36
%timeit pd.np.in1d(df['A'],vals2) # 82.9 ms
Numpy действительно сдает позиции, пока есть больше запросы. Также можно видеть, что создание хеш-карты является узким местом для панд, а не для запросов.
В конце концов, не имеет большого смысла (даже если бы я это сделал!) Оценивать производительность только для одного размера ввода - это должно быть сделано для диапазона размеров ввода - есть некоторые сюрпризы, которые нужно обнаружить!
Например, Интересный факт: если вы возьмете
df = pd.DataFrame(np.random.randint(0,10,(10**6+1), dtype='int8'),columns=['A'])
, т.е. 10^6+1
вместо 10^6
, панды прибегнут к алгоритму numpy (который, на мой взгляд, не очень умен) и станут лучше для маленьких входов, но хуже для больших:
%timeit df['A'].isin(vals) # 6ms was 17.0 ms
%timeit df['A'].isin(vals2) # 100ms was 16.8 ms
Аналитический сценарий Google точно, в чем Вы нуждаетесь. Поскольку сессия, будет открываться для поисковых роботов также.
Я могу только предложение второго Gareth для использования уже доступного анализа трафика. Если Вам не нравится идея дать данные Google по трафику Вашего веб-сайта, можно также загрузить файлы журнала и проанализировать их с одним из многих аналитических доступных инструментов файла журнала веб-сервера.
Используйте Google Analytics. Не пытайтесь изобрести велосипед если a) колесо не делает то, что Вы хотите или b) Вы просто пытаетесь узнать, как колесо работает
Для наивной реализации можно использовать пользовательский HttpModule. Для каждого запроса к Вашему приложению Вы были бы:
Вот некоторый скелетный код ниже (сохраните как StatsCounter.cs):
using System;
using System.Data;
using System.Web;
using System.Web.Security;
using System.Transactions;
namespace hitcounter
{
public class StatsCounter : IHttpModule
{
// This is what we'll call our tracking cookie.
// Alternatively, you could read this from your Web.config file:
public const string TrackingCookieName = "__SITE__STATS";
#region IHttpModule Members
public void Dispose()
{ ;}
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
context.PreSendRequestHeaders += new EventHandler(context_PreSendRequestHeaders);
}
void context_PreSendRequestHeaders(object sender, EventArgs e)
{
HttpApplication app = sender as HttpApplication;
HttpResponse response = app.Response;
if (response.Cookies[TrackingCookieName] == null)
{
HttpCookie trackingCookie = new HttpCookie(TrackingCookieName);
trackingCookie.Expires = DateTime.Now.AddYears(1); // make this cookie last a while
trackingCookie.HttpOnly = true;
trackingCookie.Path = "/";
trackingCookie.Values["VisitorCount"] = GetVisitorCount().ToString();
trackingCookie.Values["LastVisit"] = DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss");
response.Cookies.Add(trackingCookie);
}
}
private long GetVisitorCount()
{
// Lookup visitor count and cache it, for improved performance.
// Return Count (we're returning 0 here since this is just a stub):
return 0;
}
void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication app = sender as HttpApplication;
HttpRequest request = app.Request;
// Check for tracking cookie:
if (request.Cookies[TrackingCookieName] != null)
{
// Returning visitor...
}
else
{
// New visitor - record stats:
string userAgent = request.ServerVariables["HTTP_USER_AGENT"];
string ipAddress = request.ServerVariables["HTTP_REMOTE_IP"];
string time = DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss");
// ...
// Log visitor stats to database
TransactionOptions opts = new TransactionOptions();
opts.IsolationLevel = System.Transactions.IsolationLevel.Serializable;
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, opts))
{
// Update visitor count.
// Invalidate cached visitor count.
}
}
}
#endregion
}
}
Зарегистрируйте этот модуль путем добавления следующих строк к файлу Web.config:
<?xml version="1.0"?>
<configuration>
...
<system.web>
...
<httpModules>
<add name="StatsCounter" type="<ApplicationAssembly>.StatsCounter" />
</httpModules>
</system.web>
</configuration>
(Замена названием Вашего проекта веб-приложения, или удаляют его, если Вы используете проект Веб-сайта.
Хотелось бы надеяться, этого будет достаточно для получения Вас, начал экспериментировать. Как другие указали, хотя для фактического сайта Вы - очень более обеспеченный Google использования (или некоторый другой) решение для аналитики для этого.