Как обрабатывать метаданные, связанные с кадром данных pandas?

Вопрос 1. Как лучше всего сохранять метаданные в фрейме данных? Я знаю о следующей практике кодирования

import pandas as pd
df = pd.DataFrame([])
df.currency = 'USD'
df.measure = 'Price'
df.frequency = 'daily'

Но, как указано в этом сообщении Добавление метаинформации/метаданных в pandas DataFrame это связано с риском потери информации при применении таких функций, как groupby, pivot, join или loc, поскольку они могут возвращать новый DataFrame без прикрепленных метаданных.

Это все еще действует или за это время произошло обновление обработки метаинформации? Является ли хорошей практикой кодирования подкласс панд для этой цели?

Вопрос 2. Что может быть альтернативной практикой написания кода?

Я не думаю, что строительство отдельного объекта очень подходит. Также работа с Multiindex меня не убеждает. Допустим, я хочу разделить фрейм данных с ценами на фрейм данных с прибылью. Работа с мультииндексами будет очень сложной.

#define price DataFrame
p_index = pd.MultiIndex.from_tuples([['Apple', 'price', 'daily'],['MSFT', 'price', 'daily']])
price = pd.DataFrame([[90, 20], [85, 30], [70, 25]], columns=p_index)

# define earnings dataframe
e_index = pd.MultiIndex.from_tuples(
    [['Apple', 'earnings', 'daily'], ['MSFT', 'earnings', 'daily']])
earnings=pd.DataFrame([[5000, 2000], [5800, 2200], [5100, 3000]], 
                columns=e_index)

price.divide(earnings.values, level=1, axis=0)

В приведенном выше примере я даже не гарантирую, что индексы компаний действительно совпадают. Мне, вероятно, нужно будет вызвать pd.DataFrame.reindex() или аналогичный. С моей точки зрения, это не может быть хорошей практикой кодирования.

Есть ли простое решение проблемы обработки метаинформации в этом контексте, которого я не вижу?

заранее спасибо


person quantguy    schedule 28.09.2016    source источник


Ответы (2)


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

df=pd.DataFrame({'stock': 'AAPL AAPL MSFT MSFT'.split(),
                 'price':[ 445.,455.,195.,205.]})

col_labels = { 'stock' : 'Ticker Symbol',
               'price' : 'Closing Price in USD' }

Это просто словарь меток столбцов, но часто большая часть метаданных связана с конкретными столбцами. Вот пример данных с метками:

df.rename(columns=col_labels)

#   Ticker Symbol  Closing Price in USD
# 0          AAPL                 445.0
# 1          AAPL                 455.0
# 2          MSFT                 195.0
# 3          MSFT                 205.0

Приятно то, что метки сохраняются в том смысле, что вы можете применять их к любым данным, столбцы которых являются подмножеством или надмножеством исходных столбцов:

df.groupby('stock').mean().rename(columns=col_labels)

#        Closing Price in USD
# stock                      
# AAPL                  450.0
# MSFT                  200.0

Вы можете получить некоторое ограниченное постоянство, если используете атрибут attrs:

df.attrs = col_labels

Но он достаточно ограничен. Он будет сохраняться для фреймов данных, полученных через .copy(), loc[] или iloc[], но не для groupby(). Конечно, вы можете снова подключиться к любому производному фрейму данных, например,

df2.attrs = df.attrs

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

person JohnE    schedule 11.08.2020

Я думаю, что MultiIndexes - это то, что нужно, но вот так:

daily_price_data = pd.DataFrame({'Apple': [90, 85, 30], 'MSFT':[20, 30, 25]})
daily_earnings_data = pd.DataFrame({'Apple': [5000, 58000, 5100], 'MSFT':[2000, 2200, 3000]})
data = pd.concat({'price':daily_price_data, 'earnings': daily_earnings_data}, axis=1)
data


    earnings        price
    Apple   MSFT    Apple   MSFT
0   5000    2000    90      20
1   58000   2200    85      30
2   5100    3000    30      25

Затем, чтобы разделить:

data['price'] / data['earnings']

Если вы обнаружите, что ваш рабочий процесс имеет больше смысла, если компании перечислены на первом уровне индекса, тогда pandas.DataFrame.xs будет очень полезен:

data2 = data.reorder_levels([1,0], axis=1).sort_index(axis=1)
data2.xs('price', axis=1, level=-1) / data2.xs('earnings', axis=1, level=-1)
person Gordon Bean    schedule 28.09.2016