1

假设我有几个数据帧,我想遍历每个数据帧的行并做一些事情,比如使用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的 insms1 <- d$A[n]不会被读作sms1 <- df1$A[n]or 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)
  }
}
4

2 回答 2

3

只需 rbind 你的 data.frames 而不是循环:

df <- rbind(df1, df2)
df$sms <- paste(df$A, df$B, df$C)
于 2013-07-03T12:39:42.280 回答
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)。但我认为这里没有理由更喜欢这个。)

一个更好的方法是仅仅合并df1df2一个单一的数据框。您可以创建一个列来区分这两个组。然后你只需要pastePOST一个数据框:

comprehensive.df$sms <- paste(comprehensive.df$A, comprehensive.df$B, comprehensive.df$C)
...
sapply(comprehensive.df$send, POST)

你如何做到这一点取决于你的数据框有多么不同。如果它们只是略有不同,您可以使用rbind.fillfromplyr来处理缺失的列。如果它们有不同的列名等,您可以提取公共列并进行一些重命名。我只是认为,如果您在开始操作之前进行清洁和合并,那么您正在做的事情会更加清晰。

可以使用for循环。事实上,如果您查看 for 的源代码apply,您会发现它使用了for循环。真正的收获不是来自使用apply,而是来自通过将整个对象传递给函数来利用矢量化,就像上面使用paste. 这更具可读性(因为它是一条简单直接的行)并且可能会执行得更好(因为您只调用该函数一次)。

于 2013-07-03T12:30:19.813 回答