Julia Language 프로그래밍 언어 기본 문법 정리
in Development on Julia
- 프로그래밍 언어인 Julia Language 기본 문법에 대한 글입니다
Julia
- Julia는 MIT에서 개발한 언어로 2012년에 처음 개발함
- Two langauge problem
- Performance(fortan, c, asm) vs Productivity(python, ruby, matlab) vs Generality
- 이런 문제를 해결하고자 Julia를 만듬
- looks like python, feels like lisp, runs like C
- Julia는 C만큼 빠름
- Julia는 R, Matlab, Python 같이 high level로 수치 계산하기 좋고, 일반 범용 목적의 프로그래밍도 지원함
- 메타프로그래밍을 할 수 있음(macros, multiple dispatch)
- Julia는 C만큼 빠름
- 수치 해석(Numerical Analysis), 최적화(Optimization) 문제 등 고성능이 필요한 수학적 계산 처리를 주로 품
- index 숫자가 1부터 시작함
- Python에서 Julia 실행 가능 : pyjulia 사용
- Julia에서 Python 실행 가능 : PyCall 사용
Julia 사용 사례
- Celeste
- Sloan Digital Sky Survey Data로 178 terabytes
- 천문학 이미지 분석하기 위해 Julia를 활용함
- Parallel Supercomputing for Astronomy에 자세한 내용이 나옴
- 사용하는 회사
- 2018년 기준이고 지금은 더 많을듯
Julia 설치하기
Mac OS 기준
brew cask install julia
터미널에서 Julia를 입력한 후 아래와 같은 내용이 뜨면 성공
Jupyter Notebook에서 Julia 사용하기
- IJulia 사용
터미널에서 Julia를 입력해서 Julia prompt로 이동 후 아래 명령어 입력
ENV["PYTHON"] = "" ENV["JUPYTER"] = ""
IJulia 설치(Julia Prompt에서 실행)
using Pkg Pkg.add("IJulia")
IJulia 실행(Julia Prompt에서 실행)
using IJulia notebook()
- 이제 익숙한 Jupyter Notebook이 보이고 Julia 커널을 사용할 수 있게됨
- 최초 실행 이후엔 Jupyter Notebook으로 실행해도 줄리아 커널이 보임
Package 설치
- 패키지 Import는 using을 사용
Pkg를 사용해 패키지 설치
usisg Pkg Pkg.add("PackageName")
기본 문법
- 함수의 Document를 보고 싶은 경우
- 함수 앞에 ?를 붙임
- ?println
- 쉘 커맨드를 사용하고 싶은 경우
- ;를 앞에 붙임
- ;ls
- print
- println() 사용
- Assert
- @assert하고 식을 씀. 파이썬에서 assert a == 1 이런 느낌인데 골뱅이만 추가됨
Variable
- type 확인하기
- typeof() 사용
- 타입 변환은 파이썬처럼
float(365)
로 할수도 있고,parse(Float64, "365")
로 할수도 있음 - 신기한 부분은 이모지에 변수 할당할 수 있음(Super generic)
String
- "”나 “”” “"”를 사용함
- 후자의 경우 문자열 내에서 따옴표를 사용할 수 있고, 전자는 불가능(Error 발생)
- '’는 character고 string이 아님
"Here, we get an "error" because it's ambiguous where this string ends " """Look, Mom, no "errors"!!! """ typeof('a')
- String Interpolation
- Python의 F string같이 값을 넣고 흘려버리기
- 달러 기호
$
를 사용함 - $() 안에 연산도 할 수 있음
name = "kyle" num_fingers = 10 num_toes = 10 println("Hello, my name is $name.") println("I have $num_fingers fingers and $num_toes toes.") println("That is $(num_fingers + num_toes) digits in all!!")
- String Concatenation
- string끼리 합칠 경우엔
string()
을 사용
s3 = "How many cats "; s4 = "is too many cats?"; 😺 = 10 string(s3, s4) string("I don't know, but ", 😺, " is too few.")
- string끼리 합칠 경우엔
- String 반복
- Python에선 “hi”*100처럼 했지만 Julia에선 “hi”^100으로 가능함
Data Structures
- Tuple
- Tuple은 생성하고 바꿀 수 없음
()
로 만듬순서가 지정된 요소를 묶어 튜플로 만들 수 있음
myfavoriteanimals = ("penguins", "cats", "sugargliders") myfavoriteanimals[1]
- NamedTuples
- 각각의 요소가 이름이 있는 Tuple
myfavoriteanimals = (bird = "penguins", mammal = "cats", marsupial = "sugargliders") myfavoriteanimals[1] myfavoriteanimals.bird
- Dictionaries
- Python의 dictinary랑 비슷한듯. key-pair 존재
Dict()
으로 만들고, =>를 사용함myphonebook = Dict("Jenny" => "867-5309", "Ghostbusters" => "555-2368") myphonebook["Jenny"] myphonebook["Kramer"] = "555-FILK"
pop!
을 쓰면 값이 나옴(원본 dict엔 사라짐) 느낌표가 있다니 신기함pop!(myphonebook, "Kramer") myphonebook
- Tuple이나 Array와 다르게 dictionaries는 정렬되지 않아서 index로 접근할 수 없음
- Arrays
- Array는 mutable하고 dict과 다르게 순서가 있음
[]
로 만듬myfriends = ["Ted", "Robyn", "Barney", "Lily", "Marshall"] mixture = [1, 1, 2, 3, "Ted", "Robyn"]
push!
와pop!
사용 가능ND Array도 생성할 수 있음
numbers = [[1, 2, 3], [4, 5], [6, 7, 8, 9]] rand(4, 3) rand(4, 3, 2)
- 복사는
copy()
를 사용해 가능 - array의 길이는
length()
사용 - array의 요소 합은
sum()
사용
Loops
- while loops와 for loops이 있음 : 모두 end를 써야함
- while loops
사용 방식
while *condition* *loop body* end
예시 : indent에 둔감함
n = 0 while n < 10 n += 1 # n = n + 1 println(n) end n
세미 콜론(;)을 사용하면 줄바뀜 효과를 얻음
n = 0 while n < 10; n += 1 println(n) end n
myfriends = ["Ted", "Robyn", "Barney", "Lily", "Marshall"] i = 1 while i <= length(myfriends) friend = myfriends[i] println("Hi $friend, it's great to see you!") i += 1 end
- for loops
사용 방식
for *var* in *loop iterable* *loop body* end
예시(1:10은 python에서 range(1, 10)과 동일)
for n in 1:10 println(n) end
myfriends = ["Ted", "Robyn", "Barney", "Lily", "Marshall"] for friend in myfriends println("Hi $friend, it's great to see you!") end
2중 for문을 더 쉽게 쓸 수 있음
m, n = 5, 5 A = fill(0, (m, n)) for i in 1:m for j in 1:n A[i, j] = i + j end end A
B = fill(0, (m, n)) for i in 1:m, j in 1:n B[i, j] = i + j end B
Array comprehension(Python의 list comprehension 느낌) => Julia 스타일
[ x+y for x in 1:10, y in 2:5] C = [i + j for i in 1:m, j in 1:n]
Conditionals
if문
if *condition 1* *option 1* elseif *condition 2* *option 2* else *option 3* end
- fizzbuzz 예시
- &&는 AND를 뜻함
- %는 나머지를 뜻함
N=15 if (N % 3 == 0) && (N % 5 == 0) # `&&` means "AND"; % computes the remainder after division println("FizzBuzz") elseif N % 3 == 0 println("Fizz") elseif N % 5 == 0 println("Buzz") else println(N) end
- fizzbuzz 예시
- ternary operators(삼항 연산) : 오 신기함
- a ? b : c
이건 아래와 동의어임
if a b else c end
- 예시
x = 10 y = 5 if x > y x else y end (x > y) ? x : y
- short-circuit evaluation
- a && b
- if a and b가 true일 경우 true를 return함
false && (println("hi"); true) true && (println("hi"); true)
error()
를 사용하면 Error 발생true || println("hi")
||
operator는 or을 뜻함true || println("hi") false || println("hi")
Functions
- 주요 Topic
- 함수 정의하는 방법
- Duck-typing 하는 방법 : 타입을 미리 정의하는게 아닌 실행되었을 때 타입 정의. 덕타이핑이란? 글 참고
- Mutating vs non-mutating function
- Some higher order functions
함수 정의
function sayhi(name) println("Hi $name, it's great to see you!") end function f(x) x^2 end
1줄로 할 수도 있음
sayhi2(name) = println("Hi $name, it's great to see you!") f2(x) = x^2
- 함수 인자 타입 지정
::
사용하며 타입 선언이 없으면 기본적으로 Any 타입으로 지정됨
foo(x::Int, y::Int) = println("My inputs x and y are both integer!") foo(3, 4)
anonymous(익명) 함수 : = 를 사용해서 -> 결과를 낸다. Tuple도 사용 가능
sayhi3 = name -> println("Hi $name, it's great to see you!") f3 = x -> x^2 sayhi4 = (firstname, lastname) -> println("Hi $firstname $lastname, it's greate to see you!")
- Duck-typing
- Julia는 모든 입력이 의미가 있다고 생각함
- string으로 들어갈 것이라 예상했던 것이 int가 들어가도 작동함
sayhi(55595472) A = rand(3, 3) f(A) f("hi") # vector 연산은 ^ 연산이 구현되지 않아서 아래 명령어는 오류 발생 v = rand(3) f(v)
- Mutating vs non-mutating functions
!
를 붙이는 차이- sort는 원본 데이터는 변하지 않지만, sort!는 변함. 마치 pandas에서 replace=True가 기본적으로 들어간게 ! 붙인거 같은 느낌
v = [3, 5, 2] sort(v) v sort!(v) v
- Some higher order functions(고차 함수)
- map
- 해당 함수를 전달한 데이터의 모든 요소에 적용함
- map(f, [1, 2, 3]) => [f(1), f(2), f(3)] 이렇게 됨
map(x -> x^3, [1, 2, 3])
- broadcast
- map의 일반적인 형태
broadcast(f, [1, 2, 3])
함수 뒤에
.
을 붙일 경우에도 broadcast됨f.([1, 2, 3])
연산 차이
A = [i + 3*j for j in 0:2, i in 1:3] f(A) # A^2 = A*A 행렬 곱 f.(A) # 각 요소들의 제곱
아래 두 코드는 동일한 결과가 나타남
broadcast(x -> x + 2 * f(x) / x, A) A .+ 2 .* f.(A) ./ A
- map
Packages
- https://pkg.julialang.org/docs/에서 사용 가능한 패키지를 확인할 수 있음
패키지 설치(Pkg : 패키지 관리자)
using Pkg Pkg.add("Example")
패키지 사용
using "package name"
- using을 하면 그 안에 있는 함수를 사용할 수 있음
Palette 사용하는 예시
Pkg.add("Colors") using Colors palette = distinguishable_colors(100) rand(palette, 3, 3)
Plotting
- 그래프를 그리는 방식은 정말 다양함(PyPlot을 부를수도 있고, Plots 사용할수도 있음)
- Plots는 다양한 백엔드를 지원하는데, GR과 UnicodePlots을 사용해볼 예정
- Plots Backent 참고
- gr을 빌드할 때 너무 오래 걸려서 링크를 찾아봄
- Using Plots시 Permission Error가 떠서 PyPlot을 사용함
import Pkg; Pkg.add("Plots") using Plots globaltemperatures = [14.4, 14.5, 14.8, 15.2, 15.5, 15.8] numpirates = [45000, 20000, 15000, 5000, 400, 17]; gr() plot(numpirates, globaltemperatures, label="line") scatter!(numpirates, globaltemperatures, label="points") xlabel!("Number of Pirates [Approximate]") ylabel!("Global Temperature (C)") title!("Influence of pirate population on global warming") xflip!()
Pkg.add("PyPlot") using PyPlot globaltemperatures = [14.4, 14.5, 14.8, 15.2, 15.5, 15.8] numpirates = [45000, 20000, 15000, 5000, 400, 17]; plot(numpirates, globaltemperatures, label="line") scatter(numpirates, globaltemperatures, label="points", color="red") xlabel("Number of Pirates [Approximate]") ylabel("Global Temperature (C)") title("Influence of pirate population on global warming")
Multiple Dispatch
- 아마 생소한 개념. 위키피디아 참고
- 함수의 인자 타입에 따라 다른 함수 호출
foo(x::String, y::String) = println("My inputs x and y are both strings!") foo("hello", "hi!") foo(3, 4) # MethodError: no method matching foo(::Int64, ::Int64) foo(x::Int, y::Int) = println("My inputs x and y are both integers!") foo(3, 4)
method()
를 사용하면 함수에 대한 내용이 나옴- generic function with 2 methods : 2가지 메서드를 가진 함수 객체를 뜻함
methods(foo) >>> 2 methods for generic function foo: >>> foo(x::Int64, y::Int64) in Main at In[8]:1 >>> foo(x::String, y::String) in Main at In[5]:1 foo(x::Number, y::Number) = println("My inputs x and y are both numbers!") foo(x, y) = println("I accept inputs of any type!") v = rand(3) foo(v, v)
- method(+)를 입력해서 + 구현을 확인해볼 수 있음
generic function을 호출할 때 어떤 메소드가 전달되는지 확인하려면 @which 매크로를 사용할 수 있음
@which foo(3, 4) >>> foo(x::Int64, y::Int64) in Main at In[8]:1 @which 3.0 + 3.0 >>> +(x::Float64, y::Float64) in Base at float.jl:395
- 간단한 내용만 본거고, 더 궁금하면 Github 참고하면 좋음
Dataframe
- 데이터를 조작하기 위해 Dataframes.jl 활용
Pandas와 비슷한 느낌
import Pkg; Pkg.add("DataFrames") using DataFramesusing DataFrames df = DataFrame(A = 1:4, B = ["M", "F", "F", "M"])
df.col
또는df[!, :col]
을 통해 열에 직접 액세스 가능- 후자는 열 이름을 변수에 전달할 수 있어 유용함. 열 이름은 Symbol(“col”)
names(df)
로 이름을 확인할 수 있음- df[!, :col]은 복사하지 않고 원본을 컨트롤하고, df[:, :col]은 사본을 얻음
Dataframe을 만들고 하나씩 붙이는 것도 가능(Column끼리)
df = DataFrame() df.A = 1:8 df.B = ["M", "F", "F", "M", "F", "M", "M", "F"]
Row끼리 합치기 :
push!
사용df = DataFrame(A = Int[], B = String[]) push!(df, (1, "M")) push!(df, [2, "N"]) push!(df, Dict(:B => "F", :A => 3))
저장하기
using Pkg Pkg.add("CSV") using CSV CSV.write("dataframe.csv", df)
Filtering : Pandas랑 느낌 비슷한데 점을 추가함(각 요소별 연산) : .>, in. 등
df = DataFrame(A = 1:2:1000, B = repeat(1:10, inner=50), C = 1:500) df[df.A .> 500, :]
- Describe
- describe(df)로 가능
df = DataFrame(A = 1:4, B = ["M", "F", "F", "M"]) describe(df)
Aggregate : aggregate(df, 연산)
df = DataFrame(A = 1:4, B = 4.0:-1.0:1.0) aggregate(df, sum) aggregate(df, [sum, prod])
특정 값 변경하기
df.A[1] = 10
CSV Read
using Pkg Pkg.add("CSV") using CSV DataFrame(CSV.File(input))
DelimitedFiles(CSV 읽기)
using DelimitedFiles P,H = readdlm("programminglanguages.csv",header=true)
- Join
- join 인자 안에 kind = :inner, :left 등을 사용할 수 있음
people = DataFrame(ID = [20, 40], Name = ["John Doe", "Jane Doe"]) jobs = DataFrame(ID = [20, 40], Job = ["Lawyer", "Doctor"]) join(people, jobs, on = :ID)
- 그 외에도 Split-apply-combine을 위해 by 등을 사용함
최적화 라이브러리
- JuliaOpt 쪽에 자료 많음
- JuMP.jl
- CVX는 Convex.jl
JuMP 예시 코드
using JuMP, GLPK # 모델 생성 m = Model(with_optimizer(GLPK.Optimizer)) # Variable 선언 @variable(m, 0<= x1 <=10) @variable(m, x2 >=0) @variable(m, x3 >=0) # 목적 함수 @objective(m, Max, x1 + 2x2 + 5x3) # 제약 조건 설정 @constraint(m, constraint1, -x1 + x2 + 3x3 <= -5) @constraint(m, constraint2, x1 + 3x2 - 7x3 <= 10) # Optimization Model 출력 print(m) # 최적화 문제 풀기 JuMP.optimize!(m) # Optimal Solution Print println("Optimal Solutions:") println("x1 = ", JuMP.value(x1)) println("x2 = ", JuMP.value(x2)) println("x3 = ", JuMP.value(x3)) # Optimal dual variables Print println("Dual Variables:") println("dual1 = ", JuMP.shadow_price(constraint1)) println("dual2 = ", JuMP.shadow_price(constraint2))
VSCode Extension
Reference
- 권창현님의 Julia Programming for Operation Research
- Julia 공식 Document
- Intro to Julia tutorial (version 1.0)
- Intro to Julia
카일스쿨 유튜브 채널을 만들었습니다. 데이터 분석, 커리어에 대한 내용을 공유드릴 예정입니다.
PM을 위한 데이터 리터러시 강의를 만들었습니다. 문제 정의, 지표, 실험 설계, 문화 만들기, 로그 설계, 회고 등을 담은 강의입니다
이 글이 도움이 되셨거나 의견이 있으시면 댓글 남겨주셔요.