Каковы варианты клонирования или копирования списка в Python?
В Python 3 мелкая копия может быть выполнена с помощью:
a_copy = a_list.copy()
В Python 2 и 3 вы можете получить мелкую копию с полным фрагментом оригинала:
a_copy = a_list[:]
Объяснение
Существует два семантических способа копирования списка. Неглубокая копия создает новый список тех же объектов, глубокая копия создает новый список, содержащий новые эквивалентные объекты.
Короткая копия списка
Неглубокая копия копирует только сам список, который является контейнером ссылок на объекты в списке. Если объекты, содержащиеся в них, являются изменяемыми и один из них изменен, это изменение будет отражено в обоих списках.
Существуют разные способы сделать это в Python 2 и 3. Пути Python 2 также будут работать в Python 3.
Python 2
В Python 2 , идиоматический способ создания мелкой копии списка состоит из полного фрагмента оригинала:
a_copy = a_list[:]
Вы также можете выполнить одно и то же, передав список через конструктор списка,
a_copy = list(a_list)
, но использование конструктора менее эффективно:
>>> timeit >>> l = range(20) >>> min(timeit.repeat(lambda: l[:])) 0.30504298210144043 >>> min(timeit.repeat(lambda: list(l))) 0.40698814392089844
Python 3
В Python 3 списки получают метод
list.copy
:a_copy = a_list.copy()
В Python 3.5:
>>> import timeit >>> l = list(range(20)) >>> min(timeit.repeat(lambda: l[:])) 0.38448613602668047 >>> min(timeit.repeat(lambda: list(l))) 0.6309100328944623 >>> min(timeit.repeat(lambda: l.copy())) 0.38122922903858125
Создание другого указателя делает not сделать копию
Используя new_list = my_list, тогда изменяет new_list каждый раз, когда изменяется my_list. Почему это?
my_list
- это просто имя, которое указывает на фактический список в памяти. Когда вы скажетеnew_list = my_list
, что вы не делаете копию, вы просто добавляете другое имя, указывающее на этот исходный список в памяти. У нас могут быть подобные проблемы, когда мы делаем копии списков.>>> l = [[], [], []] >>> l_copy = l[:] >>> l_copy [[], [], []] >>> l_copy[0].append('foo') >>> l_copy [['foo'], [], []] >>> l [['foo'], [], []]
Список - это всего лишь массив указателей на содержимое, поэтому мелкая копия просто копирует указатели, поэтому у вас есть два разных списка, но они имеют одинаковое содержимое. Чтобы сделать копии содержимого, вам нужна глубокая копия.
Глубокие копии
Чтобы сделать глубокую копию списка в Python 2 или 3, используйте
deepcopy
в модулеcopy
:import copy a_deep_copy = copy.deepcopy(a_list)
Чтобы продемонстрировать, как это позволяет нам создавать новые под-списки:
>>> import copy >>> l [['foo'], [], []] >>> l_deep_copy = copy.deepcopy(l) >>> l_deep_copy[0].pop() 'foo' >>> l_deep_copy [[], [], []] >>> l [['foo'], [], []]
Итак, мы видим, что глубокий скопированный список - это совсем другой список из оригинала. Вы можете перевернуть свою собственную функцию, но не надо. Вероятно, вы создадите ошибки, которых иначе не было бы, используя функцию глубокой печати стандартной библиотеки.
Не использовать
eval
Вы можете видеть, что это используется как способ to deepcopy, но не делайте этого:
problematic_deep_copy = eval(repr(a_list))
- Это опасно, особенно если вы оцениваете что-то из источника, которому вы не доверяете.
- Это не надежный, если подэлемент, который вы копируете, не имеет представления, которое может быть доказано для воспроизведения эквивалентного элемента.
- Он также менее эффективен.
В 64-битном Python 2.7:
>>> import timeit >>> import copy >>> l = range(10) >>> min(timeit.repeat(lambda: copy.deepcopy(l))) 27.55826997756958 >>> min(timeit.repeat(lambda: eval(repr(l)))) 29.04534101486206
на 64-битном Python 3.5:
>>> import timeit >>> import copy >>> l = list(range(10)) >>> min(timeit.repeat(lambda: copy.deepcopy(l))) 16.84255409205798 >>> min(timeit.repeat(lambda: eval(repr(l)))) 34.813894678023644
Одно быстрое решение reindex
df.Column.value_counts().reindex(list,fill_value=0)
HIGH 3
MEDIUM 0
LOW 4
Name: Column, dtype: int64
<час> Другой способ pd.Categorical
pd.Categorical(df.Column,list).value_counts()
HIGH 3
MEDIUM 0
LOW 4
dtype: int64
Попробуйте ниже, сначала он создает пустой ряд, а затем объединяет его с серией value_counts:
pd.Series(0, index=list).combine(df.value_counts(), max)