#python #pandas #dataframe
#python #pandas #фрейм данных
Вопрос:
Я устал от панд и фреймов данных.
У меня есть один фрейм данных (именованный data
) с двумя столбцами ( userid
, date
). У меня есть второй фрейм данных, incidence_matrix
, где строки — это userid
s (те же userid
s в данных), а столбцы — даты (те же даты в data
). Вот как я создаю incidence_matrix
:
columns = pd.date_range(start='2020-01-01', end='2020-11-30', freq='M', closed='right')
index = data['USERID']
incidence_matrix = pd.DataFrame(index=index, columns=columns)
incidence_matrix = incidence_matrix.fillna(0)
Я пытаюсь выполнить итерацию по каждой userid
паре ( date
,) data
и, используя значения каждого идентификатора пользователя и даты, обновите соответствующую ячейку, incidence_matrix
чтобы она была равна 1.
В производстве data
могут быть миллионы строк. Поэтому я бы предпочел не перебирать данные и использовать подход векторизации.
Как можно (или нужно) выполнить вышеуказанное?
Я сталкиваюсь с ошибками при попытке ссылаться на ячейки по имени, например, в моей попытке ниже, первый оператор печати работает, но второй оператор печати не распознает значение даты в качестве метки
for index, row in data.iterrows():
print(row['USERID'], row['POSTDATE'])
print(incidence_matrix.loc[row['USERID']][row['POSTDATE']])
Заранее благодарю вас.
Комментарии:
1. похоже
get_dummies()
, что ( Docs ) в data df решает вашу проблему. У него не будет всех возможных значений даты, если это имеет значение для вас. Но должно быть достаточно простой адаптацией
Ответ №1:
Предупреждение: выбранное вами представление в реальной жизни будет довольно редким (посещения пользователей обычно следуют закону Zipf), что приводит к довольно неэффективному использованию памяти. Вам было бы лучше представлять свою частоту как высокую и тонкую DataFrame
, например, вывод:
data.groupby(['userid', data['date'].dt.to_period('M')]).count()
С учетом этого предостережения:
def add_new_data(data, incidence=None):
delta_incidence = (
data
.groupby(['userid', data['date'].dt.to_period('M')])
.count()
.squeeze()
.unstack('date', fill_value=0)
)
if incidence is None:
return delta_incidence
return incidence.combine(delta_incidence, np.add, fill_value=0).astype(int)
должен делать то, что вы хотите. Он повторно индексирует предыдущее значение incidence
(если таковое имеется), так что результатом является новое DataFrame
, где оси являются объединением incidence
и delta_incidence
.
Вот игрушечный пример для тестирования:
def gen_data(n):
return pd.DataFrame(
dict(
userid=np.random.choice('bob alice john james sophia'.split(), size=n),
date=[
(pd.Timestamp('2020-01-01') v * pd.Timedelta('365 days')).round('s')
for v in np.random.uniform(size=n)
],
)
)
# first time (no previous incidence)
data = gen_data(20)
incidence = add_new_data(data)
# new data arrives
data = gen_data(30)
incidence = add_new_data(data, incidence)
Комментарии:
1. @pierre_d очень интересно. Спасибо. погрузитесь в некоторые детали этого и опубликуйте здесь любые последующие вопросы.