2013-10-02 4 views
2

У меня есть большой набор данных о пометке музыки в базе данных MySQL, которую я пытаюсь проанализировать с помощью pandas. Я экспортировал его в .tsv из MySQL и теперь читаю его в виде dataframe для анализа.Усреднение по разным уровням в пандах

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

 uid artist tag  date 
0 2096963  559 46 2005-07-01 
1 2096963  584 1053 2005-07-01 
2 2096963  584 2044 2005-07-01 
3 2096963  584 2713 2005-07-01 
4 2096963  596 236 2005-07-01 
... 
     uid artist tag  date 
99995 2656262 8095 57 2005-08-01 
99996 2656262 8095 79 2005-08-01 
99997 2656262 8095 4049 2005-08-01 
99998 2656262 8095 8290 2005-08-01 
99999 2610168 8095 1054 2005-08-01 

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

data = pd.read_table(filename,header=None, names=('uid','artist','tag','date'), index_col=['date','uid','artist','tag'], parse_dates='date') 
data['annotations'] = 1 

In [41]: data.head() 
Out[41]: 
           annotations 
date  uid  artist tag 
2005-07-01 2096963 559 46    1 
        584 1053   1 
          2044   1 
          2713   1 
        596 236    1 
... 

С данными, отформатированными следующим образом, тривиально рассчитать простые распределения частот. Например, если я хочу, чтобы определить, сколько раз каждый пользователь меченых что-то (. В порядке убывания частота заказа), это так же просто, как:

data.sum(level='uid').sort('anno',ascending=False) 

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

data.sum(level='date') 

Но у меня возникают проблемы с более сложными вычислениями. В частности, Что делать, если я хочу, чтобы среднее количество аннотаций на пользователя каждый месяц? Если я позвоню:

data.sum(level=['date','uid']).head() 

я получаю количество аннотаций на одного пользователя в месяц, т.е .:

    anno 
date  uid 
2005-07-01 1040740 10 
      1067454 23 
      2096963 136 
      2115894  1 
      2163842  4 
... 

но что простой способ затем получить среднемесячный этих значений через пользователей? То есть, для каждого месяца, что среднее между пользователями столбца «anno»? У меня есть разные показатели, такие как я хочу рассчитать, поэтому я надеюсь, что решение будет обобщено.

ответ

1

я понял, альтернативный подход, который соответствует своему оригинальному формату многоиндексного, и я думаю, что быстрее, чем метод, предложенный @DanAllan.

Вспоминая, что мы вычисляем средние аннотации для каждого пользователя в месяц, давайте построим два фрейма данных (я использую только подмножество данных здесь, следовательно, аргумент nrows). data1 имеет версию мультииндекса с фиктивными переменным, и data2 является неиндексированной версией, предложенной @DanAllan

indexes=['date','uid','artist','iid','tag'] 
data1 = pd.read_table(filename,header=None, nrows=1000000, names=('uid','iid','artist','tag','date'),index_col=indexes, parse_dates='date') 
data['anno']=1 
data2 = pd.read_table(filename,header=None, nrows=1000000, names=('uid','iid','artist','tag','date'), parse_dates='date') 

С (без индекса data2) версии процесса:

daily_users = data2.groupby('date').uid.nunique() 
daily_annotations = data2.groupby('date').count().uid 
anno_per_user_perday2 = daily_annotations/daily_users.map(float) 

С мульти- индекс версия (data1), мы можем сделать:

anno_per_user_perday = data1.sum(level=['date','uid']).mean(level='date').anno 

результат точно таким же, но более чем в два раза быстрее с индексированной версией (производительность будет больше проблем с полным, 50 ми Ллион строка набора данных):

%timeit -n100 daily_users = data2.groupby('date').uid.nunique() ; daily_annotations = data2.groupby('date').count().uid ; anno_per_user_perday2 = daily_annotations/daily_users.map(float) 
100 loops, best of 3: 387 ms per loop 

%timeit -n100 anno_per_user_perday1 = data1.sum(level=['date','uid']).mean(level='date').anno 
100 loops, best of 3: 149 ms per loop 

Генерация dataframe медленнее с индексированной версии, но гибкость, которую он дает, кажется, стоит.

2

Большой MultiIndexes может быть хлопот. Я предлагаю отказаться от вашей фиктивной колонки, «аннотации» и использовать count вместо sum.

Для начала чтения в данных без присвоения индекса, т.е.

pd.read_table(filename,header=None, names=['uid','artist','tag','date'], parse_dates='date') 

Для подсчета аннотаций каждого пользователя:

data.groupby('uid').count().sort(ascending=False) 

к общему аннотаций в день:

data.groupby('date').count() 

Количество уникальных пользователей каждый день:

daily_users = data.groupby('date').uid.nunique() 

В общих аннотациях каждый день:

daily_annotations = data.groupby('date').count() 

Среднесуточные аннотации для каждого пользователя есть только ежедневные общие аннотации, деленные на количестве пользователей в этот день. В результате операции groupby обе эти серии индексируются по дате, поэтому они будут выровнены автоматически.

mean_daily_annotations_per_user = daily_annotations/daily_users 

В среднем аннотаций в месяц через пользователей, наиболее удобно использовать resample, хорошая функция для группировки различных временных частот.

mean_monthly_annotations_per_user = mean_daily_anootations_per_user.resample('M') 
+0

Я хотел попробовать с повторной выборкой с самого начала, но это не кажется работой (по крайней мере, не так, как вы описали). С «датой» в качестве индекса переэмплинг с «средним» просто вычисляет среднее арифметическое всех числовых идентификаторов для исполнителя, тега и пользователя каждый месяц (что бессмысленно), а не среднее количество аннотаций на пользователя. С другой стороны, «Count» дает общее количество строк за каждый месяц, что также неверно. Мне нужно среднее количество аннотаций (строк) для каждого пользователя, каждый месяц. – moustachio

+0

Я редактировал это, потому что изначально неправильно понял ваш вопрос. Пожалуйста, прочитайте еще раз. Я думаю, что у меня все получилось прямо сейчас. –

+0

Гораздо лучше, но единственная проблема заключается в том, что определение daily_annotations должно вытащить определенный столбец, иначе вы не сможете выполнить деление (поскольку вы определили его daily_annotations - это dataframe, но daily_users - это серия. произвольный какой столбец вы выбираете, насколько я могу судить. Редактирование и принятие ответа – moustachio

Смежные вопросы