Очень простой подход, не зависящий от версии python, отсутствовал в уже заданных ответах, которые вы можете использовать большую часть времени (по крайней мере, я):
new_list = my_list * 1 #Solution 1 when you are not using nested lists
Однако, если my_list содержит другие контейнеры ( например, вложенных списков), вы должны использовать функцию глубокой печати, как другие, предложенные в ответах выше, из библиотеки копий. Например:
import copy
new_list = copy.deepcopy(my_list) #Solution 2 when you are using nested lists
.Bonus: Если вы не хотите копировать элементы, используйте (ака мелкой копии):
new_list = my_list[:]
Давайте понимать разницу между решением # 1 и Solution # 2
>>> a = range(5)
>>> b = a*1
>>> a,b
([0, 1, 2, 3, 4], [0, 1, 2, 3, 4])
>>> a[2] = 55
>>> a,b
([0, 1, 55, 3, 4], [0, 1, 2, 3, 4])
Как вы можете видеть, решение № 1 отлично работало, когда мы не использовали вложенные списки. Давайте проверим, что произойдет, когда мы применим решение №1 к вложенным спискам.
>>> from copy import deepcopy
>>> a = [range(i,i+4) for i in range(3)]
>>> a
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
>>> b = a*1
>>> c = deepcopy(a)
>>> for i in (a, b, c): print i
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
>>> a[2].append('99')
>>> for i in (a, b, c): print i
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5, 99]]
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5, 99]] #Solution#1 didn't work in nested list
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]] #Solution #2 - DeepCopy worked in nested list
Причина, по которой это происходит, связана с «ленивой оценкой» ggplot
. Это обычная проблема, когда ggplot
используется таким образом (делая слои отдельно в цикле, вместо того, чтобы иметь для него ggplot
, как в решении @ hrbrmstr).
ggplot
сохраняет аргументы aes(...)
как выражения и оценивает их только при отображении графика. Таким образом, в ваших циклах, что-то вроде
aes(y = df[,p], colour = place[p-1])
сохраняется, как есть, и оценивается при визуализации графика после завершения цикла. На этом этапе p = 3, поэтому все графики отображаются с p = 3.
Таким образом, «правильный» способ сделать это - использовать melt(...)
в пакете reshape2
, чтобы конвертировать ваши данные от широкого до длинного формата, и пусть ggplot
управляет слоями для вас. Я ставлю «правильно» в кавычки, потому что в этом конкретном случае есть тонкость. При расчете распределений для скрипки с использованием кадра расплавленных данных ggplot
использует общую сумму (как для Чикаго, так и для Майами) в качестве шкалы. Если вы хотите, чтобы скрипки были основаны на частоте, масштабируемой по отдельности, вам нужно использовать петли (к сожалению).
Путь вокруг ленивой проблемы оценки заключается в том, чтобы ссылаться на индекс цикла в определении data=...
. Это not сохраняется как выражение, фактические данные хранятся в определении графика. Поэтому вы можете сделать это:
g <- ggplot(df,aes(x=topic))
for (p in 2:length(df)) {
gg.data <- data.frame(topic=df$topic,value=df[,p],city=names(df)[p])
g <- g + geom_violin(data=gg.data,aes(y=value, color=city))
}
g
[/g2]
, который дает тот же результат, что и ваш. Обратите внимание, что индекс p
не отображается в aes(...)
.
Обновление: примечание о scale="width"
(упомянутое в комментарии). Это приводит к тому, что все скрипки имеют одинаковую ширину (см. Ниже), что не такое же масштабирование, как в исходном коде OP. IMO - это отличный способ визуализировать данные, так как предполагает, что в группе Чикаго имеется гораздо больше данных.
ggplot(gg) +geom_violin(aes(x=topic,y=value,color=variable),
alpha=0.3,position="identity",scale="width")
[/g3]
Вы можете сделать это без петли:
df.2 <- melt(df)
gg <- ggplot(df.2, aes(x=topic, y=value))
gg <- gg + geom_violin(position="identity", aes(color=variable), alpha=0.3)
gg
[/g0]
variable
. Кроме того, следует, наверное, упомянуть, что для этого потребуется загрузить reshape2
.
– jlhoward
7 October 2014 в 23:43
Просто избегайте использовать цикл for
. Как насчет lapply
:
g <- g + lapply(2:ncol(df), function(p) {
geom_violin(aes(y = df[,p], colour = place[p-1]), alpha = 0.3)
})
EDIT: Это действительно не работает. У меня был p <- 2
в моей рабочей области, прежде чем запускать его, а затем он создал график только с данными Чикаго. Во всяком случае, принцип должен по-прежнему работать (хотя melt
, вероятно, лучший вариант):
g <- ggplot(df, aes(x=factor(topic)))
g + lapply(place, function(p) {
geom_violin(aes_string(y = p), alpha = 0.3, color = which(p==place))
})
Error in
[. Data.frame (df, , p) : object 'p' not found
. Если я сначала запустил цикл OP for (который создает переменную p
), тогда запустите lapply(...)
, я получаю тот же результат, что и OP.
– jlhoward
9 October 2014 в 16:49