조건부 (`if`) 문을 기반으로 데이터 프레임의 값 바꾸기


122

아래에 코딩 된 R 데이터 프레임에서 B 나타나는 모든 시간을 b.

junk <- data.frame(x <- rep(LETTERS[1:4], 3), y <- letters[1:12])
colnames(junk) <- c("nm", "val")

이것은 다음을 제공합니다 :

   nm val
1   A   a
2   B   b
3   C   c
4   D   d
5   A   e
6   B   f
7   C   g
8   D   h
9   A   i
10  B   j
11  C   k
12  D   l

내 초기 시도는 다음 forif같은 및 문 을 사용하는 것이 었습니다 .

for(i in junk$nm) if(i %in% "B") junk$nm <- "b"

하지만 보시다시피 모든 값을 junk$nm로 대체합니다 b. 왜 이런 일을하는지 알 수 있지만 원래 값이 .nm 인 junk $ nm의 경우 만 대체 할 수없는 것 같습니다 B.

참고 : 문제를 해결할 수 gsub있었지만 학습을 위해 RI는 여전히 내 원래 접근 방식을 작동하는 방법을 알고 싶습니다 (가능한 경우).


1
원래 data.frame 구성에 stringsAsFactors = FALSE를 추가 할 수 있습니다.
jimmyb 2011

@jimmyb 왜? 요인은 유용하며 대부분의 R 모델링 코드로 모델링하는 경우 필요합니다. 이를 처리하는 올바른 방법은 데이터가 요인임을 인정하는 것입니다. 이 변환을 원하지 않거나 필요하지 않으면 말한대로 할 수 있습니다. 요인을 원한다면 @Kenny가 수행하려는 조작을 쉽게 수행 할 수 있습니다.
Gavin Simpson

1
따라서 성능 때문에 요인이 더 많이 사용되었지만 이제는 문자열이 변경 불가능하고 요인의 값이 해싱 되었기 때문에 대부분의 기본 R 기능이 (경고와 함께) 직접 변환하기 때문에 요인의 값이 명확하지 않습니다. 나는 요인이 사람들의 R 코드에서 찾은 상당한 수의 버그를 초래한다고 생각합니다.
jimmyb 2011

답변:


217

nm를 문자로 변환 한 다음 변경하는 것이 더 쉽습니다.

junk$nm <- as.character(junk$nm)
junk$nm[junk$nm == "B"] <- "b"

편집 : 그리고 실제로 nm를 요소로 유지해야하는 경우 마지막에 추가하십시오.

junk$nm <- as.factor(junk$nm)

4
as.character ()는 요소 작업을 할 때 삶을 훨씬 더 쉽게 만듭니다. +1
Brandon Bertelsen 2011

4
열이 여러 개인 경우 어떻게됩니까?
geodex


25

짧은 대답은 다음과 같습니다.

junk$nm[junk$nm %in% "B"] <- "b"

R 소개 에서 인덱스 벡터를 살펴보십시오 (아직 읽지 않은 경우).


편집하다. 주석에서 알 수 있듯이이 솔루션은 문자 벡터에 대해 작동하므로 데이터에 실패합니다.

가장 좋은 방법은 수준을 변경하는 것입니다.

levels(junk$nm)[levels(junk$nm)=="B"] <- "b"

짧은 추가 : % in %의 사용법은 오른쪽에 c("B","C"). 하는 junk$nm[junk$nm == "B"]것이 더 좋은 방법입니다.
Thilo 2011

1
아, 또 다른 중요한 추가 사항 : 이렇게하려면 먼저 요인 수준 b을 요인 nm에 추가해야합니다 . 실제로 요소가 아닌 캐릭터로 작업하려면 diliop의 버전이 더 좋습니다. (항상 변수의 유형을 먼저 생각하십시오!)
Thilo

데이터가 요인이기 때문에 @Kenny가 만든 데이터에서는 작동하지 않습니다. 단계를 잊었거나 문자를 요인으로 변환하는 것을 중지 할 수있는 전역 설정이 있습니까?
Gavin Simpson

4
@Thilo 사이의 중요한 차이점 중 하나 %in%==있다 NA처리가 : c(1,2,NA)==1제공 TRUE, FALSE, NA하지만 c(1,2,NA) %in% 1있습니다 TRUE, FALSE, FALSE. 그리고 네,이 작업인지 확인하는 것을 잊었습니다 : /
Marek

20

당신이 보여주는 데이터는 요소이기 때문에 약간 복잡합니다. @diliop의 답변 nm은 문자 변수 로 변환하여 문제에 접근합니다 . 원래 요인으로 돌아가려면 추가 단계가 필요합니다.

대안은 제자리에있는 요인의 수준을 조작하는 것입니다.

> lev <- with(junk, levels(nm))
> lev[lev == "B"] <- "b"
> junk2 <- within(junk, levels(nm) <- lev)
> junk2
   nm val
1   A   a
2   b   b
3   C   c
4   D   d
5   A   e
6   b   f
7   C   g
8   D   h
9   A   i
10  b   j
11  C   k
12  D   l

이것은 매우 간단하며 levels().

편집 : 주석에서 @Seth가 언급했듯이 이것은 명확성을 잃지 않고 한 줄로 수행 할 수 있습니다.

within(junk, levels(nm)[levels(nm) == "B"] <- "b")

6
좋은. 의 대체 기능에 대해 몰랐습니다 levels(). 한 라이너는 junk <- within(junk, levels(nm)[levels(nm)=="B"] <- "b")어떻습니까?

그러나 당신은 그것을 두 번 부릅니다 :)
Marek

2
@Marek이 머리를 때린다 . 취침 시간이 훨씬 지났을 때 SO에 대한 댓글에 응답해서는 안된다는 것을 보여주기 위해 간다. 수 있습니다 ... 다시 시도
개빈 심슨에게

@Seth Indeed-좋아. 단계를 분리 한 이유가 확실하지 않습니까? 아마도 박람회를 위해 ...
Gavin Simpson

11

하나의 명령에서이 작업을 수행하는 가장 쉬운 방법은 명령을 사용하는 것입니다. which또한 다음과 같이 요소를 캐릭터로 변경할 필요가 없습니다.

junk$nm[which(junk$nm=="B")]<-"b"

5

에서 요인 변수를 만들었 nm으므로이를 피하거나 요인 속성에 추가 수준을 추가해야합니다. 또한 <-data.frame ()에 대한 인수를 사용하지 않아야합니다.

옵션 1:

junk <- data.frame(x = rep(LETTERS[1:4], 3), y =letters[1:12], stringsAsFactors=FALSE)
junk$nm[junk$nm == "B"] <- "b"

옵션 2 :

levels(junk$nm) <- c(levels(junk$nm), "b")
junk$nm[junk$nm == "B"] <- "b"
junk

@DWin은 문제에 대한 귀하의 의견과 변수 유형을 고려해야 할 필요성에 감사드립니다. @diliop의 대답이 첫 번째 작업이기 때문에 수락했습니다. 나는 <-vs =에 대해 많은 문제가 있다는 것을 알고 있지만 (짧게 대답 할 수 있다면) 왜 =와 함께 사용해야 data.frame합니까?
DQdlM 2011

당신은 추가 할 필요가 없습니다 b그냥 레벨 변경, 레벨로 B로를 b.
Gavin Simpson

@KennyPeanuts : 열 이름은 하나의 문제 a <- data.frame(x<-1:10)입니다. 열 이름이 x아니라 오히려 지저분 x....1.10합니다. data.frame (x = 1 : 10)을 사용하는 것이 좋습니다. 그러면 열 이름이 무엇인지 알 수 있습니다.
IRTFM 2011

@Gavin : 교체하는 것보다 추가하기가 더 쉬우 며이를 요인으로 만들지 않는 것이 더 쉽습니다.
IRTFM 2011

@ 드윈 더 쉽게? 동의하지 않습니다. 간단한 내용은 내 답변을 참조하십시오. 수준을 추가하면 predict()새 데이터의 요인 수준이 모델에 적합하는 데 사용 된 수준과 일치하지 않는 경우 불평 할 모델링 에서 예를 들어 파악할 수 있습니다. 바로 가기에 의존하는 것보다 원하는대로 데이터를 적절하게 형식화하려면 장기적으로 더 깨끗합니다. 나는 그것이 요인이하지에 쉽게 수 있습니다 동의하지만, 이미 하나, 또는 요구의 경우 일부 모델링 운동 하나 ...로
개빈 심슨

1

문자 변수로 작업하는 경우 ( stringsAsFactors여기서는 false 임) replace를 사용할 수 있습니다.

junk <- data.frame(x <- rep(LETTERS[1:4], 3), y <- letters[1:12], stringsAsFactors = FALSE)
colnames(junk) <- c("nm", "val")

junk$nm <- replace(junk$nm, junk$nm == "B", "b")
junk
#    nm val
# 1   A   a
# 2   b   b
# 3   C   c
# 4   D   d
# ...

0
stata.replace<-function(data,replacevar,replacevalue,ifs) {
  ifs=parse(text=ifs)
  yy=as.numeric(eval(ifs,data,parent.frame()))
  x=sum(yy)
  data=cbind(data,yy)
  data[yy==1,replacevar]=replacevalue
  message=noquote(paste0(x, " replacement are made"))
  print(message)
  return(data[,1:(ncol(data)-1)])
}

아래 줄을 사용하여이 함수를 호출하십시오.

d=stata.replace(d,"under20",1,"age<20")
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.