Я использую pandas
, чтобы постепенно находить новые элементы, т. Е. Для каждой строки я буду видеть, были ли значения в списке видны ранее.Если они есть, мы будем игнорировать их.Если нет, мы их выберем.
Я смог сделать это, используя row.iterrows()
, но у меня> 1M строк, поэтому я считаю, что векторизация apply
может быть лучше.
Вот пример данных и кода.Запустив этот код, вы получите ожидаемый результат:
from numpy import nan as NA
import collections
df = pd.DataFrame({'ID':['A','B','C','A','B','A','A','A','D','E','E','E'],
'Value': [1,2,3,4,3,5,2,3,7,2,3,9]})
#wrap all elements by group in a list
Changed_df=df.groupby('ID')['Value'].apply(list).reset_index()
Changed_df=Changed_df.rename(columns={'Value' : 'Elements'})
Changed_df=Changed_df.reset_index(drop=True)
def flatten(l):
for el in l:
if isinstance(el, collections.Iterable) and not isinstance(el, (str, bytes)):
yield from flatten(el)
else:
yield el
Changed_df["Elements_s"]=Changed_df['Elements'].shift()
#attempt 1: For loop
Changed_df["Diff"]=NA
Changed_df["count"]=0
Elements_so_far = []
#replace NA with empty list in columns that will go through list operations
for col in ["Elements","Elements_s","Diff"]:
Changed_df[col] = Changed_df[col].apply(lambda d: d if isinstance(d, list) else [])
for idx,row in Changed_df.iterrows():
diff = list(set(row['Elements']) - set(Elements_so_far))
Changed_df.at[idx, "Diff"] = diff
Elements_so_far.append(row['Elements'])
Elements_so_far = flatten(Elements_so_far)
Elements_so_far = list(set(Elements_so_far)) #keep unique elements
Changed_df.loc[idx,"count"]=diff.__len__()
Комментарий к коду:
- Я не фанат этого кода, потому чтоэто неуклюже и неэффективно.
- Я говорю неэффективно, потому что я создал
Elements_s
, который содержит сдвинутые значения.Другой причиной неэффективности является for
цикл по строкам.
Elements_so_far
отслеживает все элементы, которые мы обнаружили для каждой строки.Если появляется новый элемент, который отображается, мы считаем это в столбце Diff
. - Мы также отслеживаем длину новых элементов, обнаруженных в столбце
count
.
Я был бы признателен, если бы эксперт мог помочь мне с векторной версией кода.
Я попробовал векторизованную версию, но я не мог зайти слишком далеко.
#attempt 2:
Changed_df.apply(lambda x: [i for i in x['Elements'] if i in x['Elements_s']], axis=1)
Меня вдохновили Как сравнить два столбца со списком строк и создать новый столбец с уникальными элементами? сделать выше, но я не смог этого сделать.Связанный поток SO выполняет построчное различие между столбцами.
Я использую Python 3.6.7 от Anaconda.Версия для панд - 0.23.4