Множество графиков с использованием петель в R

Я все еще пытаюсь склонить голову к использованию циклов для построения в R. Я хотел бы построить (любой график для визуализации данных будет делать) столбцы z_1 против z_2 в фрейме данных ниже в соответствии с разными именами в столбце x_1.

x_1 <- c("A1", "A1","A1", "B10", "B10", "B10","B10", "C100", "C100", "C100")


z_1 <- rnorm(10, 70) 

z_2 <- rnorm(10, 1.7)

A <- data.frame(x_1, z_1, z_2)

Таким образом, я хотел бы получить три разных сюжета; один для категории A1, один для B10 и другой для C100. Я могу сделать это с использованием трех разных кодов, но я хотел бы иметь возможность использовать цикл или любой другой отдельный код для выполнения всех трех графиков на одной странице. На самом деле, у меня есть большой набор данных (4000 строк) и хотел бы построить пару идентификаторов на странице (например, 5 на странице).

Я надеюсь в этом есть смысл. Спасибо за вашу помощь.

Здесь моя попытка построить их индивидуально:

для A1:

data_A1 <- A[which(A$x_1 == "A1"), ]
plot(data_A1$z_2, data_A1$z_1)

Я также пробовал что-то вроде этого, но получал сообщения об ошибках

for ( i in A$x_1[[i]]){

plot(A[which(A$x_1==A$x_1[[i]]), ], aspect = 1)
}

Ответ 1

Простой подход с петлями будет

for (cat in unique(x_1)){
  d <- subset(A, x_1 == cat)
  plot(d$z_1, d$z_2)
}

unique(x_1) получает все уникальные значения x_1. Затем для каждого из этих значений получаем соответствующее подмножество и используйте это подмножество для построения графика.

Ответ 2

Просто чтобы понять, почему ваш исходный код не работал:

Настройка данных прекрасно работает

x_1 <- c("A1", "A1", "A1", "B10", "B10", "B10","B10", "C100", "C100", "C100")
z_1 <- rnorm(10, 70) 
z_2 <- rnorm(10, 1.7)
A <- data.frame(x_1, z_1, z_2)

Индивидуальный участок работает отлично, но как я уже сказал в комментариях, то, which не является необходимым

data_A1 <- A[which(A$x_1 == "A1"), ] # your way
plot(data_A1$z_2, data_A1$z_1)

data_A1 <- A[A$x_1 == "A1", ]    # deleting which() makes it cleaner
with(data_A1, plot(z_2, z_1))    # you can also use with() to save typing

Теперь цикл for. Давайте рассмотрим простой цикл цикла в R (довольно близко к примеру в ?"for"):

for (i in 1:5) {
   print(1:i)
}

Довольно просто, 1:5 - c(1, 2, 3, 4, 5), поэтому сначала i равно 1, затем 2 и т.д. В вашей первой строке есть проблема в этой первой строке:

for (i in A$x_1[[i]]) { ## already a problem

Сначала i является A$x_1[[i]]? Это не сработает, i еще не определился. Кроме того, A$x_1 - это вектор, а не список, поэтому вы не должны использовать [[ для его подмножества. Но мы еще не хотим подмножества, нам нужен вектор значений, которые i должен принять. В этом случае мы хотим for (i in c("A1", "B10", "C100")), но мы также хотим сделать это программно, вместо того, чтобы печатать все разные возможности. Есть пара общих способов получить это:

unique(A$x_1) # as in Mark solution
levels(A$x_1) # works because A$x_1 is a factor

Мы можем либо из этих выражений после in. Я изменил ваш [[ на [ в разговоре сюжета. [[ только для списков. Я также вынул ненужное, which()

for (i in unique(A$x_1)) {   # this line is good
    plot(A[A$x_1==A$x_1[i], ], aspect = 1)  # still a problem
}

Напомним, какие значения i принимаю: "A1", "B10", "C100". Что A$x_1 == A$x_1["A1"] собирается дать? Ничего полезного.

for (i in unique(A$x_1)) {  
    plot(A[A$x_1 == i, ], aspect = 1)  # getting there
}

Вышеприведенный код что-то делает, и он опрятен, но это не то, что вы хотите. Там есть куча предупреждений, и все они говорят нам, что aspect не является допустимым аргументом, поэтому мы его удалим. Глядя на сюжет, вы увидите, что он рисует 3 переменные, потому что мы не сказали, что поставить на оси x и y.

for (i in unique(A$x_1)) {   
    plot(A[A$x_1==i, "z_2"], A[A$x_1==i, "z_1"])  # z_2 on x, z_1 on y 
}   # Works!!!

Обратите внимание, что это почти идентично ответу Марка. Вам не нужно использовать i и j для циклов, он использовал cat. Хорошей практикой является использование более описательного имени. Теперь позвольте немного подумать:

for (i in unique(A$x_1)) {   
    plot(A[A$x_1==i, "z_2"], A[A$x_1==i, "z_1"],
         xlim = range(A$z_2), ylim = range(A$z_1), # base the axes on full data range
         main = paste("Plot of", i))  # Give each a title
}

В следующий раз: не забывайте, что вы можете запускать крошечные фрагменты кода, чтобы узнать, что они собой представляют. Если у вас есть строка, подобная for (i in A$x_1[[i]]) что вы не уверены, правильно ли это, введите A$x_1[[i]] на консоли, надеюсь, это поможет вам понять, что вы не определили i, поэтому вы измените его на

for (i in A$x_1)

то вы запустите A$x_1 и поймете, что длина равна 10. Вам нужны 3 графика, а не 10, поэтому вам нужно, чтобы i принимал 3 значения, все они разные и т.д.

Ответ 3

Возможно, вам не нужна петля. Попробуйте использовать ggplots facet_grid(). Вот документация, полная примеров.

library(ggplot2)
library(reshape2)

melted_a <- melt(A)


ggplot(melted_a, aes(variable, value)) +
  geom_jitter() +
  facet_grid(. ~ x_1)

ggplot(melted_a, aes(variable, value)) +
  geom_jitter() +
  facet_grid(variable ~ x_1)

Редактировать Возможно, это решает эту проблему. Но если вам нужно сделать много графиков с аналогичной структурой, вы можете сделать функцию и использовать aes_string() вместо aes(). Примечание. Я не специалист по написанию функций, поэтому, возможно, кто-то может редактировать и улучшать его. (не испытано)

ggplot_fun <- function(data, x, y, rowfacet, colfacet, ...){
  p <- ggplot(data, aes_string(x, y))
  p <- p + geom_jitter()
  p <- p + facet_grid(as.formula(sprintf("%s ~ %s", rowfacet, colfacet))
}

ggplot_fun(melted_a, variable, value, variable, x_1)

Идея взята из этого вопроса.

Ответ 4

Вы также настраиваете данные, например, как я здесь...

Если мне нужны датчатые графики и xlab, ylab и заголовок сюжета, чтобы иметь конкретные детали...

 for ( i in 1:length(unique(wheeldata$Date)) ){
     d <- subset( wheeldata, Date == unique ( wheeldata$Date )[i] )
     plot(d$X, d$Y, xlab = "X", ylab = "Y", main = paste0("Date: ",  unique(d$Date)) )
 }