#arrays #r #for-loop
#массивы #r #для цикла
Вопрос:
Я вроде как новичок в R и только начал использовать его для построения некоторых графиков.
У меня есть этот код:
times=integer(nrow(df));
for(i in 1:nrow(df)) {
time=df[i 1,4]-df[i,4];
times[i]<-time
}
Должен быть более умный способ сделать это без предварительной инициализации, не так ли?
Я не уверен, но то, что я ищу, это что-то вроде:
times <- for(i in 1:nrow(df)) yield df[i 1,4]-df[i,4]
(Я знаю, что это недопустимый код :))
Я надеюсь, что этот вопрос еще не задан. Я искал и не нашел ничего конкретного по «выходу» и инициализации массивов.
Как и было запрошено….
Образец данных в df:
7926 08:00:27:ed:f3:e5 MESSAGEHANDLER START 1.319242e 12
7927 08:00:27:ed:f3:e5 MESSAGEHANDLER END 1.319242e 12
7928 08:00:27:ed:f3:e5 MESSAGEHANDLER START 1.319242e 12
7929 08:00:27:ed:f3:e5 MESSAGEHANDLER END 1.319242e 12
7930 08:00:27:ed:f3:e5 MESSAGEHANDLER START 1.319242e 12
7931 08:00:27:ed:f3:e5 MESSAGEHANDLER END 1.319242e 12
7932 08:00:27:ed:f3:e5 MESSAGEHANDLER START 1.319242e 12
7933 08:00:27:ed:f3:e5 MESSAGEHANDLER END 1.319242e 12
7934 08:00:27:ed:f3:e5 MESSAGEHANDLER START 1.319242e 12
7935 08:00:27:ed:f3:e5 MESSAGEHANDLER END 1.319242e 12
7936 08:00:27:ed:f3:e5 MESSAGEHANDLER START 1.319242e 12
7937 08:00:27:ed:f3:e5 MESSAGEHANDLER END 1.319242e 12
7938 08:00:27:ed:f3:e5 MESSAGEHANDLER START 1.319242e 12
7939 08:00:27:ed:f3:e5 MESSAGEHANDLER END 1.319242e 12
После того, как мой цикл раз равен:
[7921] 508 500 497 501 466 502 505 500 488 501 500 501 490 501 478 501 501 501
[7939] NA
Хорошо, чтобы получить более конкретную информацию, я действительно хочу сделать это:
times1=integer(nrow(df));for(i in 1:nrow(df)) { if (df[i,3] == "START") times1[i]<-df[i 1,4]-df[i,4]}
times2=integer(nrow(df));for(i in 1:nrow(df)) { if (df[i,3] == "END") times2[i]<-df[i 1,4]-df[i,4]}
Тогда результат будет примерно таким, как для times1:
[7921] 0 500 0 501 0 502 0 500 0 501 0 501 0 501 0 501 0 501
[7939] 0
Но мне нужно:
[3960] 500 501 502 500 501 501 501 501 501
Словами:
Я анализирую измеренные данные из файла csv, который попадает в df, как показано выше. Это для «START», за которым следует «END»
Данные в df описывают, что пакет был получен, когда в df [,3] есть «ЗАПУСК» в определенное время в миллисекундах в df [,4]. Теперь мне нужно вычислить время, прошедшее от получения до отправки (это время, необходимое моей машине для анализа ПОЛУЧЕННОГО ПАКЕТА и вычисления результата для его ОТПРАВКИ.) Так что КОНЕЦ в df[,3] означает, что пакет был успешно отправлен в unixtime df[,4] .
Другой случай — «END», за которым следует «START»
Это время, которое прошло между «мой пакет был отправлен» и «был получен» новый.
Теперь я добавляю образец csv и мой полный код для воспроизведения:
#load csv in df!
df = read.csv("/tmp/measure.csv",FALSE)
absolute=integer(nrow(df));for(i in 1:nrow(df)) {time=df[i,4]-df[1,4];absolute[i]<-(time/1000)}
times=integer(nrow(df));for(i in 1:nrow(df)) {time=df[i 1,4]-df[i,4];times[i]<-time}
#plot(absolute,times)
plot(absolute,times,lty=1,pch=1,col="#11223399",type="l")
lines(absolute,array(mean(times,na.rm=1),nrow(df)),col="red")
Вот мой measure.csv:
08:00:27:ed:f3:e5,TMCMESSAGEHANDLER,END,1319238175202
08:00:27:ed:f3:e5,TMCMESSAGEHANDLER,START,1319238175690
08:00:27:ed:f3:e5,TMCMESSAGEHANDLER,END,1319238176195
08:00:27:ed:f3:e5,TMCMESSAGEHANDLER,START,1319238176665
08:00:27:ed:f3:e5,TMCMESSAGEHANDLER,END,1319238177167
08:00:27:ed:f3:e5,TMCMESSAGEHANDLER,START,1319238177669
08:00:27:ed:f3:e5,TMCMESSAGEHANDLER,END,1319238178172
08:00:27:ed:f3:e5,TMCMESSAGEHANDLER,START,1319238178639
08:00:27:ed:f3:e5,TMCMESSAGEHANDLER,END,1319238179139
08:00:27:ed:f3:e5,TMCMESSAGEHANDLER,START,1319238179658
08:00:27:ed:f3:e5,TMCMESSAGEHANDLER,END,1319238180161
08:00:27:ed:f3:e5,TMCMESSAGEHANDLER,START,1319238180654
08:00:27:ed:f3:e5,TMCMESSAGEHANDLER,END,1319238181154
08:00:27:ed:f3:e5,TMCMESSAGEHANDLER,START,1319238181669
08:00:27:ed:f3:e5,TMCMESSAGEHANDLER,END,1319238182170
08:00:27:ed:f3:e5,TMCMESSAGEHANDLER,START,1319238182629
08:00:27:ed:f3:e5,TMCMESSAGEHANDLER,END,1319238183130
Я надеюсь, что это делает его более понятным.
Комментарии:
1. Вам будет намного легче понять, что вы хотите, если вы опубликуете образцы данных и ожидаемые результаты.
2. дело не в результате, они просто прекрасны. Это все о том, что может язык. Но я публикую некоторые из своих данных. Итак, мой код работает, но выглядит неуклюже.
3. @Andrie: я не могу использовать diff, потому что мне нужно выполнить дополнительные проверки типа if (df[i,3] == START amp;amp; df[i 1,3] == END) сделайте это иначе, сделайте это
4. Извините, но я понятия не имею, что вы пытаетесь сделать. Кажется, вы выполняете какую-то операцию над вектором. Может быть, это поможет, если вы 1) опишите словами, что должна делать эта операция, и 2) сделайте свой пример минимально воспроизводимым.
5. Одно предостережение: поступают ли сообщения в последовательном порядке? Если пакеты перекрываются, вам нужно разделить по идентификатору пакета.
Ответ №1:
Я думаю, вы хотите вычислить разницу между последовательными элементами в векторе. В этом случае вы ищете diff
:
set.seed(0)
x <- sample(1:10, 5)
x
[1] 1 2 9 5 3
diff(x)
[1] 1 7 -4 -2
Ответ №2:
Надеюсь, я не слишком далек от истины — почему бы вообще не избежать цикла?:
# generate some data sort of similar to yours:
DF <- data.frame(pos4 = rep(c("START","END"),10),times=rep(0,20))
DF$times[DF$pos4=="START"] <- 1:10
DF$times[DF$pos4=="END"] <- DF$times[DF$pos4=="START"] runif(10)
DF
DF
pos4 times
1 START 1.000000
2 END 1.750459
3 START 2.000000
4 END 2.212599
5 START 3.000000
6 END 3.974809
....
Я предполагаю, что время НАЧАЛА и ОКОНЧАНИЯ в вашем наборе данных в порядке..
(times <- DF$times[DF$pos4=="END"] - DF$times[DF$pos4=="START"])
[1] 0.7504590 0.2125986 0.9748094 0.3313644 0.3448410 0.8677022 0.9534317
[8] 0.1279304 0.6500212 0.1798664
не уверен, какие проверки вам нужно выполнить, поскольку они не были в цикле for, который вы опубликовали в вопросе.
——————РЕДАКТИРОВАТЬ—————————
чтобы включить из приведенного ниже комментария, который, похоже, все понял правильно, это действительно был вопрос об индексации: где:
DIFFS <- diff(DF$times)
дает вам все различия, вы просто хотели разделить это на два объекта: один для четных индексов, другой для нечетных индексов:
times1 <- DIFFS[seq(from=1,to=length(DIFFS),by=2)]
times2 <- DIFFS[seq(from=2,to=length(DIFFS),by=2)]
и не связанная, но тоже полезная: вы использовали ‘absolute’ и ‘df’ для имен объектов в вашем коде, но это также функции в R, поэтому, хотя это работает, лучше присвоить им имена, которые еще не приняты. Рад, что вы получили то, что искали!
Комментарии:
1. это почти то, что я ищу. В настоящее время я тестирую.
2. хорошо, это отлично работает для вычисления разницы с 1,2 3,4 5,6, но как мне вычислить 2,3 и 4,5? я только заставляю его вычислять 2,1 4,3 6,5 (мне нужен следующий ЗАПУСК, а не предыдущий). Извините, понятно, что я имею в виду? 🙂
3. Чтобы добавить к этому evildead, R сильно отличается от других языков, к которым вы, возможно, привыкли. Циклы используются редко. Циклы в R намного медленнее, чем другие методы, которые могут быть вам доступны.
4. Я уверен, что вообще не использую циклы. Я читал, что R похож на диалект scheme, так что это имеет смысл. Обычно в «функциональных языках» у вас есть что-то вроде так называемого «for expression» с выходом (по крайней мере, в scala и python). Почему я использовал реальный цикл в первую очередь, потому что мне нужно обратиться к «следующему» элементу из относительной позиции. В настоящее время проблема с опубликованным выражением заключается в том, что оно принимает первое найденное, а затем выполняет итерацию по коллекции.
5. затем выполните diff(), как говорит Андри, для ваших первых различий (END1-START1): diff(DF $times)[seq(from=1,to=length(DF $ times),by= 2)] и для ваших различий второго типа (START2-END1): diff(DF $ раз)[seq(от= 2, до = длина (DF $ раз), by= 2)]
Ответ №3:
Вы также можете сделать что-то вроде
lapply(sequence(nrow(df)-1),function(i,df) df[i 1,4]-df[i,4],df)
или также попробуйте sapply
вместо lapply
(в противном случае, тот же синтаксис).
Редактировать:
Более конкретно, я думаю
times <- sapply(sequence(nrow(df)-1),function(i,df) df[i 1,4]-df[i,4],df)
или
times <- unlist(lapply(sequence(nrow(df)-1),function(i,df) df[i 1,4]-df[i,4],df))
это помогло бы. Что касается изменения формы, в ней нет идентифицирующей переменной, df
которая соединяла бы время начала и окончания вместе, поэтому пришлось бы делать это вручную, предполагая, что две пары встречаются в последовательных строках:
times <- apply(matrix(df[,4],ncol=2,byrow=TRUE),1,diff)
Ответ №4:
Я выхожу за дверь, но 2 комментария: 1) добавьте заголовки столбцов во фрейм данных 2) Я думаю, что оператору нужен пакет reshape, чтобы разделить его время начала и окончания на 2 разных столбца, называемых start, а затем end. затем используйте операцию End-Start для вектора.
Комментарии:
1. Ответ Тима Риффа мне нравится больше, чем мой собственный. Это быстрее.
2. Я согласен — изменение формы фрейма данных упростило бы задачу