#python #pandas #dataframe #vectorization
#питон #панды #фрейм данных #векторизация
Вопрос:
У меня есть следующий фрейм данных с двумя столбцами c1
, и c2
я хочу добавить новый столбец c3
, основанный на следующей логике, то, что у меня есть, работает, но медленно, может ли кто-нибудь предложить способ векторизации этого?
- Должны быть сгруппированы на основе
c1
, аc2
затем для каждой группы новый столбецc3
должен заполняться последовательно, начиная сvalues
того места, где ключ является значениемc1
, и каждая «подгруппа» будет иметь последующие значения, IOWvalues[value_of_c1][idx]
, гдеidx
находится «подгруппа», пример ниже - Первая группа
(1, 'a')
, здесьc1
1
, индекс «подгруппы»"a"
0
равен (первая подгруппа 1), поэтомуc3
для всех строк в этой группеvalues[1][0]
- Вторая группа
(1, 'b')
здесьc1
все еще1
есть, но «подгруппа» —"b"
это индекс1
so (вторая подгруппа из 1), поэтому для всех строк в этой группеc3
values[1][1]
- Третья группа
(2, 'y')
здесьc1
теперь2
, «подгруппа»"a"
, и индекс0
(первая подгруппа из 2), поэтому для всех строк в этой группеc3
values[2][0]
- И так далее
values
будут иметь необходимые элементы, чтобы удовлетворить этой логике.
Код
import pandas as pd df = pd.DataFrame( { "c1": [1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2], "c2": ["a", "a", "a", "b", "b", "b", "y", "y", "y", "z", "z", "z"], } ) new_df = pd.DataFrame() values = {1: ["a1", "a2"], 2: ["b1", "b2"]} for i, j in df.groupby("c1"): for idx, (k, l) in enumerate(j.groupby("c2")): l["c3"] = values[i][idx] new_df = new_df.append(l)
Вывод (работает, но мой код работает медленно)
c1 c2 c3 0 1 a a1 1 1 a a1 2 1 a a1 3 1 b a2 4 1 b a2 5 1 b a2 6 2 y b1 7 2 y b1 8 2 y b1 9 2 z b2 10 2 z b2 11 2 z b2
Ответ №1:
Если вы не возражаете использовать другую библиотеку, вам в основном нужно кодировать надписи в своих группах:
from sklearn.preprocessing import LabelEncoder def le(x): return pd.DataFrame(LabelEncoder().fit_transform(x),index=x.index) df['idx'] = df.groupby('c1')['c2'].apply(le) df['c3'] = df.apply(lambda x:values[x['c1']][x['idx']],axis=1) c1 c2 idx c3 0 1 a 0 a1 1 1 a 0 a1 2 1 a 0 a1 3 1 b 1 a2 4 1 b 1 a2 5 1 b 1 a2 6 2 y 0 b1 7 2 y 0 b1 8 2 y 0 b1 9 2 z 1 b2 10 2 z 1 b2 11 2 z 1 b2
В противном случае это вопрос использования pd.Categorical
той же концепции , что и выше, просто вы преобразуете столбец в каждой группе в категорию и просто вытаскиваете код:
def le(x): return pd.DataFrame(pd.Categorical(x).codes,index=x.index)
Комментарии:
1. спасибо за альтернативное решение, я рассчитал это с помощью
pd.Categorical
предложения, и оно, похоже, быстрее, чем у меня есть2. пока я пытаюсь понять это, не могли бы вы сообщить мне, зависит ли это от
values
данных, которые я показал, или это общее решение? например, если значенияvalues
перетасованы и отличаются, это все равно будет работать? это не учитывает шаблон примера игрушки, верно?3. nvm, это работает,
[x['c1']][x['idx']]
я думал, что это объединение некоторых столбцов , но я не заметилvalues
, что вvalues[x['c1']][x['idx']]
, еще раз спасибо, это работает4. круто, хорошо, что ты это понял.. да, часть словаря немного тяжеловата для глаз
Ответ №2:
In [203]: a = pd.DataFrame([[k, value, idx] for k,v in values.items() for idx,value in enumerate(v)], columns=['c1', 'c3', 'gr']) ...: b = df.assign(gr=df.groupby(['c1']).transform(lambda x: (x.ne(x.shift()).cumsum())- 1)) ...: print(b) ...: b.merge(a).drop(columns='gr') ...: # b c1 c2 gr 0 1 a 0 1 1 a 0 2 1 a 0 3 1 b 1 4 1 b 1 5 1 b 1 6 2 y 0 7 2 y 0 8 2 y 0 9 2 z 1 10 2 z 1 11 2 z 1 Out[203]: c1 c2 c3 0 1 a a1 1 1 a a1 2 1 a a1 3 1 b a2 4 1 b a2 5 1 b a2 6 2 y b1 7 2 y b1 8 2 y b1 9 2 z b2 10 2 z b2 11 2 z b2
Комментарии:
1. спасибо за решение, вы можете это объяснить? Я с радостью приму это
2. 1.
df.assign(gr=...)
это то же самое, чтоdf['gr'] = ...
3. Я новичок в панд, но, судя по вашим усилиям, насколько сложной была эта проблема?
4. @Valencia Я не могу говорить за Asish, такие проблемы, как эти, довольно просто решить для более опытных пользователей pandas.
5. Я рассчитал этот код с помощью timeit, но почему это медленнее, чем у меня, для меня это выглядит полностью векторизованным и прекрасным