条件付き( `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

私の最初の試みは、次のようなa forおよびifステートメントを使用することでした:

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

ご覧のとおり、これでのすべての値がに置き換えjunk$nmられbます。これがなぜこれを行っているのかはわかりますが、元の値があったjunk $ nmのケースのみを置き換えるようには思えませんB

注:私は何とか問題を解決できましたgsubが、RIを学ぶために、元のアプローチを機能させる方法を知りたいと思っています(可能な場合)。


1
元のdata.frame構造にstringsAsFactors = FALSEを追加することもできます。
jimmyb

@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

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
ああ、もう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")どうですか?

しかし、それを2回呼び出します:)
Marek

2
@マレクは頭を平手打ちするちょうどそれが人の就寝時刻かなり過ぎているとき、人はSOのコメントに応答すべきでないことを示すために行きます。もう一度試してみましょう...
ギャビンシンプソン

@Seth Indeed-いいね。手順を分けた理由がわかりませんか?おそらく説明のために...
ギャビンシンプソン、

11

1つのコマンドでこれを行う最も簡単な方法は、コマンドを使用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:列名は1つの問題a <- data.frame(x<-1:10)です。その列名ではxなく、散らかっていx....1.10ます。data.frame(x = 1:10)を使用することをお勧めします。次に、列名がわかります。
IRTFM 2011

@Gavin:置き換えるよりも追加が簡単で、それを要因にしないほうが簡単です。
IRTFM 2011

@Dwinの方が簡単ですか?同意しません-簡単なことについては私の回答を参照してください。レベルを追加すると、たとえばpredict()、新しいデータの因子レベルがモデルのあてはめに使用されたものと一致しない場合に文句を言うモデリングで、あなたを見つけ出すことができます。ショートカットに頼るよりも、適切にフォーマットされたデータを取得するために、長期的にはよりクリーンです。要因にしない方が簡単かもしれませんが、既に要因となっている場合、または何らかのモデリング演習で1つにする必要がある場合は同意します...
Gavin Simpson

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.