แทนที่ค่าในกรอบข้อมูลตามคำสั่งเงื่อนไข ("ถ้า")


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 forand ifstatement ดังนี้:

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

แต่ในฐานะที่ผมมั่นใจว่าคุณสามารถดูนี้แทนที่ของค่าของกับjunk$nm bฉันสามารถดูว่าทำไมถึงทำเช่นนี้ แต่ฉันไม่สามารถดูเหมือนจะได้รับมันจะเปลี่ยนเฉพาะกรณีดังกล่าวของขยะ $ Bนาโนเมตรที่ค่าเดิมคือ

หมายเหตุ: ฉันสามารถแก้ปัญหาได้gsubแต่เพื่อความสนใจในการเรียนรู้ RI ยังคงต้องการทราบวิธีการใช้งานแนวทางเดิมของฉัน (ถ้าเป็นไปได้)


1
คุณอาจต้องการเพิ่ม stringsAsFactors = FALSE ในโครงสร้าง data.frame ดั้งเดิม
jimmyb

@jimmyb ทำไม? ปัจจัยมีประโยชน์และจำเป็นหากมีการสร้างโมเดลด้วยรหัสโมเดลส่วนใหญ่ของ R วิธีที่ถูกต้องในการจัดการกับสิ่งนี้คือการยอมรับว่าข้อมูลเป็นปัจจัย หากคุณไม่ต้องการ / ต้องการการแปลงนี้คุณสามารถทำได้ตามที่คุณพูด หากคุณต้องการปัจจัยมีวิธีง่ายๆในการจัดการที่ @Kenny ต้องการดำเนินการ
Gavin Simpson

1
ดังนั้นปัจจัยที่เคยได้รับความนิยมมากขึ้นเนื่องจากประสิทธิภาพอย่างไรก็ตามตอนนี้สตริงไม่เปลี่ยนรูปและแฮชค่าของปัจจัยนั้นไม่ค่อยชัดเจนเนื่องจากฟังก์ชัน R พื้นฐานส่วนใหญ่จะแปลงเพียงแค่ (แม้ว่าจะมีคำเตือน) โดยตรง ฉันคิดว่าปัจจัยต่างๆส่งผลให้เกิดข้อบกพร่องจำนวนมากที่ฉันพบในรหัส R ของประชาชน
jimmyb

คำตอบ:


218

แปลงนาโนเมตรเป็นอักขระได้ง่ายขึ้นจากนั้นทำการเปลี่ยนแปลง:

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

44

อีกวิธีหนึ่งที่มีประโยชน์ในการแทนที่ค่า

library(plyr)
junk$nm <- revalue(junk$nm, c("B"="b"))

25

คำตอบสั้น ๆ คือ:

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

ดูเวกเตอร์ดัชนีใน R บทนำ (ถ้าคุณยังไม่ได้อ่าน)


แก้ไข ดังที่สังเกตเห็นในความคิดเห็นโซลูชันนี้ใช้ได้กับเวกเตอร์อักขระจึงล้มเหลวในข้อมูลของคุณ

สำหรับปัจจัยวิธีที่ดีที่สุดคือการเปลี่ยนระดับ:

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

นอกจากนี้ระยะสั้น: การใช้งานของ% ใน% c("B","C")เท่านั้นจริงๆช่วยถ้าคุณมีชุดด้านขวาเป็น การทำเป็นjunk$nm[junk$nm == "B"]วิธีที่ดีกว่า
Thilo

1
อ้ออีกอย่างที่สำคัญเพิ่มเติม: การทำเช่นนี้ต้องเพิ่มระดับปัจจัยbให้กับปัจจัยนาโนเมตรก่อน ในความเป็นจริงแล้วเวอร์ชันของ 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 เมื่อเป็นเวลาก่อนนอน ลองอีกครั้ง ...
Gavin Simpson

@Seth แน่นอน - ดี ไม่แน่ใจว่าทำไมฉันถึงแยกขั้นตอน? บางทีสำหรับการจัดนิทรรศการ ...
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

คุณไม่จำเป็นต้องเพิ่มbระดับเพียงเปลี่ยนระดับที่เป็นไปB b
Gavin Simpson

@KennyPeanuts: a <- data.frame(x<-1:10)ชื่อคอลัมน์เป็นปัญหาหนึ่งดูที่ ชื่อคอลัมน์ของมันไม่ได้แต่ยุ่งx x....1.10ควรใช้ data.frame (x = 1: 10) แล้วคุณจะรู้ว่าชื่อคอลัมน์ของคุณคืออะไร
IRTFM

@Gavin: ง่ายต่อการเพิ่มมากกว่าการแทนที่และง่ายกว่าที่จะไม่ทำให้เป็นปัจจัย
IRTFM

@Dwin ง่ายกว่าไหม ฉันไม่เห็นด้วย - ดูคำตอบของฉันสำหรับสิ่งง่ายๆ การเพิ่มระดับสามารถจับคุณได้โดยพูดในการสร้างแบบจำลองpredict()ซึ่งจะบ่นหากระดับปัจจัยในข้อมูลใหม่ไม่ตรงกับระดับที่ใช้เพื่อให้พอดีกับโมเดล ทำความสะอาดในระยะยาวเพื่อให้ได้ข้อมูลที่จัดรูปแบบตามที่คุณต้องการอย่างถูกต้องดีกว่าพึ่งพาทางลัด ฉันเห็นด้วยว่ามันอาจจะง่ายกว่าที่จะไม่ทำให้มันเป็นปัจจัย แต่ถ้ามันมีอยู่แล้วหรือจำเป็นต้องเป็นหนึ่งในแบบฝึกหัดการสร้างแบบจำลอง ...
Gavin Simpson

1

หากคุณกำลังทำงานกับตัวแปรอักขระ (โปรดทราบว่าstringsAsFactorsเป็นเท็จที่นี่) คุณสามารถใช้การแทนที่:

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.