2015-05-29 2 views
29

Я делаю некоторые упражнения с наборами данных, как так:Список со многими словарями VS с несколькими списками?

Список со многими словарями

users = [ 
    {"id": 0, "name": "Ashley"}, 
    {"id": 1, "name": "Ben"}, 
    {"id": 2, "name": "Conrad"}, 
    {"id": 3, "name": "Doug"}, 
    {"id": 4, "name": "Evin"}, 
    {"id": 5, "name": "Florian"}, 
    {"id": 6, "name": "Gerald"} 
] 

словарь с несколькими списками

users2 = { 
    "id": [0, 1, 2, 3, 4, 5, 6], 
    "name": ["Ashley", "Ben", "Conrad", "Doug","Evin", "Florian", "Gerald"] 
} 

Панды dataframes

import pandas as pd 
pd_users = pd.DataFrame(users) 
pd_users2 = pd.DataFrame(users2) 
print pd_users == pd_users2 

Вопросы:

  1. Должен ли я структурировать наборы данных, как пользователи или как потребляющие2?
  2. Существуют ли отличия в производительности?
  3. Является ли еще более удобочитаемым, чем другим?
  4. Есть ли стандарт, которому я должен следовать?
  5. Обычно я конвертирую их в dataframes pandas. Когда я это делаю, обе версии идентичны ... правильно?
  6. Выходные данные верны для каждого элемента, поэтому не имеет значения, правильно ли я работаю с panda df?
+5

Хорошие вопросы Я пойду с первым вариантом, потому что я Recon поиск и вставка будет менее утомительным по сравнению с второй – therealprashant

+4

Я бы пошел с первым, пока удобство использования является самым важным аспектом. Наличие идентификатора вместе с NAME будет удобно при перемещении. –

+3

Первая версия легко сортируется, а вторая - нет. –

ответ

24

Это относится к column oriented databases против ряда ориентированных. Ваш первый пример - структура данных, ориентированная на строки, а вторая - ориентированная на столбцы. В частном случае Python первое может быть сделано значительно более эффективно с использованием slots, так что словарь столбцов не нужно дублировать для каждой строки.

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

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

Существует третий вариант, не очевидный в вашем примере: в этом случае у вас есть только два столбца, один из которых представляет собой целочисленный идентификатор в смежном диапазоне от 0. Это может быть сохранено в порядке самих записей, что означает, что вся структура будет найдена в списке, который вы назвали users2['name']; но, в частности, записи неполны без их положения. Список переводится в строки, используя enumerate(). Для баз данных также часто используется этот особый случай (например, sqlite rowid).

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

+0

Пример использования 'слотов' для сохранения памяти: http://tech.oyster.com/save-ram-with-python-slots/ –

4

users В целом, на самом деле это коллекция из user элементов. Поэтому лучше определить элемент user как автономный объект. Таким образом, ваш первый вариант правильный.

5

Временная сложность для поисков в -

  • List - O (п)
  • Dicts - O (1)

Но это не мешало бы много, если ваш ISN данные» что большие, а также современные процессоры достаточно эффективны.
Вы должны пойти с тем, в котором поиск синтаксически чист и читабель (читаемость имеет значение).
Первый вариант вполне уместен, так как переменная представляет собой коллекцию пользователей (которым присвоен идентификатор), а вторая - просто коллекция имен пользователей и идентификаторов.

+1

«Вы должны пойти с тем, в котором поиск синтаксически чист и читабель» +1. Но я не думаю, что сложность времени имеет значение, поскольку мы не знаем, как он обращается к этим данным. –

6

Пользователей

  1. Когда вам нужно добавить некоторый новый пользователь просто сделать новый dict всех деталей пользователя и добавить его

  2. легко сортируется, как @StevenRumbalski предложил

  3. Поиск будет легким

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

потребляющие2

  1. Лично я вижу это в первый раз, и я бы не приблизился к этому, если у меня было большое количество записей.

PS: Но я хотел бы узнать преимущества users2 над users Опять хороший вопрос

1

Первый вариант списка словарей будет намного лучше по нескольким причинам. В списке содержатся такие методы, как EXTEND, APPENT, PUSH, которые не всегда доступны со словарями.

4

Некоторые ответы относительно панд аспекта:

  1. Оба dataframes действительно являются одинаковыми и столбец ориентированной, что это хорошо, потому что панды работает лучше всего, когда данные в каждом столбце однородны (то есть числа, могут быть сохранены в виде ints и floats). Основной причиной использования панд в первую очередь является то, что вы можете делать векторизованные числовые операции, которые на порядок быстрее, чем чистый питон, но это зависит от столбчатой ​​организации, когда данные имеют гетерогенный тип.
  2. Вы можете сделать pd_users.T, если хотите, и затем увидите (через или dtypes), что все затем сохраняется как объект общего назначения, потому что столбец содержит как строки, так и числа.
  3. После преобразования вы можете сделать pd_users.set_index('id') так, чтобы ваш dataframe был по существу словарем с id как ключи. Или наоборот: name.
  4. Это довольно распространенный (и в целом довольно быстрый), чтобы изменить индексы, а затем изменить их обратно, транспонировать, подмножество и т. Д. При работе с пандами, поэтому обычно не нужно слишком много думать о структуре в начале. Просто измените его, как вам нужно «на лету».
  5. Возможно, это может касаться касательной, но более простой аналог панды из того, что у вас выше, может быть Series, а не DataFrame. Ряд по существу является столбцом кадра данных, хотя на самом деле это всего лишь одномерный массив данных с индексом («ключи»).

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

>>> df.set_index('name') 

     id 
name  
Ashley 0 
Ben  1 
Conrad 2 
Doug  3 
Evin  4 
Florian 5 
Gerald 6 

>>> df.set_index('name').T 

name Ashley Ben Conrad Doug Evin Florian Gerald 
id   0 1  2  3  4  5  6 

>>> df.set_index('name').loc['Doug'] 

id 3 
Name: Doug, dtype: int64 
+0

Эй! Вы упомянули, что оба кадра данных ориентированы на столбцы. Самый верный ответ прямо сейчас предполагает, что один из них - столбец, а другой - строка. Можешь подтвердить? – megashigger

+1

Я считаю, что @YannVernier ссылается только на случай * перед * преобразованием в pandas. Вы уже доказали, что они одинаковы с 'pd_users == pd_users2'. Но вы можете сделать 'pd_users == pd_users2.T' (поместить транспонирование на одну из них) для дальнейшей проверки. Это вызовет исключение, потому что два кадра данных больше не соответствуют. Помимо проверки на равенство, просто печать кадра данных показывает, как pandas структурирует данные в терминах строк и столбцов. – JohnE

+0

Ах, это имеет смысл. Спасибо за разъяснения. – megashigger

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