假设我有几个数据帧,我想循环遍历每个数据帧的行并执行某些操作,例如使用httr
包发送SMS消息。我可以创建几个循环,但我怀疑答案是“不要使用循环!”。
df1 <- data.frame(A=1:10, B=2:11, C=3:12) # imagine these columns hold words and phone numbers
df2 <- data.frame(A=4:13, B=5:14, C=6:15)
# loop for df1
for (n in 1:nrow(df1)) { # imagine that each row is a person
# get details for each person (row)
sms1 <- df1$A[n]
sms2 <- df1$B[n]
sms3 <- df1$C[n]
# create personalized message to send
sms <- paste(sms1, sms2, sms3, sep=" ")
# here I would use the POST() function of httr to send a personalized SMS to each person, but that is not important
}
# loop for df2
for (n in 1:nrow(df1)) {
sms1 <- df2$A[n]
sms2 <- df2$B[n]
sms3 <- df2$C[n]
sms <- paste(sms1, sms2, sms3, sep=" ")
# here I would use the POST() function of httr to send a personalized SMS, but that is not important
}
但我真正想做的是创建一个外部循环来遍历每个数据帧。类似的东西:
dfs <- c("df1", "df2")
# loop over dfs
for (d in dfs) {
for (n in 1:nrow(d)) {
sms1 <- d$A[n]
sms2 <- d$B[n]
sms3 <- d$C[n]
sms <- paste(sms1, sms2, sms3, sep=" ")
# here I would use the POST() function of httr to send a personalized SMS, but that is not important
}
}
但我知道这不行。我d
中的sms1 <- d$A[n]
不会被视为sms1 <- df1$A[n]
或sms1 <- df2$A[n]
。
有没有办法做这个循环?更好的是,正确的应用方法是什么?
更新
以下是我需要对两个数据框中的每一行执行POST步骤的示例,以便向每个人(行)发送个性化消息:
# let's say that sms3 in my example is a phone number
# let's also say that I define the following objects once outside of the loop:
# url, username, password, account, source, network
# when I paste together the following objects, I get string that is formatted for my API gateway.
send <- paste0(url, username, password, account, source, sms3,
sms, network)
POST(send)
这将在我原始帖子的评论中提到的循环:
# remove these paste steps from the loops as recommended in the answers
df1$sms <- paste(df2$A, df2$B)
df2$sms <- paste(df2$A, df2$B)
dfs <- c("df1", "df2")
# loop over dfs
for (d in dfs) {
for (n in 1:nrow(d)) {
sms3 <- d$C[n] # to get phone number
send <- paste0(url, username, password, account, source, sms3, sms, network)
POST(send)
}
}
答案 0 :(得分:3)
您不需要将每一行循环到paste
个元素。相反,您只需为每个数据框调用一次paste
:
df1$sms <- paste(df1$A, df1$B, df1$C)
然后,您可以再次调用df1$send
来创建paste
,或者根据您的具体需求,只使用一个paste
。
现在您已在df1$send
中拥有所需的一切,您只需在每个元素上调用POST
即可。 POST
没有矢量化,因此您必须以某种方式迭代元素。例如:
sapply(df1$send, POST)
您可以为df2
再次执行此操作,但另一种方法是创建数据帧列表,然后循环,为每个数据帧执行相同的paste
操作。例如:
my.dfs <- list(df1, df2)
for (df in my.dfs) {
df$sms <- paste(df$A, df$B, df$C)
...
sapply(df$send, POST)
}
(你可以也循环遍历字符串的名字,就像你原来的那样,然后获得与每个字符串相对应的实际对象:df <- get(d)
。但我认为这里没有理由更喜欢这个。)
更好的方法是将df1
和df2
合并到一个数据框中。您可以创建一个列来区分这两个组。然后,您只需要在一个数据框上paste
和POST
:
comprehensive.df$sms <- paste(comprehensive.df$A, comprehensive.df$B, comprehensive.df$C)
...
sapply(comprehensive.df$send, POST)
如何执行此操作取决于数据框的不同程度。如果它们略有不同,您可以使用rbind.fill
中的plyr
来处理缺少的列。如果它们具有不同的列名等,您可以提取公共列并进行一些重命名。我只是认为,如果你在进行手术之前进行清洁和合并,你所做的事情会更清楚。
可以使用for
循环。事实上,如果你查看apply
的来源,你会发现它使用了for
循环。实际的收益不是来自使用apply
,而是来自通过将整个对象传递给函数来利用向量化,如上面使用paste
所做的那样。这更具可读性(因为它是一条直接的单行)并且可能性能更好(因为你只需要调用函数一次)。
答案 1 :(得分:3)
只需重新绑定数据框架而不是循环:
df <- rbind(df1, df2)
df$sms <- paste(df$A, df$B, df$C)