Статьи

R: применение функции к каждой строке фрейма данных

В моем постоянном исследовании лондонских встреч я хотел рассчитать расстояние от мест встречи до центральной точки в Лондоне.

Я создал список, содержащий координаты некоторых мест, где проводятся встречи NoSQL в Лондоне, если вы хотите следовать:

01
02
03
04
05
06
07
08
09
10
11
12
13
library(dplyr)
  
# https://gist.github.com/mneedham/7e926a213bf76febf5ed
venues = read.csv("/tmp/venues.csv")
  
venues %>% head()
##                        venue      lat       lon
## 1              Skills Matter 51.52482 -0.099109
## 2                   Skinkers 51.50492 -0.083870
## 3          Theodore Bullfrog 51.50878 -0.123749
## 4 The Skills Matter eXchange 51.52452 -0.099231
## 5               The Guardian 51.53373 -0.122340
## 6            White Bear Yard 51.52227 -0.109804

Теперь сделать расчет. Я выбрал здание Центральной точки на Тоттенхэм Корт Роуд в качестве нашей центральной точки. Мы можем использовать функцию distHaversine в библиотеке геосферы, которая позволяет нам выполнять вычисления:

1
2
3
4
5
6
7
8
options("scipen"=100, "digits"=4)
library(geosphere)
  
centre = c(-0.129581, 51.516578)
aVenue = venues %>% slice(1)
aVenue
##           venue   lat      lon
## 1 Skills Matter 51.52 -0.09911

Теперь мы можем рассчитать расстояние от Skillsmatter до нашей центральной точки:

1
2
distHaversine(c(aVenue$lon, aVenue$lat), centre)
## [1] 2302

Это работает довольно хорошо, поэтому теперь мы хотим применить его к каждой строке во фрейме данных мест и добавить дополнительный столбец, содержащий это значение.

Это была моя первая попытка …

1
2
venues %>% mutate(distHaversine(c(lon,lat),centre))
## Error in .pointsToMatrix(p1): Wrong length for a vector, should be 2

… который не работал так, как я себе представлял!

В конце концов я нашел свой путь к функции by, которая позволяет вам «применить функцию к фрейму данных, разделенному на факторы». В этом случае я бы не группировал строки по коэффициенту — я бы применил функцию к каждой строке отдельно.

Я подключил все так:

1
2
3
4
5
6
distanceFromCentre = by(venues, 1:nrow(venues), function(row) { distHaversine(c(row$lon, row$lat), centre)  })
  
distanceFromCentre %>% head()
## 1:nrow(venues)
##      1      2      3      4      5      6
## 2301.6 3422.6  957.5 2280.6 1974.1 1509.5

Теперь мы можем добавить расстояния к нашему фрейму данных мест:

01
02
03
04
05
06
07
08
09
10
11
venuesWithCentre = venues %>%
  mutate(distanceFromCentre = by(venues, 1:nrow(venues), function(row) { distHaversine(c(row$lon, row$lat), centre)  }))
  
venuesWithCentre %>% head()
##                        venue   lat      lon distanceFromCentre
## 1              Skills Matter 51.52 -0.09911             2301.6
## 2                   Skinkers 51.50 -0.08387             3422.6
## 3          Theodore Bullfrog 51.51 -0.12375              957.5
## 4 The Skills Matter eXchange 51.52 -0.09923             2280.6
## 5               The Guardian 51.53 -0.12234             1974.1
## 6            White Bear Yard 51.52 -0.10980             1509.5

И вуаля!