2017-12-06 18 views
1

편집 : 내 df 창조 오타는 MediaName의 마지막 값에 누락 된 _로, 있었다 ; 이제 수정되었습니다.는 :: 제기 (tibble :: data_frame없이) 돌연변이 "평가 오류 : 문자가 아닌 인수"

난 세번째 변수 Phase의 값에 따라 다른 변수 MediaName의 값의 일부로서 데이터 프레임의 새로운 변수 TrialId을 만들려 및 I는 dplyr::mutate 내에 strsplitifelse을 사용하여 다음과 같이 그렇게 할 수 있다고 생각 : 나는 믿고 있기 때문에

> df$TrialId 
[1] "A1" "B2" "A2" "B1" "A1" "B2" "A2" "B1" "HC" "TC" "RC" 

되는 예상 결과는 그러나 이것은 012의 나에게 다음과 같은 오류를 제공

library(dplyr) 

# Creating a simple data frame for the example 
df <- data.frame(Phase = c(rep("Familiarisation",8),rep("Test",3)), 
       MediaName = c("Flip_A1_G1","Reg_B2_S1","Reg_A2_G1","Flip_B1_S1", 
           "Reg_A1_G2","Flip_B2_S2","Reg_A2_G2","Flip_B1_S2", 
           "HC_A1L","TC_B1R","RC_BL_2R")) 

# Creating a new column 
df <- df %>% 
    mutate(TrialId = ifelse(Phase == "Familiarisation", 
          sapply(strsplit(MediaName, "_"), "[", 2), 
          sapply(strsplit(MediaName, "_"), "[", 1))) 

:

Error in mutate_impl(.data, dots) : 
    Evaluation error: non-character argument. 

내가 쉽게이 문제를 해결 이유를 알 수없이 tibble::data_frame으로,이 작은 예에서 정의하여 내 데이터 프레임을 내 문제를 해결할 수 this SO question 알고있다. 나는 실제 코드 df에서와 마찬가지로 csv 파일 (read.csv())을 읽는 것으로부터 정확히 알 수는 없습니다. 나는 df <- df %>% as_tibble() %>% mutate(...)을 사용하는 것이 비슷한 방식으로 문제를 해결할 것이라고 생각해 왔지만, 왜 그런가? (왜?).

실제로 파일을 읽을 때도 tibble을 사용할 수 있습니까? 아니면 내가해야 할 일을 성취하기위한 다른 방법이 있는데, strsplit을 사용하지 않고있을 수 있습니까?

나는 또한 tidyr::separate을 사용할 수 있지만 Phase의 값에 따라 첫 번째 또는 두 번째 값을 유지해야하므로 정확히 원하는 것을 수행하지 않습니다. this other SO question을 읽는 중입니다.

+1

아마도 'factor'클래스가 있습니다. '문자 '로 변환 한 다음'ifelse'즉'df %> % mutate_all (으로.문자) %> %''mutate' 호출 전에 – akrun

+0

젠장, 이건 너무 뻔한 느낌이어서 시도조차하지 못했지만 효과가있다 ... 왜'tibble :: data_frame'을 사용하는지 이해하는 데 관심이있다. 그것은 작동하지만 as_tibble을 사용하지는 않는다. –

+1

주된 이유는'data_frame'은 기본적으로 모든 비 숫자 컬럼에 대해'character' 클래스를 제공하고'data.frame'을 사용하면'stringsAsFactors = TRUE'가 기본값입니다. ' 'as_tibble'을 사용하기 때문에'data.frame'에 의해 생성 된 컬럼 클래스를 변경하지 않습니다 – akrun

답변

1

문자열이 factor에서 자동으로 변환되었으므로 문제가 발생했습니다. 따라서 문자열이 아닌 개체에 strsplit()을 적용 할 수 없습니다. 내 솔루션은 MediaNamestring 유형으로 변환하기 만하면됩니다.

require(dplyr)  
df <- df %>% 
     dplyr::mutate(MediaName = as.character(levels(df$MediaName))[df$MediaName]) %>% 
       dplyr::mutate(TrialId = ifelse(Phase == "Familiarisation", 
             sapply(strsplit(MediaName, "_"), "[", 2), 
             sapply(strsplit(MediaName, "_"), "[", 1))) 





solution<- c("A1", "B2", "A2", "B1", "A1", "B2", "A2", "B1", "HC", "TC", "RC") 
identical(solution, df$TrialId) 
[1] TRUE 
+0

답을 넓힐 수 있습니까? 나는 돌연변이가 없으면 그것을하는 법을 보지 못한다 ... –

+0

@ArthurSpoon 그러나 나는 당신에게 Mutate 해답을 제시하지 않고있다. 그러나 나의 생각은 문제를 해결한다. 또한 'df $ MediaName <- as.character (levels (df $ MediaName)) [df $ MediaName]'을 사용하는 것을 고려하십시오. 'MediaName'이 'factor'로 저장되어 있고 'strsplit'을 수행하려면 문자열이 필요합니다! – Seymour

+0

그래, 나는 @akrun이 그 시점을 더 일찍 만들었다는 것을 안다. 나는'strsplit'이'grepl '과 같은 방식으로 행동 할 것이라고 생각했으며, 사실은 그렇지 않을 때 인자를 받아 들였다. –

2

당신이 시도 할 수 :

library(tidyverse) 
# your first data 
df_old <- data.frame(Phase = c(rep("Familiarisation",8),rep("Test",3)), 
       MediaName = c("Flip_A1_G1","Reg_B2_S1","Reg_A2_G1","Flip_B1_S1", 
           "Reg_A1_G2","Flip_B2_S2","Reg_A2_G2","Flip_B1_S2", 
           "HC_A1L","TC_B1R","RC_BL2R")) 
df_old %>% 
    separate(MediaName, into=letters[1:3], sep="_", fill = "left", remove = FALSE) %>% 
    select(Phase, MediaName, TrialId=b) 
      Phase MediaName TrialId 
1 Familiarisation Flip_A1_G1  A1 
2 Familiarisation Reg_B2_S1  B2 
3 Familiarisation Reg_A2_G1  A2 
4 Familiarisation Flip_B1_S1  B1 
5 Familiarisation Reg_A1_G2  A1 
6 Familiarisation Flip_B2_S2  B2 
7 Familiarisation Reg_A2_G2  A2 
8 Familiarisation Flip_B1_S2  B1 
9    Test  HC_A1L  HC 
10   Test  TC_B1R  TC 
11   Test RC_BL2R  RC 

그것은 제공된 샘플 데이터를 따라 하드 솔루션입니다. "_"으로 구분하고, 왼쪽에서 세 개의 "_"이 (가) NA 인 3 대신에 두 개가있는 경우. 마지막으로 필요한 열을 선택하십시오.

편집

새로운 데이터로는 다소 복잡합니다. 시도해 볼 수 있습니다.

df %>% 
    add_column(MediaName_keep=df$MediaName) %>% 
    group_by(MediaName_keep) %>% 
    separate_rows(MediaName, sep="_") %>% 
    mutate(n=1:n()) %>% 
    filter((Phase == "Familiarisation" & n == 2) | (Phase == "Test" & n == 1)) %>% 
    select(Phase, MediaName=MediaName_keep, TrialId=MediaName) 
# A tibble: 11 x 3 
# Groups: MediaName [11] 
      Phase MediaName TrialId 
      <fctr>  <fctr> <chr> 
1 Familiarisation Flip_A1_G1  A1 
2 Familiarisation Reg_B2_S1  B2 
3 Familiarisation Reg_A2_G1  A2 
4 Familiarisation Flip_B1_S1  B1 
5 Familiarisation Reg_A1_G2  A1 
6 Familiarisation Flip_B2_S2  B2 
7 Familiarisation Reg_A2_G2  A2 
8 Familiarisation Flip_B1_S2  B1 
9   Test  HC_A1L  HC 
10   Test  TC_B1R  TC 
11   Test RC_BL_2R  RC 

아이디어는 같습니다. 별개이지만이 시간에 새 행을 추가하고 계산하려면 MediaName_keep으로 필터링 한 다음 필요에 따라 필터링하십시오.

+0

나는이 깔끔한 대답을 정말 좋아하지만, 'df' 정의의 오타 때문에 작동하지 않습니다. (현재 수정 됨) :'Phase == "Test"'가 실행될 때 MediaName에 두 개의'_ '가 있지만 때때로 두 번째가 아닌 첫 번째 값이 필요합니다. 이 경우에는 .../ –

+0

@ArthurSpoon 제 편집을 참조하십시오. – Jimbou