barcode

R 배워보기- 6.3. Manipulating data-Data Frames

Coding/R

들어가기 전에 작은 시범조교를 하나(아니고 넷) 준비했음.. 다운 ㄱㄱ 

example4.csv
0.00MB
example3.csv
0.00MB
example2.csv
0.00MB
example.csv
0.00MB

각 csv파일의 내용물을 R로 불러오면 

> df=read.csv('/home/koreanraichu/example.csv',sep=";")
> df
          ID Interesred.in  Class
1 kimlab0213        Python  Basic
2   ahn_0526        Python Medium
3   peponi01             R  Basic
4  kuda_koma             R Expert
5 comma_life          Java  Basic
6 wheresjohn          Java Medium
7 hanguk_joa        Python Expert
8   sigma_00             R  Basic
9  kokoatalk          Java  Basic

(example, 구분자 세미콜론)

 

> df2=read.csv('/home/koreanraichu/example2.csv')
> df2
       ID              Product.name Category.1   Category.2  Price Order Cancel
1  LB-001                   LB agar     Medium     Bacteria  55000     5      0
2  LB-002                  LB broth     Medium     Bacteria  50000     6      1
3  MS-001                   MS agar     Medium        Plant  65000     7      2
4  MS-002                  MS broth     Medium        Plant  60000     7      0
5  DM-001                      DMEM     Medium Cell culture  90000    20      0
6  BC-001                 BCIG agar     Medium     Bacteria  70000    10      2
7  MS-003 MS agar(w/ plant hormone)     Medium        Plant  75000     2      1
8  PI-001             Pasteur pipet Consumable Experimental  10000    30      5
9  PI-002           Pipet-AID(10ml) Consumable Experimental  15000    45      0
10 PI-003           Pipet-AID(25ml) Consumable Experimental  25000    45      5
11 PI-004                 Pipet-AID  Equipment Experimental 100000     2      0
12 GL-001               Slide glass  Glasswear Experimental  20000    50      0
13 GL-002               Cover glass  Glasswear Experimental  20000    55      1

(example2, 구분자 콤마) 만들어놓고 잊혀진 파일 

 

> df3=read.csv('/home/koreanraichu/example3.csv',sep="\t")
> df3
                    name Chemical.formula MW.g.mol.1. Density.g.cm.3.
1        Sodium chloride             NaCl      58.443         2.17000
2            Acetic acid           C2H4O2      60.052         1.04900
3                Glucose          C6H12O6     180.156         1.54000
4    Mercury(II) sulfide              HgS     232.660         8.10000
5                Toluene             C7H8      92.141         0.87000
6                 Phenol            C6H6O      94.113         1.07000
7               Glycerol           C3H8O3      92.094         1.26100
8                   PETN        C5H8N4O12     316.137         1.77000
9                Ethanol            C2H6O      46.069         0.78945
10                   SDS      C12H25NaSO4     288.372         1.01000
11         Chlorophyll a     C55H72MgN4O5     893.509         1.07900
12 Citric acid anhydrous           C6H8O7     192.123         1.66500
13      Boron tribromide             BBr3     250.520         2.64300

(example3, 구분자 탭)

 

> df4=read.csv('/home/koreanraichu/example4.csv',sep=" ")
> df4
        category         compound_name chemical_formula Molecular_mass.g.mol.1.
1         Borane                Borane              BH3                  13.830
2         Borane        Ammonia_borane             BNH6                  30.865
3         Borane           Tetraborane            B4H10                  53.320
4         Borane        Pentaborane(9)             B5H9                  63.120
5         Borane        Octadecaborane           B18H22                 216.770
6          Oxide     Caesium_monooxide             Cs2O                 281.810
7          Oxide        Actinium_oxide            Ac2O3                 502.053
8          Oxide      Triuranium_oxide             U3O8                 842.100
9          Oxide Technetium(VII)_oxide            Tc2O7                 307.810
10         Oxide     Thorium_monooxide              ThO                 248.040
11        Alkane               Methane              CH4                  16.043
12        Alkane                Hexane            C6H14                  86.178
13        Alkane                Nonane            C9H20                 128.259
14        Alkane             Tridecane           C13H28                 184.367
15        Alkane          Hentricotane           C31H64                 436.853
16 Sugar_alcohol              Mannotol          C6H14O6                 182.172
17 Sugar_alcohol               Xylitol          C5H12O5                 152.146
18 Sugar_alcohol               Fucitol          C6H14O5                 166.170
19 Sugar_alcohol             Volemitol          C7H16O7                 212.198
20 Sugar_alcohol              Inositol          C6H12O6                 180.160
21  IARC_group_1          Aflatoxin_B1         C17H12O6                 312.277
22  IARC_group_1           Cicloaporin    C61H111N11O12                1202.635
23  IARC_group_1      Gallium_arsenide             GaAs                 144.615
24  IARC_group_1             Melphalan    C13H18Cl2N2O2                 305.200
25  IARC_group_1          Azothioprine        C9H7N7O2S                 277.260

(example4, 구분자 공백)

받아뒀다가 이거 할 때도 쓰고 판다스 할 때도 쓰세요. 참고로 해당 csv파일은 엑셀로도 열 수는 있지만 일단 만들 때는 지에딧으로 만들었음. (gedit filename.확장자 하면 그걸로 뜹디다)


Python과 R의 데이터프레임 

-R은 데이터프레임을 다루기 위해 따로 뭘 깔 필요가 없다. 물론 일부 기능을 위해 plyr 라이브러리를 깔긴 해야 하지만 라이브러리 없이도 할 수는 있다. (python은 일단 판다스부터 깔고 봐야 한다)


-얘도 구분자 지정 안 해주면 default는 ,다. (위에 불러오는 코드를 보면 세미콜론과 탭, 공백은 따로 sep=""옵션을 줬다) 원래 csv의 cs가 comma seperated의 약자. 

 

컬럼명 바꾸기

이번 시범조교는 2번 파일. 해당 파일의 컬럼명은 

> names(df2)
[1] "ID"           "Product.name" "Category.1"   "Category.2"   "Price"       
[6] "Order"        "Cancel"

이렇게 되어 있다. 

우리의 신입사원 김부추씨는 저 csv파일을 받아서 R로 깔끔하게 정리를 했다. (order는 주문량, cancel은 주문 취소량) 그런데 중간보고를 위해 상급자에게 갔더니 상급자의 한마디! 

"부추씨, 이거 정리 되게 깔끔하게 잘 했어. 그런데 저기 ID가 한번에 딱 봐서는 모를 것 같거든... ID만 Product ID로 바꿔서 제출하면 될 것 같아. "

김부추 멘붕왔다. 헐 그럼 csv파일단에서 수정 다시 해야 함? 이거 하느라 개고생했는데...OTL 근데 부추가 누구죠 아 제 텅비드 이름인데요 이제 텅비드를 취업시키는건가 아 걍 해요 

> library(plyr)
> rename(df2,c("ID"="Product.ID"))
Product.ID              Product.name Category.1   Category.2  Price Order
1      LB-001                   LB agar     Medium     Bacteria  55000     5
2      LB-002                  LB broth     Medium     Bacteria  50000     6
3      MS-001                   MS agar     Medium        Plant  65000     7
4      MS-002                  MS broth     Medium        Plant  60000     7
5      DM-001                      DMEM     Medium Cell culture  90000    20
6      BC-001                 BCIG agar     Medium     Bacteria  70000    10
7      MS-003 MS agar(w/ plant hormone)     Medium        Plant  75000     2
8      PI-001             Pasteur pipet Consumable Experimental  10000    30
9      PI-002           Pipet-AID(10ml) Consumable Experimental  15000    45
10     PI-003           Pipet-AID(25ml) Consumable Experimental  25000    45
11     PI-004                 Pipet-AID  Equipment Experimental 100000     2
12     GL-001               Slide glass  Glasswear Experimental  20000    50
13     GL-002               Cover glass  Glasswear Experimental  20000    55
   Cancel
1       0
2       1
3       2
4       0
5       0
6       2
7       1
8       5
9       0
10      5
11      0
12      0
13      1

파일단에서 손댈 것도 없이 그냥 저거 한 방이면 끝난다. (물론 plyr 라이브러리는 깔아두셨죠?) 참고로 얘는 저거 적용하고 names(df2)로 불러보면 ID로 나온다. (df2=코드 하고 해야 하나...)

네? 당장 보고 들어가야 해서 plyr 라이브러리 깔 시간이 없다고요? 

> names(df2)[names(df2)=="ID"]="Product.ID"
> df2
   Product.ID              Product.name Category.1   Category.2  Price Order
1      LB-001                   LB agar     Medium     Bacteria  55000     5
2      LB-002                  LB broth     Medium     Bacteria  50000     6
3      MS-001                   MS agar     Medium        Plant  65000     7
4      MS-002                  MS broth     Medium        Plant  60000     7
5      DM-001                      DMEM     Medium Cell culture  90000    20
6      BC-001                 BCIG agar     Medium     Bacteria  70000    10
7      MS-003 MS agar(w/ plant hormone)     Medium        Plant  75000     2
8      PI-001             Pasteur pipet Consumable Experimental  10000    30
9      PI-002           Pipet-AID(10ml) Consumable Experimental  15000    45
10     PI-003           Pipet-AID(25ml) Consumable Experimental  25000    45
11     PI-004                 Pipet-AID  Equipment Experimental 100000     2
12     GL-001               Slide glass  Glasswear Experimental  20000    50
13     GL-002               Cover glass  Glasswear Experimental  20000    55
   Cancel
1       0
2       1
3       2
4       0
5       0
6       2
7       1
8       5
9       0
10      5
11      0
12      0
13      1

ㄱㄱ 

 

> names(df2)=sub("ID","Product.ID",names(df2))
> df2
   Product.Product.ID              Product.name Category.1   Category.2  Price
1              LB-001                   LB agar     Medium     Bacteria  55000
2              LB-002                  LB broth     Medium     Bacteria  50000
3              MS-001                   MS agar     Medium        Plant  65000
4              MS-002                  MS broth     Medium        Plant  60000
5              DM-001                      DMEM     Medium Cell culture  90000
6              BC-001                 BCIG agar     Medium     Bacteria  70000
7              MS-003 MS agar(w/ plant hormone)     Medium        Plant  75000
8              PI-001             Pasteur pipet Consumable Experimental  10000
9              PI-002           Pipet-AID(10ml) Consumable Experimental  15000
10             PI-003           Pipet-AID(25ml) Consumable Experimental  25000
11             PI-004                 Pipet-AID  Equipment Experimental 100000
12             GL-001               Slide glass  Glasswear Experimental  20000
13             GL-002               Cover glass  Glasswear Experimental  20000
   Order Cancel
1      5      0
2      6      1
3      7      2
4      7      0
5     20      0
6     10      2
7      2      1
8     30      5
9     45      0
10    45      5
11     2      0
12    50      0
13    55      1
> names(df2)=gsub("D","d",names(df2))
> df2
   Product.Product.Id              Product.name Category.1   Category.2  Price
1              LB-001                   LB agar     Medium     Bacteria  55000
2              LB-002                  LB broth     Medium     Bacteria  50000
3              MS-001                   MS agar     Medium        Plant  65000
4              MS-002                  MS broth     Medium        Plant  60000
5              DM-001                      DMEM     Medium Cell culture  90000
6              BC-001                 BCIG agar     Medium     Bacteria  70000
7              MS-003 MS agar(w/ plant hormone)     Medium        Plant  75000
8              PI-001             Pasteur pipet Consumable Experimental  10000
9              PI-002           Pipet-AID(10ml) Consumable Experimental  15000
10             PI-003           Pipet-AID(25ml) Consumable Experimental  25000
11             PI-004                 Pipet-AID  Equipment Experimental 100000
12             GL-001               Slide glass  Glasswear Experimental  20000
13             GL-002               Cover glass  Glasswear Experimental  20000
   Order Cancel
1      5      0
2      6      1
3      7      2
4      7      0
5     20      0
6     10      2
7      2      1
8     30      5
9     45      0
10    45      5
11     2      0
12    50      0
13    55      1

sub(), gsub()도 당연히 된다. (라이브러리 없어도 됨)

 

컬럼 첨삭하기

> df
          ID Interesred.in  Class
1 kimlab0213        Python  Basic
2   ahn_0526        Python Medium
3   peponi01             R  Basic
4  kuda_koma             R Expert
5 comma_life          Java  Basic
6 wheresjohn          Java Medium
7 hanguk_joa        Python Expert
8   sigma_00             R  Basic
9  kokoatalk          Java  Basic

example 1번을 모셔봅시다. 예제 1번은 회원들에게 프로그래밍 언어 강의를 제공하는 웹 플랫폼을 상정하고 만든 것이다. (그래서 파이썬 R 자바가... 씨언어 어디갔어요 씨언어 뭐 씨? 씨샵? 씨쁠쁠?) 그러니까 ID는 회원 아이디, 관심분야는 파이썬, 클래스는 강의의 난이도(초급/중급/전문가). 

씁 근데 이렇게만 해서는 이 아이디의 주인이 해당 수업을 다 이수했나 아닌가를 모르겠다. 그래서 P/F 컬럼을 새로 추가하고자 한다. 

 

> df$PF=c("P","P","F","F","P","F","P","F","F")
> df
          ID Interesred.in  Class PF
1 kimlab0213        Python  Basic  P
2   ahn_0526        Python Medium  P
3   peponi01             R  Basic  F
4  kuda_koma             R Expert  F
5 comma_life          Java  Basic  P
6 wheresjohn          Java Medium  F
7 hanguk_joa        Python Expert  P
8   sigma_00             R  Basic  F
9  kokoatalk          Java  Basic  F

제목이요? 저거는 따옴표로 감싸지 않는 이상 공백 있으면 에러뜸미다... (언더바 ㄱㄱ)

 

> df[,"Pass or Fail"]=c("P","P","F","F","P","F","P","F","F")
> df
          ID Interesred.in  Class Pass or Fail
1 kimlab0213        Python  Basic            P
2   ahn_0526        Python Medium            P
3   peponi01             R  Basic            F
4  kuda_koma             R Expert            F
5 comma_life          Java  Basic            P
6 wheresjohn          Java Medium            F
7 hanguk_joa        Python Expert            P
8   sigma_00             R  Basic            F
9  kokoatalk          Java  Basic            F

아니면 이건 어떠심? 

그렇게 아이디어를 제안한 김상추씨. 하지만 선배 김양상추씨(둘 다 본인 포켓몬 이름임... 릴리요였나...)는 그 제안을 듣고 이렇게 말했다. 

"좋은 아이디어긴 한데... P/F로 매기게 되면 강의 이수여부는 알 수 있지만, 출결 관리까지 알기는 좀 힘들 것 같아. 차라리 P/F를 빼고 출석율을 넣거나, 출석율이랑 병기하는 건 어때? "

> df$PF=NULL
> df
          ID Interesred.in  Class
1 kimlab0213        Python  Basic
2   ahn_0526        Python Medium
3   peponi01             R  Basic
4  kuda_koma             R Expert
5 comma_life          Java  Basic
6 wheresjohn          Java Medium
7 hanguk_joa        Python Expert
8   sigma_00             R  Basic
9  kokoatalk          Java  Basic

그래서 김상추씨는 PF 컬럼을 빼버렸다. 

참고로 

# Ways to add a column
data$size      <- c("small", "large", "medium")
data[["size"]] <- c("small", "large", "medium")
data[,"size"]  <- c("small", "large", "medium")
data$size      <- 0   # Use the same value (0) for all rows
# Ways to remove the column
data$size      <- NULL
data[["size"]] <- NULL
data[,"size"]  <- NULL
data[[3]]      <- NULL
data[,3]       <- NULL
data           <- subset(data, select=-size)

이건 뭐 니들이 뭘 좋아할 지 몰라서 다 넣었어도 아니고 첨삭 방법이 되게 많다. 

 

컬럼 오더 바꾸기

이번 시범조교... 

> df3
                    name Chemical.formula MW.g.mol.1. Density.g.cm.3.
1        Sodium chloride             NaCl      58.443         2.17000
2            Acetic acid           C2H4O2      60.052         1.04900
3                Glucose          C6H12O6     180.156         1.54000
4    Mercury(II) sulfide              HgS     232.660         8.10000
5                Toluene             C7H8      92.141         0.87000
6                 Phenol            C6H6O      94.113         1.07000
7               Glycerol           C3H8O3      92.094         1.26100
8                   PETN        C5H8N4O12     316.137         1.77000
9                Ethanol            C2H6O      46.069         0.78945
10                   SDS      C12H25NaSO4     288.372         1.01000
11         Chlorophyll a     C55H72MgN4O5     893.509         1.07900
12 Citric acid anhydrous           C6H8O7     192.123         1.66500
13      Boron tribromide             BBr3     250.520         2.64300

이분임... 

보기만 해도 으아아가 절로 나온다면 정상입니다. 난 아니지만. 이사람 집에 주기율표 있다 끝말잇기 잘하시겠네요 아뇨 그건 아닙니다 원래 주기율표 다 꿰고 있으면 완급조절도 가능하다 코페르니슘! 슘페터! 터븀! 

 

> df3[c(4,3,2,1)]
   Density.g.cm.3. MW.g.mol.1. Chemical.formula                  name
1          2.17000      58.443             NaCl       Sodium chloride
2          1.04900      60.052           C2H4O2           Acetic acid
3          1.54000     180.156          C6H12O6               Glucose
4          8.10000     232.660              HgS   Mercury(II) sulfide
5          0.87000      92.141             C7H8               Toluene
6          1.07000      94.113            C6H6O                Phenol
7          1.26100      92.094           C3H8O3              Glycerol
8          1.77000     316.137        C5H8N4O12                  PETN
9          0.78945      46.069            C2H6O               Ethanol
10         1.01000     288.372      C12H25NaSO4                   SDS
11         1.07900     893.509     C55H72MgN4O5         Chlorophyll a
12         1.66500     192.123           C6H8O7 Citric acid anhydrous
13         2.64300     250.520             BBr3      Boron tribromide

오더를 이렇게 컬럼명으로 바꾸거나(...)

> df3[c("Chemical.formula","name","MW.g.mol.1.","Density.g.cm.3.")]
   Chemical.formula                  name MW.g.mol.1. Density.g.cm.3.
1              NaCl       Sodium chloride      58.443         2.17000
2            C2H4O2           Acetic acid      60.052         1.04900
3           C6H12O6               Glucose     180.156         1.54000
4               HgS   Mercury(II) sulfide     232.660         8.10000
5              C7H8               Toluene      92.141         0.87000
6             C6H6O                Phenol      94.113         1.07000
7            C3H8O3              Glycerol      92.094         1.26100
8         C5H8N4O12                  PETN     316.137         1.77000
9             C2H6O               Ethanol      46.069         0.78945
10      C12H25NaSO4                   SDS     288.372         1.01000
11     C55H72MgN4O5         Chlorophyll a     893.509         1.07900
12           C6H8O7 Citric acid anhydrous     192.123         1.66500
13             BBr3      Boron tribromide     250.520         2.64300

...일단 저건 숫자가 더 효율적임. 

 

> df3[,c(1,2,4,3)]
                    name Chemical.formula Density.g.cm.3. MW.g.mol.1.
1        Sodium chloride             NaCl         2.17000      58.443
2            Acetic acid           C2H4O2         1.04900      60.052
3                Glucose          C6H12O6         1.54000     180.156
4    Mercury(II) sulfide              HgS         8.10000     232.660
5                Toluene             C7H8         0.87000      92.141
6                 Phenol            C6H6O         1.07000      94.113
7               Glycerol           C3H8O3         1.26100      92.094
8                   PETN        C5H8N4O12         1.77000     316.137
9                Ethanol            C2H6O         0.78945      46.069
10                   SDS      C12H25NaSO4         1.01000     288.372
11         Chlorophyll a     C55H72MgN4O5         1.07900     893.509
12 Citric acid anhydrous           C6H8O7         1.66500     192.123
13      Boron tribromide             BBr3         2.64300     250.520

뭔 매트릭스 매기듯이 이렇게도 한다. 

 

> df3[2]
   Chemical.formula
1              NaCl
2            C2H4O2
3           C6H12O6
4               HgS
5              C7H8
6             C6H6O
7            C3H8O3
8         C5H8N4O12
9             C2H6O
10      C12H25NaSO4
11     C55H72MgN4O5
12           C6H8O7
13             BBr3

2열을 뽑아봤습니다. 

 

> df3[,2]
 [1] NaCl         C2H4O2       C6H12O6      HgS          C7H8        
 [6] C6H6O        C3H8O3       C5H8N4O12    C2H6O        C12H25NaSO4 
[11] C55H72MgN4O5 C6H8O7       BBr3        
13 Levels: BBr3 C12H25NaSO4 C2H4O2 C2H6O C3H8O3 C55H72MgN4O5 ... NaCl

이렇게 하면 벡터처럼 뽑힌다. (레벨이 있는 걸 보면 아시겠지만 팩터임)

 

> df3[,2,drop=FALSE]
   Chemical.formula
1              NaCl
2            C2H4O2
3           C6H12O6
4               HgS
5              C7H8
6             C6H6O
7            C3H8O3
8         C5H8N4O12
9             C2H6O
10      C12H25NaSO4
11     C55H72MgN4O5
12           C6H8O7
13             BBr3

drop=FALSE를 주면 표 형태로 뽑힌다. 저게 그 시리즌가 그거냐 그건 판다스고 

 

파이널 퓨전

> df
          ID Interesred.in  Class Pass or Fail
1 kimlab0213        Python  Basic            P
2   ahn_0526        Python Medium            P
3   peponi01             R  Basic            F
4  kuda_koma             R Expert            F
5 comma_life          Java  Basic            P
6 wheresjohn          Java Medium            F
7 hanguk_joa        Python Expert            P
8   sigma_00             R  Basic            F
9  kokoatalk          Java  Basic            F

아까 그거 맞다. 여기에다가 클래스별 가격 정보를 추가할건데... 그럼 가격표가 어디 있느냐고? 

 

> df5=read.table(header=TRUE, text='
+ Class;Price
+ Basic;Free
+ Medium;1000
+ Expert;2000
+ ',sep=";")
> df5
   Class Price
1  Basic  Free
2 Medium  1000
3 Expert  2000

여기요. 

이 표를 파이널(별)퓨전해달라는 업무를 받은 김상추씨(아니 진짜 내 포켓몬 이름이여 이름이 왜그래요 부추때문에 추로 끝나는 야채는 다 넣었음 다행히도 고추는 없습니다 그건 어감이 거시기해서)... 아니 그럼 새로 컬럼 만들고 저걸 일일이 다 써요? ㄴㄴ 

> merge(df,df5,"Class")
   Class         ID Interesred.in Pass or Fail Price
1  Basic kimlab0213        Python            P  Free
2  Basic   peponi01             R            F  Free
3  Basic   sigma_00             R            F  Free
4  Basic comma_life          Java            P  Free
5  Basic  kokoatalk          Java            F  Free
6 Expert hanguk_joa        Python            P  2000
7 Expert  kuda_koma             R            F  2000
8 Medium   ahn_0526        Python            P  1000
9 Medium wheresjohn          Java            F  1000

공통된 컬럼인 Class를 기반으로 파이널퓨전 하면 된다. 

> df6[c(3,4,5,1,2)]
          ID Interesred.in Pass or Fail  Class Price
1 kimlab0213        Python            P  Basic  Free
2   peponi01             R            F  Basic  Free
3   sigma_00             R            F  Basic  Free
4 comma_life          Java            P  Basic  Free
5  kokoatalk          Java            F  Basic  Free
6 hanguk_joa        Python            P Expert  2000
7  kuda_koma             R            F Expert  2000
8   ahn_0526        Python            P Medium  1000
9 wheresjohn          Java            F Medium  1000

새 데이터프레임에 할당하고 순서 바꿀 수 있다. 

 

> stories2 <- read.table(header=TRUE, text='
+    id       title
+     1       lions
+     2      tigers
+     3       bears
+ ')
  subject storyid rating
1       1       1    6.7
2       1       2    4.5
3       1       3    3.7
4       2       2    3.3
5       2       3    4.1
6       2       1    5.2

컬럼명이 다른데 되나요? 

> merge(x=stories2,y=data,by.x="id",by.y="storyid")
  id  title subject rating
1  1  lions       1    6.7
2  1  lions       2    5.2
3  2 tigers       1    4.5
4  2 tigers       2    3.3
5  3  bears       1    3.7
6  3  bears       2    4.1

네. 근데 내가 갖고 있는거에 만들어서 할랬더니 에러뜸... 

 

Error in fix.by(by.x, x) : 'by' must specify a uniquely valid column

혹시 이 에러 해결법 아시는 분 제보좀 부탁드립니다. (합치려는 데이터프레임 영역 팩터로 같은 거 확인함) 

 

> animals <- read.table(header=T, text='
+    size type         name
+   small  cat         lynx
+     big  cat        tiger
+   small  dog    chihuahua
+     big  dog "great dane"
+ ')
> observations <- read.table(header=T, text='
+    number  size type
+         1   big  cat
+         2 small  dog
+         3 small  dog
+         4   big  dog
+ ')

이걸 파이널퓨전하는 것도 된다. 

> merge(observations,animals,c("size","type"))
   size type number       name
1   big  cat      1      tiger
2   big  dog      4 great dane
3 small  dog      2  chihuahua
4 small  dog      3  chihuahua

어째서인지는 모르겠으나 됨. 

 

데이터프레임 비교하기

> dfA <- data.frame(Subject=c(1,1,2,2), Response=c("X","X","X","X"))
> dfB <- data.frame(Subject=c(1,2,3), Response=c("X","Y","X"))
> dfC <- data.frame(Subject=c(1,2,3), Response=c("Z","Y","Z"))
> dfA
  Subject Response
1       1        X
2       1        X
3       2        X
4       2        X
> dfB
  Subject Response
1       1        X
2       2        Y
3       3        X
> dfC
  Subject Response
1       1        Z
2       2        Y
3       3        Z

쿡북에 있는 시범조교를 모셔봤습니다. 

 

> dfA$Coder="A"
> dfB$Coder="B"
> dfC$Coder="C"

각 데이터프레임에 Coder라는 컬럼을 추가한다. 

> df7=rbind(dfA,dfB,dfC)
> df7
   Subject Response Coder
1        1        X     A
2        1        X     A
3        2        X     A
4        2        X     A
5        1        X     B
6        2        Y     B
7        3        X     B
8        1        Z     C
9        2        Y     C
10       3        Z     C

그리고 행단위로 파이널퓨전! 

> df7=df7[,c("Coder","Subject","Response")]
> df7
   Coder Subject Response
1      A       1        X
2      A       1        X
3      A       2        X
4      A       2        X
5      B       1        X
6      B       2        Y
7      B       3        X
8      C       1        Z
9      C       2        Y
10     C       3        Z

하고 정렬까지 해야 시범조교 끝... 

참고로 이걸 진행하려면 함수 하나를 정의하고 가야 하는데 

dupsBetweenGroups <- function (df, idcol) {
    # df: the data frame
    # idcol: the column which identifies the group each row belongs to

    # Get the data columns to use for finding matches
    datacols <- setdiff(names(df), idcol)

    # Sort by idcol, then datacols. Save order so we can undo the sorting later.
    sortorder <- do.call(order, df)
    df <- df[sortorder,]

    # Find duplicates within each id group (first copy not marked)
    dupWithin <- duplicated(df)

    # With duplicates within each group filtered out, find duplicates between groups. 
    # Need to scan up and down with duplicated() because first copy is not marked.
    dupBetween = rep(NA, nrow(df))
    dupBetween[!dupWithin] <- duplicated(df[!dupWithin,datacols])
    dupBetween[!dupWithin] <- duplicated(df[!dupWithin,datacols], fromLast=TRUE) | dupBetween[!dupWithin]

    # ============= Replace NA's with previous non-NA value ==============
    # This is why we sorted earlier - it was necessary to do this part efficiently

    # Get indexes of non-NA's
    goodIdx <- !is.na(dupBetween)

    # These are the non-NA values from x only
    # Add a leading NA for later use when we index into this vector
    goodVals <- c(NA, dupBetween[goodIdx])

    # Fill the indices of the output vector with the indices pulled from
    # these offsets of goodVals. Add 1 to avoid indexing to zero.
    fillIdx <- cumsum(goodIdx)+1

    # The original vector, now with gaps filled
    dupBetween <- goodVals[fillIdx]

    # Undo the original sort
    dupBetween[sortorder] <- dupBetween

    # Return the vector of which entries are duplicated across groups
    return(dupBetween)
}

이놈이다. 정의하고 가자. 

 

> dupRows=dupsBetweenGroups(df7,"Coder")
> dupRows
 [1]  TRUE  TRUE FALSE FALSE  TRUE  TRUE FALSE FALSE  TRUE FALSE

근데 이렇게만 해 두면 뭔지 모르것다... 

> cbind(df7,dup=dupRows)
   Coder Subject Response   dup
1      A       1        X  TRUE
2      A       1        X  TRUE
3      A       2        X FALSE
4      A       2        X FALSE
5      B       1        X  TRUE
6      B       2        Y  TRUE
7      B       3        X FALSE
8      C       1        Z FALSE
9      C       2        Y  TRUE
10     C       3        Z FALSE

열단위로 결합해도 뭔지 모르겠다... 

사실 저건 각 테이블에서 중복되는 값을 찾아주는 함수이다. 코드가 달라도 중복되는 값이 있으면 TRUE, 아예 없으면 FALSE. 

 

> cbind(df7,unique=!dupRows)
   Coder Subject Response unique
1      A       1        X  FALSE
2      A       1        X  FALSE
3      A       2        X   TRUE
4      A       2        X   TRUE
5      B       1        X  FALSE
6      B       2        Y  FALSE
7      B       3        X   TRUE
8      C       1        Z   TRUE
9      C       2        Y  FALSE
10     C       3        Z   TRUE

이건 반대로 중복이 없으면 TRUE, 중복값이 있으면 FALSE다. 

 

서브셋 나누기

> dfA=subset(dfDup,Coder=="A",select=-Coder)
> dfB=subset(dfDup,Coder=="B",select=-Coder)
> dfC=subset(dfDup,Coder=="C",select=-Coder)
> dfA
  Subject Response   dup
1       1        X  TRUE
2       1        X  TRUE
3       2        X FALSE
4       2        X FALSE
> dfB
  Subject Response   dup
5       1        X  TRUE
6       2        Y  TRUE
7       3        X FALSE
> dfC
   Subject Response   dup
8        1        Z FALSE
9        2        Y  TRUE
10       3        Z FALSE
# 아 저게 Coder 빼고 셀렉션해달라는 얘기였냐고

나누면 됩니다. 근데 저 셀렉트는 뭐냐... 

 

> df4
        category         compound_name chemical_formula Molecular_mass.g.mol.1.
1         Borane                Borane              BH3                  13.830
2         Borane        Ammonia_borane             BNH6                  30.865
3         Borane           Tetraborane            B4H10                  53.320
4         Borane        Pentaborane(9)             B5H9                  63.120
5         Borane        Octadecaborane           B18H22                 216.770
6          Oxide     Caesium_monooxide             Cs2O                 281.810
7          Oxide        Actinium_oxide            Ac2O3                 502.053
8          Oxide      Triuranium_oxide             U3O8                 842.100
9          Oxide Technetium(VII)_oxide            Tc2O7                 307.810
10         Oxide     Thorium_monooxide              ThO                 248.040
11        Alkane               Methane              CH4                  16.043
12        Alkane                Hexane            C6H14                  86.178
13        Alkane                Nonane            C9H20                 128.259
14        Alkane             Tridecane           C13H28                 184.367
15        Alkane          Hentricotane           C31H64                 436.853
16 Sugar_alcohol              Mannotol          C6H14O6                 182.172
17 Sugar_alcohol               Xylitol          C5H12O5                 152.146
18 Sugar_alcohol               Fucitol          C6H14O5                 166.170
19 Sugar_alcohol             Volemitol          C7H16O7                 212.198
20 Sugar_alcohol              Inositol          C6H12O6                 180.160
21  IARC_group_1          Aflatoxin_B1         C17H12O6                 312.277
22  IARC_group_1           Cicloaporin    C61H111N11O12                1202.635
23  IARC_group_1      Gallium_arsenide             GaAs                 144.615
24  IARC_group_1             Melphalan    C13H18Cl2N2O2                 305.200
25  IARC_group_1          Azothioprine        C9H7N7O2S                 277.260

시범조교 4번을 불러보자. 으아아 저게 뭐야 참고로 IARC group 1은 이놈은 Carcinogen(발암물질)이 확실하니까 먹지도 마시지도 말고 애비 지지해야되는 것들. 

> df4A=subset(df4,category=="Borane")
> df4A
  category  compound_name chemical_formula Molecular_mass.g.mol.1.
1   Borane         Borane              BH3                  13.830
2   Borane Ammonia_borane             BNH6                  30.865
3   Borane    Tetraborane            B4H10                  53.320
4   Borane Pentaborane(9)             B5H9                  63.120
5   Borane Octadecaborane           B18H22                 216.770

Borane(붕소 화합물임... 자세한건 모름)으로 서브셋을 만들어보면 이렇게 나온다. 근데 생각해보니 Borane으로 묶었는데 저기서 카테고리를 보여 줄 필요가 없거든. 

> df4B=subset(df4,category=="IARC_group_1",select=-category)
> df4B
      compound_name chemical_formula Molecular_mass.g.mol.1.
21     Aflatoxin_B1         C17H12O6                 312.277
22      Cicloaporin    C61H111N11O12                1202.635
23 Gallium_arsenide             GaAs                 144.615
24        Melphalan    C13H18Cl2N2O2                 305.200
25     Azothioprine        C9H7N7O2S                 277.260

그래서 select에 -를 줘서 뺀 것이다. (R에서 -붙으면 그거 빼고 달라는 얘기)

 

> df4C=subset(df4,Molecular_mass.g.mol.1.>=100)
> df4C
        category         compound_name chemical_formula Molecular_mass.g.mol.1.
5         Borane        Octadecaborane           B18H22                 216.770
6          Oxide     Caesium_monooxide             Cs2O                 281.810
7          Oxide        Actinium_oxide            Ac2O3                 502.053
8          Oxide      Triuranium_oxide             U3O8                 842.100
9          Oxide Technetium(VII)_oxide            Tc2O7                 307.810
10         Oxide     Thorium_monooxide              ThO                 248.040
13        Alkane                Nonane            C9H20                 128.259
14        Alkane             Tridecane           C13H28                 184.367
15        Alkane          Hentricotane           C31H64                 436.853
16 Sugar_alcohol              Mannotol          C6H14O6                 182.172
17 Sugar_alcohol               Xylitol          C5H12O5                 152.146
18 Sugar_alcohol               Fucitol          C6H14O5                 166.170
19 Sugar_alcohol             Volemitol          C7H16O7                 212.198
20 Sugar_alcohol              Inositol          C6H12O6                 180.160
21  IARC_group_1          Aflatoxin_B1         C17H12O6                 312.277
22  IARC_group_1           Cicloaporin    C61H111N11O12                1202.635
23  IARC_group_1      Gallium_arsenide             GaAs                 144.615
24  IARC_group_1             Melphalan    C13H18Cl2N2O2                 305.200
25  IARC_group_1          Azothioprine        C9H7N7O2S                 277.260

참고로 조건부로 서브셋 만드는 것도 된다. 뭐 여기서는 100으로 잡았지만 ChEMBL에서 불러온 다음 RO5 조건 만족하는 것들로 만들거나 BBB 통과 조건으로 만들거나 할 수도 있다. (아니면 SMILES에 @@ 붙은거?)

 

팩터 레벨 재조정하기

그 뮤츠씨가 좋아하는? 아니 그건 팩트라니까 얘는 팩터잖아 

 

> str(df3)
'data.frame':	13 obs. of  4 variables:
 $ name            : Factor w/ 13 levels "Acetic acid",..: 12 1 6 8 13 10 7 9 5 11 ...
 $ Chemical.formula: Factor w/ 13 levels "BBr3","C12H25NaSO4",..: 13 3 8 12 11 9 5 7 4 2 ...
 $ MW.g.mol.1.     : num  58.4 60.1 180.2 232.7 92.1 ...
 $ Density.g.cm.3. : num  2.17 1.05 1.54 8.1 0.87 ...

3번 시범조교에도 팩터가 두 개 있다. (이름, 분자식) ㅇㅋ? ㄱㄱ 

 

> df3_1=droplevels(df3)
> df3_1
                  name Chemical.formula MW.g.mol.1. Density.g.cm.3.
1      Sodium chloride             NaCl      58.443         2.17000
2          Acetic acid           C2H4O2      60.052         1.04900
3              Glucose          C6H12O6     180.156         1.54000
4  Mercury(II) sulfide              HgS     232.660         8.10000
5              Toluene             C7H8      92.141         0.87000
6               Phenol            C6H6O      94.113         1.07000
7             Glycerol           C3H8O3      92.094         1.26100
8                 PETN        C5H8N4O12     316.137         1.77000
9              Ethanol            C2H6O      46.069         0.78945
10                 SDS      C12H25NaSO4     288.372         1.01000
11       Chlorophyll a     C55H72MgN4O5     893.509         1.07900
13    Boron tribromide             BBr3     250.520         2.64300

12행을 날리고 droplevel()을 적용하면 

> str(df3_1)
'data.frame':	12 obs. of  4 variables:
 $ name            : Factor w/ 12 levels "Acetic acid",..: 11 1 5 7 12 9 6 8 4 10 ...
 $ Chemical.formula: Factor w/ 12 levels "BBr3","C12H25NaSO4",..: 12 3 8 11 10 9 5 7 4 2 ...
 $ MW.g.mol.1.     : num  58.4 60.1 180.2 232.7 92.1 ...
 $ Density.g.cm.3. : num  2.17 1.05 1.54 8.1 0.87 ...

팩터 레벨이 바뀌었다. (13->12)

이걸 vapply()와 lapply()를 적용해서 할 수도 있는데 

> factor_cols=vapply(df3,is.factor,logical(1))
> factor_cols
            name Chemical.formula      MW.g.mol.1.  Density.g.cm.3. 
            TRUE             TRUE            FALSE            FALSE

vapply()를 통해 이놈이 팩터인가를 볼 수 있고 

> df3[factor_cols]=lapply(df3[factor_cols],factor)
# Apply the factor() function to those columns, and assign then back into d

팩터 함수를 적용시키면

> str(df3)
'data.frame':	12 obs. of  4 variables:
 $ name            : Factor w/ 12 levels "Acetic acid",..: 11 1 5 7 12 9 6 8 4 10 ...
 $ Chemical.formula: Factor w/ 12 levels "BBr3","C12H25NaSO4",..: 12 3 8 11 10 9 5 7 4 2 ...
 $ MW.g.mol.1.     : num  58.4 60.1 180.2 232.7 92.1 ...
 $ Density.g.cm.3. : num  2.17 1.05 1.54 8.1 0.87 ...

(대충 droplevel()이랑 같은거라는 얘기)