2025-08-26

보이스피싱과 모텔

요즘에는 별 보이스피싱이 다 있군요. 전화 받는 사람이 범죄에 연루되었는데 자기들이 도와주는 것처럼 하면서 정신 쏙 빼 놓고, 모텔에 몇 주 칩거하게 하고 그동안 계좌를 조금씩 털어가는 방식이라는데...이거야말로 가스라이팅인듯. 작은 사소한 것부터 하라고 해서 그걸 하게 하고 조금씩 조금씩 강도를 높여가서 나중에는 무려 모텔에 스스로 걸어 들어가게 만드는 수법인 것 같아요.

그 수법이 널리 알려져서 피해자가 줄어들기를 바라네요.

보이스피싱 당해 8000만원 잃은 이야기: .

모르는 사람이 전화로 (다른 확인 없이) 빨리/당장 뭘 하라 마라 하면 (어디 링크를 가라, 뭘 확인해라, 대답해라 등등), 우선 하지말고, 잘 모르겠다 싶으면 전화를 한번 확 끊어보는 것도 좋을 듯.



2025-08-24

"set on something" 뜻: 목표를 가지고 그것을 하다

= to be determined to do something

뭔가를 하기로 목표를 세우고 그것을 굳은 마음으로 확고하게 해나가고 밀어붙이는 상태를 의미하네요.

예제로,

"Although we didn't have much money, my dad and mon were set on giving me the kind of opportunities my brother and siter never got."
많은 돈은 없었지만, 어머니 아버지는 나의 형제 자매에게는 절대 주어지지 않았던 그런 종류의 기회를 나에게 주기 위해서 매우 노력하셨다.

She had her mind pretty well set on working for a small company.
그녀는 작은 회사를 목표로 일할 것을 굳게 결심했다.

She seems set on marrying him.
그녀는 그와 결혼하려고 밀어붙이기로 한 것 같다.

2025-08-18

"bring about" 뜻: 초래하다, 결과로 만들어내다

"result in"과 같은 뜻으로, 기본적으로 인과 관계를 얘기할 때 사용합니다.

예제로,

[원인] brings about [결과]
He brought about his company's collapse by his reckless spending.
분별없는 지출로 그 남자는 자신의 회사를 결과적으로 무너지게 했다. 

It took hours of negotiations to bring about a reconciliation between the two sides.
양 편의 화해를 결과로 얻어내기 위해 협상하는 데에 여러 시간이 걸렸다.

[결과] is brought about by [원인]
"The failure was brought about by a combination of controllable and uncontrollable factors."
그 실패는 조절 가능한 요인과 가능하지 않은 요인의 결합에 의한 결과물이다.

2025-05-11

책리뷰 - 기쁨의 집 (이디스 워튼)

릴리라는 인물이 속물에 황새 쫓아가는 뱁새였던 것은 맞고. 그래서 멍청한 행동만 계속하는 릴리에게 짜증이 났는데, 다 읽고 나니 셀던이 제일 싫다. 아주 그냥 의심의 캐릭터다. 

셀던의 '실험적' 방해만 없었더라면, 릴리는 진작에 결혼해서 잘먹고 잘살았을텐데. 꼬시는건지 아닌지 계속 헷갈리게 하면서, 우리가 결혼하려면 릴리에게 네가 뭔가를 포기해야한다고 끊임없이 현학적으로 빈정대고. 자신은 도대체 뭘 포기했지?

욕심 많은 로스데일에 비해 셀던이 뭐가 나은지...... 최소한 로스데일은 릴리의 허영을 뒷받침해줄 "능력"있고, 릴리의 진심을 알긴 알고, 돌아가는 상황은 정확히 파악하고 있었고, 그리고 도움은 안되었을 망정, 자신이 도울 수 있는 한에서는 릴리를 안타까워하고 도우려고 노력이라도 했다고. 문제는 릴리가 좋아하는건 어떤 이유에서인지 셀던이었다는게 문제였지.

그에 비해 셀던은 상황파악 안되고, 귀얇고, 부자도 아니고, 사치스러운 여자가 무서웠으면서도 또 눈은 높고, 자기 자신을 의심하면서도, 릴리보다 어쨋거나 자신이 도덕적으로 우위에 있다고 생각하고.

릴리는 쓸모없는(?) 동정심/명예/허영 때문에, 자신이 그렇게 나쁘지는 않다는 것을 셀던에게 "증명" 했고, 결국은 자신의 모든 것을 버린거나 다름이 없다. 하지만, 셀던이 릴리때문에 포기한건 끝까지 지켜봐도 하나도 없다. 

릴리가 화해를 청하자 셀던이 또 쌩뚱맞게 너 결혼하냐고 묻는 장면은, 릴리라는 인간에 대한 무관심, 그리고 릴리가 자신의 결혼상대인가 아닌가에 대한 관심 밖에 없음을 보여주는 것 같다. 

그 순간은 릴리가 과거의 자신과 화해하는 순간인 것을. 그걸 무슨 자기한테 사랑고백한거라고 생각한건지. 그것도 그 당장도 아니고 그 다음날 청혼을 하러 가는 것도 어이 없고. 또 마지막 순간까지 릴리가 쓴 편지를 보고 의심..야 됐다!! 소리가 절로 나옴.

사실 멍청하나 나름 행복하게 살 수 있었던 릴리에게 자기 의심의 씨앗을 뿌린 것은 셀든인듯.

2025-05-08

뭐먹지 - 감자채 볶음

  1. 감자를 껍질 깍고, 길게 채썹니다. 약 5에서 7mm 두께로.
  2. 양파를 길게 채썹니다. 결방향으로.
  3. 기름 두른 팬에 같이 볶아요. (아, 햄도 길게 채썰어서 넣어주면 맛있어요)
  4. 감자가 살짝 투명해지면서 익었다 싶으면, 소금+후추 뿌려서 섞어주고,
  5. 먹습니다.


2025-02-14

Learn R - Dedup!

Dedup (deduplication) is the first step to analyze any data. 

There is almost always some redundancy in the table of any raw data if you're dealing with the type of "real-world" data sets. It could be the consequence of many complex joins or the data is copied twice by mistakes. Whatever the reason is, a perfectly cleaned data is rare. Any further analyses on it without checking it deliberately could just create lots of complex troubles later! 

Let's explore the ways to dedup in R.

This is one simple data frame.

> df <- data.frame(name=c('Alice', 'Brian', 'Chris', 'Brian'), age=c(10, 20, 30, 20), height=c(5.2, 5.7, 6, 5.7))
> df
   name age height
1 Alice  10    5.2
2 Brian  20    5.7
3 Chris  30    6.0
4 Brian  20    5.7

Rows 2 and 4 are duplicated. To remove one of them, we can use three methods.

(1) duplicated()

The function duplicate() indicates which rows are duplicated. It is R's base function, so it doesn't need the installation.

> duplicated(df)
[1] FALSE FALSE FALSE  TRUE

The 4th row is duplicated (as the True indicates). The rows not duplicated are found using the "not" operator (!) as follows.

> !duplicated(df)
[1]  TRUE  TRUE  TRUE FALSE

Slicing with the index selects the rows not duplicated.

> df[!duplicated(df),]
   name age height
1 Alice  10    5.2
2 Brian  20    5.7
3 Chris  30    6.0


(2) unique()

The function unique() returns the dataframe after removing the redundancy. It's also the base function of R so ready to be used without installation.

> unique(df)
   name age height
1 Alice  10    5.2
2 Brian  20    5.7
3 Chris  30    6.0


(3) distinct() in dplyr

Install dplyr package first, then use distinct() in the package. It returns the same distinct rows only.

> dplyr::distinct(df)
   name age height
1 Alice  10    5.2
2 Brian  20    5.7
3 Chris  30    6.0

The same could be done using piping in a tidyverse style.

> df %>% distinct()
   name age height
1 Alice  10    5.2
2 Brian  20    5.7
3 Chris  30    6.0

It's that easy. Just remember to dedup!


"if any" 뜻: 거의 없을 것이지만 만약 있다고 한다면

말하는 것에 혹시나 모를 가능성을 덧붙이지만, 사실 그럴 일이 거의 없다거나 매우 적다는 것을 강조하고 싶을 때 사용합니다.


  • 몇 가지 예를 든 다음에 ", if any"라고 문장의 끝에 붙이는 경우가 많음. 
      ex. "Are there any benefits, if any?" 아마 있다고 해도, 장점이 있나?


  • 아니면, 명사 바로 뒤에 붙인다. 

      ex. "What benefits, if any, are there?" 만약 있다고 한다면, 어떤 장점이 있나?


  • 양을 나타내는 표현 (several/few/many) 뒤에 쓰이면 그 수가 아주 적을 것이라는 것을 표시함.

       ex. "There are few errors, if any." (아마도) 있다고 해도, 거의 오류는 없을것이다.




2025-02-08

어장관리남(또는 어장관리녀)이 만들어지는 과정

"크랜포드"라는 2007년 BBC드라마를 보기 시작했다. 1842년 영국의 보수적인 시골 동네 크랜포드가 배경이고. 이 동네의 저택에 사는 지주 마님으로부터 찢어지게 가난한 오두막집 사람들까지, 다양한 계급의 동네 사람들(주로 여자들)의 삶이 나오는데 꽤 재미있다. 

한 에피소드로 해리슨이라는 훈훈한 젊은 의사가 한순간에 어장관리남으로 전락하는 과정이 나오는데, 이게 친절하고 예쁜 여자가 어장관리녀로 낙인찍히는 과정이랑 매우 똑같다. 

가난하지만 나름 능력 있는 의사 해리슨이 보수적이고 말많은 마을 크랜포드에 의사 조수로 오게 되고, 젊은 미혼남이라는 이유로 그는 동네 여자들의 과도한 관심을 받게 된다. 사실 해리슨은 크랜포드에 오자마자 이미 목사의 딸 소피에게 한눈에 반해서 청혼을 해도 된다는 허락도 거의 받은 상태였다. 다른 여자분들에게는 그냥 환자니까, 또는 자기 하숙집 주인이니까, 그냥 예의상 친절하게 응대를 했을 뿐인데, 다들 해리슨이 자기를 좋아해서 곧 자기에게 청혼을 할거라고 오해하고 난리쳐서, 어느 순간 해리슨은 자기도 모르는 사이에 동네의 "어장관리남"이 되어버린다. 그리하여 목사는 대노하고, 소피에게도 차이고, 사람들에게 냉대를 받아서 마을에서 쫒겨날 지경이 된다..

1842년 얘기인데, 왜 이렇게 현대적인건지 ㅎㅎ 

친절하고 예쁜 여자가 (예를 들어, 대학교 새내기 여학생 또는 갓 입사한 여자 신입) 걍 원래 친절한 사람이라서 주위 사람들에게 친절하게 대하니까, 주위의 모든 남자들이 그녀가 자기를 좋아한다고 착각하다가, 다들 모여서 자기들이 제각각 착각한걸 깨닫는게 아니라, 그 여자가 어장관리녀라고 낙인찍고 욕하는 그런 상황.

크랜포드에서는 해리슨은 결국 누명을 벗고 소피와 다시 잘 되지만, 현실에서는 그 친절하고 잘 웃던 여자분은 없어지고 이제는 안친절한 "어장관리녀"가 남을 뿐...  

2024-12-18

책리뷰 - 행운에 속지 마라 (나심 탈렙)

2011년에 "블랙스완"을 써서 유명해진 나심 탈렙이 2001년에 낸 책. 원제 Fooled by Randomness로 번역하면  '(우리는) 무작위성에 속고있는 중이다' 정도가 될 듯.

블랙스완의 내용과 겹치는 점이 많고, 좀 비슷한 스타일로 쓰여는데 블랙스완이 좀 더 재밌게 쓰여지긴 했다. 다방면으로 철학적 discussion을 하는 것은 블랙스완이 더 재미있고. 이 책은 살짝 약한 연습 version같은 느낌이 있다.

주 내용은, 성공이 행운에 의한 것인지 아닌지 잘 모르니까 한번 성공했다고 그 방법이 통할 것이라고 생각하지말라는 것이고. 무작위성(randomness)에 대한 연구자라고 본인은 주장하는 만큼, 무작위성에 대한 내용을 일반인도 좀 쉽게 이해하도록 좀 친절하게 설명해준 것 같다 (블랙스완에서는 어쩐지 덜 친절함). 

블랙스완에서는 똑같은 randomness에 대한 얘기를 하고 똑같은 principle이지만, 대신 한번도 실패하지 않았다고 안실패한다고 생각하지말라, 큰 불행이 올 수도 있다는 식으로 얘기를 전개하였는데, 블랙스완의 방식이 사람들의 관심을 더 끌었다고 생각한다. 사람들은 부정적인 일이 더 관심이 많아서일까? 큰 행운이 생긴다는 얘기보다 큰 불행이 생긴다는 얘기에 더 많은 관심을 보이니까. 

(블랙스완에서는 '블랙스완'이나 터키라는 눈에 보이는 것 같은 example과 Gaussian에 대한 좀 더 체계적인 비판, 그리고 다양한 철학적 stance를 보여주기위한 각종 캐릭터들, 그리고 자신의 memoir를 철학적 주장과 매우 교묘하고 신기하게 섞어놓은 뭐라 categorize하기 힘든, 이렇게 글을 풀어놓는 방식이 새롭다. 그리고 더 제멋대로라고 할까. Fooled By Randomness는 좀 더 대중적으로 읽히고 싶어서 쓴 책이고 블랙스완은 정말 더더 독자 눈치 안보고 쓰고 싶은데로 멋대로 자기 성향대로 최고로 잘난 척하면서 쓴 것 같은데도 더 재밌다)

블랙스완에서는 인간이 randomness를 인식하지 못하는 이유, 어떤 상황에서건 설명을 만들어내려고 하는 biological한 약점, 역사라는 것은 그때 그 순간에 일어난 일들을 순차적으로 기입하는 것이 아니라 그 한참 후의 '결과물'을 본 다음에만 이해할 수 있다는 새로운 관점, Gaussian을 좋아하는 또는 normal model을 좋아하는 사람들에 대한 끝없는 공격이 더 늘어났다. (그동안 behavioral economics가 발달하여 더 많은 사람들이 Taleb의 이야기를 들어주기 시작했는지도.. 아니면 그동안 더 명성을 쌓아서 하고 싶은 말을 할 수 있게 된 것인가.)



2024-11-18

Learn R - Compute group means

Here are six boxes filled with either potatos or apples. 

Dataframe df has a group column that indicates whether it's a potato or apple box and a weight colmn that contains the weight of the box.

> df <- data.frame(
+   group=c('potato', 'potato', 'apple', 'apple', 'potato', 'apple'),
+   weight=c(10, 2, 5, 26, 3, 6))

It looks like this.

> df
   group weight
1 potato     10
2 potato      2
3  apple      5
4  apple     26
5 potato      3
6  apple      6

What can we do to get the average weights for the potato and apple boxes, respectively?

First, let's load dplyr.

> library(dplyr)

Then, with df,

  1. group by them with apple/potato group column
  2. send the output via piping (%>%)
  3. summarize the mean of weight and save them with a new column mean.weight.

 df %>% group_by(group) %>% summarize(mean.weight = mean(weight))

# A tibble: 2 × 2
  group  mean.weight
  <chr>        <dbl>
1 apple         12.3
2 potato         5  

The avarage weight for apple boxes is 12.3, and the average weight for potato boxes is 5.

It's that simple! Enjoy coding in R!


R에서 그룹 별로 평균 구하기

여섯 개의 상자 안에 감자 또는 사과가 들어 있다고 합니다. 

데이타프레임 df에는 group에는 감자인지 사과인지가, weight에는 각 상자의 무게가 들어갑니다.

> df <- data.frame(
+   group=c('potato', 'potato', 'apple', 'apple', 'potato', 'apple'),
+   weight=c(10, 2, 5, 26, 3, 6))

이 데이타프레임은 다음과 같습니다.

> df
   group weight
1 potato     10
2 potato      2
3  apple      5
4  apple     26
5 potato      3
6  apple      6

감자 상자, 사과 상자 그룹의 각각의 평균 무게를 구하고 싶다면?

우선 dplyr를 로딩합니다.

> library(dplyr)

df를 가지고

  1. 사과/감자 group 별로 grouping을 해주고 (group_by)
  2. 그 결과를 파이프로 받아서 (%>%)
  3. weight의 평균을 낸 다음에 이를 새로운 컬럼 mean.weight에 넣어줍니다 (summarize).

 > df %>% group_by(group) %>% summarize(mean.weight = mean(weight))

# A tibble: 2 × 2
  group  mean.weight
  <chr>        <dbl>
1 apple         12.3
2 potato         5  

사과상자의 평균 무게는 12.3, 감자상자의 평균은 5임을 알 수 있습니다.

참 쉽죠?


2024-10-06

간단 요리 - 달걀 껍질 잘 까지게 삶는 방법, 완전 정복!

삶은 달걀 껍질이 잘 안까질 때! 😡

검색을 해보면 여러 방법들이 나옵니다만...삶아서 바로 찬물에 넣는거, 달걀을 실온에 놔뒀다가 삶는거, 소금물로 삶는 것 다 안되더라구요. 제일 효과본건 이 방법이예요. 

팔팔 끓는 물에 달걀을 넣는다

대신 넣다가 깨질 수 있으니 숫가락 같은걸루 조심해서 넣으셔야 해요. 달걀이 익으면 불을 끄고 놔뒀다가 물이 미적지근하게 식으면 껍질을 깝니다. 잘 까지죠?

2024-09-23

간단 요리 - 스테이크 만들기

1. 고기 겉면에 소금(+후추)를 잔뜩 바르고 기름으로 문질러서(생략가능) 상온에 놔둔 상태에서,

2. 스뎅 후라이팬을 3분 이상 센불로 충분히 (고기가 닿았을 때 "치지지직" 소리나도록) 달굽니다. (손에 물을 묻혀서 팬에 살짝 뿌렸을 때 물이 작은 물방울이 되어서 또르르 굴러다니면 딱 좋은 온도로 달궈진 거예요.)

4. 고기의 옆면이 반 높이까지 익었을 때 (불 세기에 따라 다르지만 약 4-5분), 뒤집어서 다른 면도 익힙니다. 불은 계속 쎈불.

5. 나머지 옆면이 다 익은게 보이면 팬에서 꺼내서, 접시에 놓고 호일로 완전히 덮어서 상온에서 10분 놔둡니다 (중요함!).

먹습니다.

2024-09-21

책리뷰 - 월급쟁이 부자로 은퇴하기 (강우신)

월급쟁이가 떼부자로 은퇴할 수는 없겠지만, 은퇴 후에 따박따박 월급 나오는 직장이 없을 때에도 안정적이고 원활한 현금 흐름을 유지하기 위해서, 미리미리 돈/인맥/건강 관리를 하라는 얘기. 

돈을 만들기 위해서 투자도 해서 재산을 불리고. 은퇴 후 제2의 직업도 미리 계획하고. 은퇴 후에는 아무래도 아프기도 쉬우니까 건강 관리도 미리 열심히 하고. 인맥도 다 재산이니까 열심히 관리하고. 이렇게 준비해서 나중에 필요한 돈이 나올 수 있게 해놓으라는 조언들...어떻게 보면 지루하고 평범한 조언들이지만, 결국 이런 기본적인 것들이 중요한 거 아닐까. 

사람들이 흔히들 듣기 좋아하는 것 같은, "누가 얼마를 어떻게 벌었대드라"하는 그런 자극적인 얘기는 안나온다. 하지만, 자산관리가 직업인 저자가 업무를 통해서 수없이 보고 들은 '성공적'으로 은퇴한 케이스들이 있고, 여기서 나오는 공통적 특징을 배우는게, 한 두 가지 특이하고 재밌는 '대성공' 케이스를 듣는 것보다는, 평범한 월급쟁이들에게 도움이 될 것 같다.

2006년 책이라서, 투자에 관한 내용이 조금 옛날 트렌드이지 않을까 예상했는데, 그렇진 않다. 그리고 돈에 관한 얘기 이긴 하지만, 또 어떻게 보면 돈에 관한 얘기 만은 아니라서 읽어 볼만한 책이라고 생각한다.  

2024-09-16

Visual Illusion - Size Constancy

 

It's a visual illusion that is cuased by perceiving the size of objects samely without considering the distance from the viewer. 

In the picture, the fishing people sitting/standing on the rim were, in fact, very close to the camera that took the picture, while the very small fishing man left was sitting far away from the camera. This picture does not provide enough distance cues, so our brain interprets the scene as ordinary size people fishing with a very small, tiny person.

2024-09-15

Learn R - How to clean the "working memory" in R

When you want to delete all the variables and objects in the current workingspace in R for whatever reason, you can use rm().

For me, it happens when I am running lines of code in command lines to do quick, exploratory, pilot types of analyses. Some variables (or objects) defined earlier could create a mess if the existing variables have the same name. The old value previously set could introduce a wrong initial value. Then, the code returns some value without any errors, but it could be just wrong! The worse is that I don't even know what just happened...

How can we fix it quickly? By cleaning the current workspace (which is generally the global environment. If you don't know about "environments" in R, don't worry about them for now).

This is what I usually do:

> rm(list=ls())

It cleans all the objects in the workingspace.

Let's see if there is any previous objects:

> ls()
character(0)

Now it's a clean slate! So no worries about using wrong inital values for variables. It must return errors if the value is not correctly set before using it.

Enjoy coding in R!


2024-09-13

책리뷰 - 오늘의 화학 (조지 자이던)

많이 가공된 음식이 정말 몸에 좋은지 나쁜지, 어떻게 나쁜지에 대한 이야기, 그리고 그와 관련된 과학에 대한 책이다. 

저자의 결론은 신문에서 떠드는 각종 "과학"(이라고 부르는) 기사(사실은 거의 광고)들을 너무 믿지 말라는 것. 대신 FDA나 CDC에서 나쁘다 또는 위험하다고 하면 그건 확실히 알려야할 만큼이나 과학적으로 나쁘다는게 거의 증명된 것이므로 주의해서 들어야한다! 말로만 과학적인 척 하는 수많은 연구 결과(실과제로는, 광고/그냥 흥밋거리 기사)에 흔들리지 말라는 것.  

건강 관련 뉴스는 항상 돈이 되어왔던 것 같다. 예를 들어, 1876년 책인 "톰 소여의 모험"에도 건강 뉴스에 대한 에피소드가 나온다. 작가인 마크 트웨인이 어렸을 적의 이야기라고 하니까, 1800년대 초반의 얘기임에도, 주인공 톰을 길러주는 폴리 이모님이 그 시절 신제품이었던 "진통제"니 "목욕 요법"이니 하는 유행을 열심히 따라가고 이런 것을 알려주는 건강 관련 잡지까지 구독했다는 내용이 나온다. 물론 허구의 소설이긴 하지만, 이렇게 건강 관련 뉴스에 열광하는 독자들은 예나 지금이나 존재했고 그래서 그런 기사도 계속 나오는 듯. 이렇게 유구한 역사의 가짜 과학(적인듯이 보이는) 광고들 때문에 정말 진지하게 과학하는 사람들만 오명을 얻게 되는 것 같다. 

물론, "과학한다"는 사람들이 다 옳은 것도 아니긴 하지만... 과학적 방법을 적용할 때에 현실적인 여러 문제점들이 있다고 해도, 최소한 "틀림을 증명할 수 있는 것"에 대해서만 얘기한다는 점에서, 현 시점에는 그나마 가장 사실에 가까운 정보를 얻기 위한 가장 유용한 방법이 과학이긴 하다. 

이 "오늘의 화학" 책에서는, 여러 과학적 방법을 해석할 때의 문제점이나 일반적인 과학자들이 publish하려고 할 때 쓰는 "속임수"들 (예를 들어 p-hacking)에 대해서 비교적 쉽게 설명하려고 노력했다. 

책의 결론은, 그렇다고 건강한 생활 습관(예를 들어, 너무 많은 붉은 고기, 당, 포화지방을 적게 먹는 것)이 중요하다는 것을 안 받아들일 필요는 없다는 얘기. 좀 복잡하게 중립적 입장을 취하는게, 작가가 정말 "과학하는" (결론 내기 어려운 증거에 대해서는 왠만하면 결론 내려고 안하는) 사람이라서 그런듯 :) 

이러니까 과학이 어려운 거 아닐까. 증거가 엄청 쌓이기 전에는 과학자들은 쉽게 결론을 내주지 않으니까. 과학 교과서에 나오는 내용들이야 정말 증거가 너무 너무 많아서 이건 거의 참이다 이런 내용들만 나오는 거지만 (교과서에 나오는 실험들은 정말 아무나 붙잡아서 대충 실험하라고 해도 진짜 신기하게도 찰떡같이 p-value가 낮게 나오긴한다) 간단히 말하면, 교과서에 안 실린 내용들은 아직 현재 연구 중인 주제들이고 아직 모르니까 계속 하는 것이기 때문에 알아서 걸러 들어야한다. 

가공 음식이라던가, 자외선 차단제 등의 '화학 제품'이 건강에 미치는 영향에 대해서 여기저기 언론에서 떠드는 내용에 대해서, 그런 기사의 근거가 되는 과학적 방법을 이해하면서 정보를 더욱 정확하게 이해하고 싶은 사람들이 읽어보면 많은 도움이 되는 책인 것 같다.

2024-09-01

R 배우기 - Dedup! 데이터프레임 중복제거

어떤 테이블이건 분석을 할 때 가장 처음 시작은 dedup부터라고 생각합니다. 테이블들을 join하다 보면 어떤 이유로건 중복된 행이 생길 수가 있는데, 중복을 확인하는 과정을 거치지 않고 분석을 해봤자 틀린 분석이 나올 수 밖에 없어요.

R 데이터프레임에서 중복된 행을 제거하는 방법을 알아보겠습니다.

우선 중복이 있는 간단한 데이터프레임을 만들어봅니다.

> df <- data.frame(name=c('Alice', 'Brian', 'Chris', 'Brian'), age=c(10, 20, 30, 20), height=c(5.2, 5.7, 6, 5.7))
> df
   name age height
1 Alice  10    5.2
2 Brian  20    5.7
3 Chris  30    6.0
4 Brian  20    5.7

2번과 4번 행(row)이 중복되어있죠. 이를 제거하기 위해서, 다음의 세 가지 방법을 사용할 수 있습니다.

(1) duplicated 이용 

어떤 열이 중복된 row 인지는 duplicate() 함수를 써서 알 수 있습니다. R의 base함수이기 때문에 별도의 package설치할 필요 없이 바로 사용할 수 있습니다.

> duplicated(df)
[1] FALSE FALSE FALSE  TRUE

4번째 row가 중복되었음(TRUE)을 보여줍니다. 따라서, 중복되지 않은 row는 !(not)을 이용해서 아래와 같이 찾아낼 수 있습니다.

> !duplicated(df)
[1]  TRUE  TRUE  TRUE FALSE

이 결과를 index로 해서 slicing하면 중복되지 않은 행만 선택이 됩니다.

> df[!duplicated(df),]
   name age height
1 Alice  10    5.2
2 Brian  20    5.7
3 Chris  30    6.0


(2) unique 이용

unique()함수는 중복을 없엔 결과를 리턴합니다. unique()역시 R의 base함수이므로, 별도의 설치 없이 바로 사용할 수 있습니다.

> unique(df)
   name age height
1 Alice  10    5.2
2 Brian  20    5.7
3 Chris  30    6.0

이와 같이 중복된 행을 제거하고 unique한 행만 보여줍니다.


(3) dplyr의 distinct()이용

dplyr 팩키지를 설치하고 distinct()함수를 사용하여도 unique()와 같은 결과를 얻을 수 있습니다.

> dplyr::distinct(df)
   name age height
1 Alice  10    5.2
2 Brian  20    5.7
3 Chris  30    6.0

참고로, tidyverse스타일의 파이프를 사용하면 이렇게도 쓸 수 있습니다.

> df %>% distinct()
   name age height
1 Alice  10    5.2
2 Brian  20    5.7
3 Chris  30    6.0

쉽죠? 중요한 점은 잊지말고 dedup!


2024-08-25

책리뷰 - 몸은 기억한다 by 베셀 반 데어 콜크

저자는 트라우마(전쟁/아동학대/대형사고 등)로 인한 개개인의 문제 행동들을 제각각의 성격 장애로 보지 않고, 정신적 외상으로 인한 생물학적 결과로 본다. 즉 트라우마의 결과로 뇌가 타격을 받은 이후 적절히 치료되지 못한 상태에서, 이성적인 뇌와 정서적 뇌의 역할이 균형을 이루지 못하여 여러가지 정신적 또는 육체적 문제로 이어진다고 설명한다. 

트라우마에 관한 괴로운 경험, 그리고 그 이후에 나타나는 안타까운 반응에 대한 내용을 읽기가 좀 힘이 들었다. 트라우마로 인한 생물학적 결과와 그에 따른 행동변화라는 연결 고리를 다양한 케이스를 통해서 이해하고 확인하기 위해서는 피해갈 수는 없는 과정이지만, 쉽진 않았다. 단순한 독자 입장에서도 이러한 고통스러운 얘기들을 보고 듣는 데에 처리하는 시간이 필요한데...그래서 다른 책들보다 매우 더디게 읽을 수 밖에 없었다. 

이 책에서 제시하는 치료의 접근법은 좀 동양적이라고 할 수 있다. 하나하나의 개별적 증상과 그 증상 완화를 회복의 목표로 두지 않고, 다양한 증상을 아우르는 기저의 원인을 처리하는 접근법이다. 어떤 모델로 트라우마 회복이라는 주제에 접근할 것 인가 그 자체는 그닥 중요하진 않다고 생각한다. 어떤 모델을 사용하건 효과 있는 방법은 효과가 있는 것이니까. 

약물로 증상을 완화 시키려는 화학적 치료법이 대세인 상황에서, 저자는 이성적/정서적 뇌의 통합을 추구하고 치유하는 좀 더 다양한 방법을 제시한다. 안전한 환경 하에서 아직 처리되지 못한 트라우마 관련 정보를 재처리 한다던가, 몸과 뇌에 좋은 경험을 추가하는 트레이닝 등의 방법인데, 물론 노력과 시간이 필요한 방법들이긴 하다. 기록 차원에서, 주요한 치료 방법 들을 정리해 보았다.

 (1) 트라우마를 다시 처리하는 기회를 주는 방법: 언어의 힘을 이용한 진정 (자기자신에 대한 자유로운 글쓰기), 언어 외적인 힘을 이용하여 표현하는 방법 (그림/음악/춤),  안구 운동 민감소실 및 재처리 요법을 통한 트라우마 재처리 (Eye Movement Desensitization and Reprocessing, EMDR, 아마도 REM 수면과 비슷한 몸의 상태를 유도해서 재처리 시간을 가지는 것 같아보인다)

(2) 자기 자신을 들여다보고 여러 개의 내적 자아에 대한 리더쉽을 찾는 법 (흩어진 마음을 찾고, 잃어버린 마음을 찾아가는 동양철학 적이기도 하다)

(3) 마비된 감각/느낌/생각/좋은 피드백을 다시 결합하는 트레이닝: 마사지, 요가,  과거와 재접촉하여 트라우마로 인해 텅빈 내면을 스스로 채우기, 뉴로피드백 (명상과 비슷한 것 같다)

(4) 공동체가 함께하는 의식: 연극에 참여하여 표현하고 공감하기

이 책에 나온 각종 치유법은, 누구나 살아가면서 겪는 크고 작은 트라우마 해소에 도움이 될 것이라고 생각한다. 이 중 자신에게 맞는 방법을 찾아 시도해보는 것 만으로도 가치가 있을 것 같다.

2024-07-22

R 배우기 - dplyr사용하기

R로 데이터 분석할 때 dplyr가 정말 유용합니다. 예를 들어, dplyr를 쓰면 for loop를 쓸 일이 거의 없어요.

그럼 기본적인 사용법을 볼까요. 

dplyr 패키지를 인스톨하고 (install.packages("dplyr")), 라이브러리를 불러줍니다.

> library(dplyr)

data frame을 하나 만들어봅시다.

> df <- data.frame(name=c('Alice', 'Brian', 'Chris'), age=c(10, 20, 30), height=c(5.2, 5.7, 6))
> df
   name age height
1 Alice  10    5.2
2 Brian  20    5.7
3 Chris  30    6.0

dplyr에서는 %>% 라는 "파이프"를 사용하는데요, 파이프를 사용하면 왼쪽의 결과물이 자동으로 오른쪽 함수의 input이 됩니다.

예를 들어, dplyr의 filter()라는 함수는 row를 선택할 때 사용합니다. Alice의 데이타를 보려면,

> filter(df, name == 'Alice')
   name age height
1 Alice  10    5.2

파이프로도 똑같은 일을 할 수 있습니다.

> df %>% filter(name == 'Alice')
   name age height
1 Alice  10    5.2

파이프 %>% 왼쪽에 있는 df가 오른쪽에 있는 filter()함수의 input이 되는 것입니다.

dplyr에서 많이 쓰이는 select()라는 함수는 column선택할 때 사용됩니다. name, age, height의 세 개의 컬럼 중에서, name과 age만 보고 싶다면,

> select(df, name, age)
   name age
1 Alice  10
2 Brian  20
3 Chris  30

파이프로는 

> df %>% select(name, age)
   name age
1 Alice  10
2 Brian  20
3 Chris  30

여기서도 df가 select()함수의 input으로 들어간 것입니다.

만약 이름이 Alice가 몇 살인지 알고 싶다면, 위의 두 함수를 한 번 씩 적용하면 되겠죠.

> df1 <- filter(df, name == 'Alice')
> select(df1, name, age)
   name age
1 Alice  10

먼저 filter한 다음에 그 결과물을 df1에 잠시 저장한 다음 select했는데요. 이렇게 함수를 순차적으로 사용할 때, 파이프의 장점이 드러납니다. 

왜냐하면 파이프의 왼쪽의 결과물이 오른쪽 함수의 input이 되니까요.

> df %>% filter(name == 'Alice') %>% select(name, age)

   name age
1 Alice  10

이렇게 파이프를 사용하면, 중간에 df1을 따로 만들 필요가 없어요. 처음 filter()함수의 결과물이 select()함수의 input으로 들어간 것입니다.

그리고 위의 예제에서 보이는 것처럼, 어떤 순서대로 뭘 했는지 그 흐름대로 읽을 수 있으니 나중에 봤을 때에도 이해하기 편하죠. 

여기까지가, dplyr의 기본적인 사용 방법 입니다. 

(dplyr의 다양한 함수들은 https://dplyr.tidyverse.org 에서 찾아볼 수 있습니다.)