簡體   English   中英

遍歷數據幀並根據條件[R]更改值

[英]Iterating through data frame and changing values on condition [R]

因為這個for循環序列已經困擾了我很長一段時間了,所以不得不記賬了。

我在R中有一個數據幀,具有1000行10列,每個值的范圍為1:3。 我想重新編碼每個條目,以便:1 == 3,2 == 2,3 == 1。 我知道,有更簡便的方法可以做到這一點,例如對每個列進行子設置並對條件進行硬編碼,但這並不總是理想的,因為我使用的許多數據集最多有100列。

我想使用嵌套循環來完成此任務-到目前為止,這是我的目的:

for(i in 1:nrow(dat_trans)){
  for(j in length(dat_trans)){
    if(dat_trans[i,j] == 1){
      dat_trans[i,j] <- 3
    } else if(dat_trans[i,j] == 2){
      dat_trans[i,j] <- 2
    } else{
      dat_trans[i,j] <- 1
    }
  }
}

因此,我遍歷第一列,獲取每個值並根據if / else的條件對其進行更改,但我仍在學習R,因此,如果我的代碼中有任何指針,請隨時指出。

編輯:代碼

R是向量化語言,因此您實際上不需要內部循環。
另外,如果您注意到4-“舊值” =“新值”,則可以消除if語句。

for(i in 1:ncol(dat_trans)){
        dat_trans[,i] <- 4-dat_trans[,i]
}

現在,外部循環僅在各列之間進行10次迭代,而不是對所有行進行1000次迭代。 這將大大提高性能。

這種操作是交換操作。 不使用for循環交換值的方法很多。

設置一個簡單的數據框:

df <- data.frame(
  col1 = c(1,2,3),
  col2 = c(2,3,1),
  col3 = c(3,1,2)
)

使用虛擬值:

df[df==1] <- 4
df[df==3] <- 1
df[df==4] <- 3

使用臨時變量:

dftemp <- df
df[dftemp==1] <- 3
df[dftemp==3] <- 1

使用乘法/除法和加法/減法:

df <- 4 - df

使用布爾運算:

df <- (df==1) * 3 + (df==2) * 2 + (df==3) * 1

使用按位異或(以防您確實需要速度):

df[df!=2] <- sapply(df, function(x){bitwXor(2,x)})[df!=2]

如果需要嵌套的for循環,則switch功能是一個不錯的選擇。

for(i in seq(ncol(df))){
  for(j in seq(nrow(df))){
    df[j,i] <- switch(df[j,i],3,2,1)
  }
}

如果值的索引值不如1、2和3,則可以使用文本。

for(i in seq(ncol(df))){
  for(j in seq(nrow(df))){
    df[j,i] <- switch(as.character(df[j,i]),
                      "1" = 3,
                      "2" = 2,
                      "3" = 1)
  }
}

這聽起來像merge / join操作。

set.seed(42)
dat_trans <- as.data.frame(
  setNames(lapply(1:3, function(ign) sample(1:3, size=10, replace=TRUE)),
           c("V1", "V2", "V3"))
)
dat_trans
#    V1 V2 V3
# 1   3  2  3
# 2   3  3  1
# 3   1  3  3
# 4   3  1  3
# 5   2  2  1
# 6   2  3  2
# 7   3  3  2
# 8   1  1  3
# 9   2  2  2
# 10  3  2  3

newvals <- data.frame(old = c(1, 3), new = c(3, 1))
newvals
#   old new
# 1   1   3
# 2   3   1

使用dplyrtidyr

library(dplyr)
library(tidyr) # gather, spread
dat_trans %>%
  mutate(rn = row_number()) %>%
  gather(k, v, -rn) %>%
  left_join(newvals, by = c("v" = "old")) %>%
  mutate(v = if_else(is.na(new), v, new)) %>%
  select(-new) %>%
  spread(k, v) %>%
  select(-rn)
#    V1 V2 V3
# 1   1  2  1
# 2   1  1  3
# 3   3  1  1
# 4   1  3  1
# 5   2  2  3
# 6   2  1  2
# 7   1  1  2
# 8   3  3  1
# 9   2  2  2
# 10  1  2  1

(對rn的需求可能是由於我使用的是較舊版本的tidyr :我是0.8.2,盡管最近發布了1.0.0。該版本在spread / gather和引入方面做了很多改進/工作,另外, pivot_*函數可能會更順暢。如果您使用的是更新版本,請嘗試不使用rn部分。)


或者使用“重新編碼”思維方式的更直接的方法:

dat_trans[,c("V1", "V2", "V3")] <- lapply(dat_trans[,c("V1", "V2", "V3")], car::recode, "1=3; 3=1")
# or
dat_trans[,c("V1", "V2", "V3")] <- lapply(dat_trans[,c("V1", "V2", "V3")], dplyr::recode, '1' = 3L, '3' = 1L)

您可以使用分配矩陣am 使用am列1 match() df1屬性的每個值,但選擇列2,然后將其分配給df1 當然是在lapply()中。

df1
#   V1 V2 V3
# 1  1  2  1
# 2  1  2  1
# 3  1  1  2
# 4  1  3  2
# 5  2  3  2

am <- matrix(c(1, 2, 3, 3, 2, 1), 3)
am
#      [,1] [,2]
# [1,]    1    3
# [2,]    2    2
# [3,]    3    1

df1[] <- lapply(df1, function(x) am[match(x, am[,1]), 2])
df1
#   V1 V2 V3
# 1  3  2  3
# 2  3  2  3
# 3  3  3  2
# 4  3  1  2
# 5  2  1  2

數據

df1 <- structure(list(V1 = c(1L, 1L, 1L, 1L, 2L), V2 = c(2L, 2L, 1L, 
3L, 3L), V3 = c(1L, 1L, 2L, 2L, 2L)), class = "data.frame", row.names = c(NA, 
-5L))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM