简体   繁体   中英

Apply User-Defined Function to Specific Dataframe Columns

I have seen the question here R apply user define function on data frame columns but mine is a little different...

I would like to pass specific columns of my dataframe to a function, then return the result of that function to a new column of my dataframe.

Basically, I have a dataframe like this:

df.latitude1
df.longitude1
df.latitude2
df.longitude2

Then I have a method getDistance(lat1, lng1, lat2, lng2) and I would like to return the result of that computation into a new column in my dataframe called distance .

Update

> asn$geoDistance <- distHaversine(asn[,c("homeLocationGeoLat", "homeLocationGeoLng")], dat[,c("hostLocationGeoLat", "hostLocationGeoLng")])
Error in .pointsToMatrix(p1) : latitude < -90
> asn$homeLocationGeoLat[asn$homeLocationGeoLat < -90]
  [1] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
 [40] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
 [79] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[118] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[157] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[196] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[235] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[274] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[313] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[352] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[391] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[430] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[469] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[508] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[547] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
> asn$hostLocationGeoLat[asn$hostLocationGeoLat < -90]
  [1] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
 [40] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
 [79] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[118] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[157] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[196] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[235] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[274] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[313] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[352] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[391] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[430] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[469] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[508] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[547] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[586] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[625] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[664] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[703] NA NA NA NA NA NA NA NA NA
> newDf <- asn[, c('durationDays', 'homeLocationGeoLat', 'homeLocationGeoLng', 'hostLocationGeoLat', 'hostLocationGeoLng')]
> dput(head(newDf))
structure(list(durationDays = c(0, 0, 180, 0, 365, 0), homeLocationGeoLat = c(-23.5489433, 
1.2800945, 12.9715987, 25.7889689, 49.3063689, 25.271139), homeLocationGeoLng = c(-46.6388182, 
103.8509491, 77.5945627, -80.2264393, 8.6427693, 55.307485), 
    hostLocationGeoLat = c(37.4418834, 49.2774456, 52.3905689, 
    49.3063689, 53.3498053, 37.4418834), hostLocationGeoLng = c(-122.1430195, 
    7.1118995, 13.0644729, 8.6427693, -6.2603097, -122.1430195
    )), .Names = c("durationDays", "homeLocationGeoLat", "homeLocationGeoLng", 
"hostLocationGeoLat", "hostLocationGeoLng"), row.names = c(NA, 
6L), class = "data.frame")

Your best bet is probably to use a vectorized function and compute the distances for all pairs of points at the same time. For instance, you could use the distHaversine function from the geosphere package to do the calculation in one shot:

# 10000 points
set.seed(144)
dat <- data.frame(lat1=runif(10000, 10, 20), lng1=runif(10000, 10, 20),
                  lat2=runif(10000, 10, 20), lng2=runif(10000, 10, 20))

# Get all distances
library(geosphere)
dat$distance <- distHaversine(dat[,c("lng1", "lat1")], dat[,c("lng2", "lat2")])
head(dat$distance)
# [1] 293912.3 332583.2 870767.8 167362.9 371920.6 659368.1

If you were going to use a function from the apply family, you would probably loop through the rows of your data frame, computing the distances one at a time. While this will give the same answer, it will be much slower:

all.equal(distHaversine(dat[,c("lng1", "lat1")], dat[,c("lng2", "lat2")]),
          apply(dat, 1, function(x) distHaversine(x[c("lng1", "lat1")], x[c("lng2", "lat2")])))
# [1] TRUE
system.time(distHaversine(dat[,c("lng1", "lat1")], dat[,c("lng2", "lat2")]))
#    user  system elapsed 
#   0.005   0.001   0.008 
system.time(apply(dat, 1, function(x) distHaversine(x[c("lng1", "lat1")], x[c("lng2", "lat2")])))
#    user  system elapsed 
#   0.887   0.007   0.895 

The reason for the 100x slowdown is that you can't take advantage of vectorization if you perform the distance computation one row at a time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM