Доступ к строкам и столбцам в одном и том же DataFrame dtype - PullRequest
2 голосов
/ 08 марта 2019

Я немного удивлен, что для уникального d-типа DataFrame (nxn dataFrame) доступ к строке медленнее, чем к столбцу.Исходя из того, что я собираю, DataFrame идентичного dtype должен храниться как непрерывный блок в памяти, поэтому доступ к строкам или столбцам должен быть одинаково быстрым (просто вопрос обновления правильного шага).

Пример кода:

df = pd.DataFrame(np.random.randn(100, 100))

%timeit df[0]
%timeit df.loc[0]

Самый медленный пробег длился в 12,86 раз дольше, чем самый быстрый.Это может означать, что промежуточный результат кэшируется.

100000 loops, best of 3: 2.72 µs per loop
10000 loops, best of 3: 116 µs per loop    

Я определенно не очень хорошо понимаю, как хранится dataFrame, спасибо за вашу помощь!

Ответы [ 2 ]

0 голосов
/ 08 марта 2019

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

Насколько я понимаю, структура данных Pandas наиболее непосредственно сопоставима со словарем словарей, где первый индекс - это столбцы. Таким образом, ДФ:

   a b
 c 1 2
 d 3 4

по существу {'a': {'c': 1, 'd': 3}, 'b': {'c': 2, 'd': 4}}. Я предполагаю, что с этого момента я прав в этом утверждении, и хотел бы, чтобы его поправили, если кто-то знает больше о пандах.

Таким образом, индексирование столбца является простым поиском по хешу, тогда как индексирование строки требует итерации по всем столбцам и выполнения поиска по хешу для каждого.

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

0 голосов
/ 08 марта 2019

Если вы посмотрите на базовый массив numpy, вы увидите, что скорость доступа к строкам / столбцам одинакова, по крайней мере, в моем тесте:

%timeit df.values[0]
# 10.2 µs ± 596 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit df.values[:, 0]
# 10.2 µs ± 730 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

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

Вот еще одно сравнение по времени:

%timeit df.iloc[0, :]
# 141 µs ± 7 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit df.iloc[:, 0]
# 61.9 µs ± 1.76 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Доступ к столбцам также происходит быстрее, хотя и значительно медленнее. Я не уверен, что это объяснит. Я предполагаю, что замедление по сравнению с доступом к строке / столбцу напрямую связано с необходимостью возврата pd.Series. При доступе к строке, возможно, потребуется создать новый pd.Series. Но я не знаю, почему iloc медленнее и для столбцов - возможно, он также каждый раз создает новую серию, поскольку iloc может использоваться довольно гибко и может не возвращать существующую серию (или может возвращать фрейм данных). Но если новая серия создается оба раза, то я снова в недоумении, почему одна операция превосходит другую.

И для большей полноты

%timeit df.loc[0, :]
# 155 µs ± 6.48 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit df.loc[:, 0]
# 35.6 µs ± 1.28 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...