Pandas датафрейм из dict, почему? - PullRequest
2 голосов
/ 01 апреля 2020

Я могу создать pandas фрейм данных из dict следующим образом:

d = {'Key':['abc','def','xyz'], 'Value':[1,2,3]}
df = pd.DataFrame(d)
df.set_index('Key', inplace=True)

А также, сначала создав серию, подобную этой:

d = {'abc': 1, 'def': 2, 'xyz': 3}
a = pd.Series(d, name='Value')
df = pd.DataFrame(a)

Но не прямо так:

d = {'abc': 1, 'def': 2, 'xyz': 3}
df = pd.DataFrame(d)

Мне известен метод from_dict, и это также дает желаемый результат:

d = {'abc': 1, 'def': 2, 'xyz': 3}
pd.DataFrame.from_dict(d, orient='index')

, но я не понимаю, почему:

(1) требуется отдельный метод для создания информационного кадра из dict, когда создание из серии или списка работает без проблем;

(2) как / почему создание информационного кадра из dict / списка списков работает, но не создавая из диктата напрямую.

Нашли несколько ответов SE, которые предлагают решения, но искали «почему» , так как это поведение кажется несовместимым. Может кто-нибудь пролить свет на то, чего мне здесь не хватает.

1 Ответ

1 голос
/ 01 апреля 2020

Здесь на самом деле происходит много всего, поэтому давайте разберем его.


Проблема

Существует так много разных способов создать DataFrame (из списка records, dict, csv, ndarray, et c ...), что даже для python ветеранов может потребоваться много времени, чтобы понять их всех. Черт, в каждом из этих способов есть ДАЖЕ БОЛЬШЕ способов построить DataFrame путем настройки некоторых параметров и еще много чего.

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

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

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


Решение

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

  1. Создать только один конструктор, который проверяет ввод и обрабатывает его соответствующим образом, охватывая все возможные варианты , Это может стать очень раздутым и сложным, когда определенные входные данные имеют свои собственные параметры / параметры и когда их просто слишком много.
  2. Разделите каждую опцию на @classmethod, чтобы обрабатывать каждый конкретный c индивидуальный способ Построение объекта.

Второе, как правило, лучше, так как оно действительно обеспечивает разделение проблем как принцип проектирования SE, однако пользователю необходимо знать все различные @classmethod конструктор вызывает в результате. Хотя, по моему мнению, если ваш объектный класс достаточно сложен, чтобы иметь много различных вариантов построения, пользователь должен знать об этом в любом случае.


Путь Panda

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

Например, для dicts, по умолчанию, если вы передать dict в конструктор DataFrame, он будет обрабатывать его как Case 1 . Если вы хотите выполнить второй случай, вам нужно будет использовать DataFrame.from_dict и передать orient='index' (без orient='index', будет использоваться поведение по умолчанию, описанное в base Case 1 ).

По-моему, я не фанат такого рода реализации. Лично это больше сбивает с толку, чем полезно. Честно говоря, многие pandas разработаны так. Есть причина, по которой pandas является топи c каждого другого вопроса python с тегами stackoverflow.

...