데이터 수집없이는, Data Science or Data Analytic과정에 접근 할 수없다.
Pandas
- 2008년 Wes Mckinney에 의해 제작
- 초기에는 재정적 정량화를 위해 개발
- 오늘날 대규모 개발 커뮤니티 분야에서 사용
- 판다스를 사용하면 데이터를 쉽게 로드하고 조작 할 수 있으며, 분석 및 시각화 라이브러리와 통합되어 쉽게 사용 가능
DataFrame
- Pandas의 중심 자료형
- 2차원 데이터 구조 ( 열 - column labels 과 행 - row labels 을 가짐 )
- pandas는 다양한 데이터 형식을 처리
Flat Files
- 매우 간단한 구조로, 데이터 저장 및 공유에 널리 사용
- Flat file 데이터는 색상이나 글꼴같은 서식 없이, 일반 텍스트로 저장
- 각 행은, 구분 기호(delimiter) 라고 불리는 문자로 구분하여 한 행을 나타냄
- 일반적인 구분기호는 쉼표(,) - 이 외에 값도 사용 가능
ex) delimiter가 쉼표일때
import pandas as pd
tax_data = pd.read_csv("us_tax_data.csv")
tax_data.head(4)
ex) delimiter가 탭일때
import pandas as pd
tax_data = pd.read_csv("us_tax_data.tsv", sep ="\t")
tax_data.head(4)
usecols
usecols 파라미터를 이용해서, 원하는 column만 로드할 수 있음
ex) column 이름으로 로드
col_names = ['STATEFIPS', 'STATE', 'zipcode', 'agi_stub', 'N1']
tax_data_v1 = pd.read_csv("us_tax_data.csv", usecols = col_names )
ex) column 번호로 로드
col_nums = [0,1,2,3,4]
tax_data_v2 = pd.read_csv("us_tax_data.csv", usecols = col_nums )
nrows
tax_data_first1000 =pd.read_csv("us_tax_data.csv", nrows=1000, skiprows=1000)
nrows : 몇번째 row까지 로드할 것인지
skiprows : 데이터를 로드할때, 몇번째 부터 가져올지
ex ) nrows 500, skiprows = 1000 => 1000행 ~ 1500행의 데이터를 가져옴
header
header = None
: 헤더정보를 가져오지않는다.
col_names = list(tax_data_first_1000)
tax_data_next500 = pd.read_csv("us_tax_data.csv", nrows=500, skiprows=1000,
header=None, names = col_names)
skiprows 하면 header 정보를 빼놓고 로드하는데, 이를 해결하기 위해 다음과같이 names 를 이용
Common Errors
- 분석을 방해 할 수 있는 잘못된 열 데이터 유형
- 결측 값
- 판다스로 읽을 수 없는 형식
1. Specifying Data Types
데이터를 가져올 때, Pandas는 각 열의 데이터 유형을 유추하는데, 때로는 잘못 유추
이를 막기 위해서, dtype
을통해 직접 데이터 유형을 선언
tax_data = pd.read_csv("us_tax_data.csv", dtype ={"zipcode":str})
2. Customizing Missing Data Values
Pandas 는 N/A 또는 null 과 같은 일부 값을 자동으로 인식
누락된 데이터를 데이터 정리 기능을 이용하여 자동으로 정리.
하지만 때때로 누락 된 값을 포착하지 못하는 방식으로 표현
이러한 NA values 키워드 인수를 사용하여 이러한 누락 된 데이터를 고려하도록 Pandas에게 지시가능
tax_data = pd.read_csv("us_tax_data.csv", na_values = {"zipcode":0})
3. Lines with Errors
Pandas가 파싱 할 수 없는 줄, ex ) 레코드에 있는 것보다 더 많은 값을 가진 경우
이런 경우는 error_bad_lines
와 warn_bad_lines
를 이용하여 해결
error_bad_lines = False
: 오류로 잘못된 줄을 False로 할 경우, Pandas가 건너 뜁니다.
warn_bad_lines = True
: 파싱 할 수 없는 줄을 건너 뛸 때 메시지를 표시
Spreadsheets
- Excel 파일로 잘 알려져있다.
- 데이터는 행과 열의 테이블 형태
- Flat files과 다르게 서식도 지원한다.
- Excel 파일 또는 통합 문서에는 여러개의 스프레드시트가 있을 수 있다.
Loading Spreadsheets
survey_data = pd.read_excel("fcc_surcey.xlsx")
사람이 읽기 쉬운 자료는, 기계가 읽기 어렵다.
스프레드 시트에는 일반적으로 표형식이 아닌 정보가 표함된다. ex) 메타 데이터, 헤더, 인보이스 등
CSV와 마찬가지로 Excel 읽기에서도 이러한 부분을 건너뛰거나 제한하여 원하는 행, 열만 가져올수있다.
nrows
: csv와 동일하게 행의 정수를 취함
skiprows
: 동일하게, 건너 뛸 행 번호를 취함
usecols
: 열 번호, 열 이름를 취함( CSV 와 다른점 : “A:P” 와 같이 문자의 범위도 가능)
survey_data = pd.read_excel("fcc_survey_with_headers.xlsx", skiprows=2, usecols="W:AB, AR")
Getting data from multiple worksheets
Excel 파일에는 여러 장의 데이터가 포함되는 것은 매우 일반적
기본적으로 Excel 읽기는, 통합 문서의 첫 번째 시트의 데이터를 가져옴
sheet_name
: 파라미터를 통해, 시트 이름 키워드 인수로 변경
survey_data_sheet2 = pd.read_excel("fcc_survey.xlsx", sheet_name=1)
----------
survey_data_2017 = pd.read_excel("fcc_survey.xlsx", sheet_name="2017")
Loading All Sheets
sheet_name = None
을 이용
survey_responses = pd.read_excel("fcc_survey.xlsx", sheet_name=None)
dict 형식으로 저장
Putting It All Together
나눠져 있는 스프레드시트를 하나의 데이터프레임으로
all_responses = pd.DataFrame()
for sheet_name, frame in survey_responses.items():
frame["Year"] = sheet_name
all_responses = all_responses.append(frame)
Modifying imports : true/false data
Pandas 는 Booleans 데이터를 bool 자료형으로 처리하지않음.
bool_data = pd.read_excel("fcc_survey_booleans.xlsx", dtype= {"AttendedBootCamp" : bool, "AttendedBootCampYesNo" : bool})
pandas 는 boolean 데이터에서, NaN 값을 True로 처리
bool_data = pd.read_excel("fcc_survey_booleans.xlsx", dtype= {"AttendedBootCamp" : bool, "AttendedBootCampYesNo" : bool}, true_value = ["Yes"], false_value = ["No"])
이를 사용하면 NaN값으로 표시
Modifying imports : parsing dates
파이썬은 날짜 시간형식을, 특수 데이터 유형인 datetime으로 저장합니다.
datetimes 는 무수히 많은 표현으로 나타 낼 수 있습니다.
기본적으로 datetime 데이터를 object타입으로 로드
만약 datetime관련 연산을 하고싶다면, parse_dates
키워드 변수를 사용 (dtype
이 아님을 주목)
parse_dates
는 파싱 할 열 이름 또는 숫자, 리스트 형을 허용
date_cols = ["Part1StartTime", "Part1EndTime"]
survey_df = pd.read_excel("fcc_survey.xlsx", parse_dates=date_cols)
date_cols = ["Part1StartTime", "Part1EndTime", [["Part2StartDate", "Part2StartTime"]]]
survey_df = pd.read_excel("fcc_survey.xlsx", parse_dates=date_cols)
date_cols = {"Part1Start":"Part1StartTime", "Part1End":"Part1EndTime", "Part2Start":["Part2StartDate","Part2StartTime"]}
survey_df = pd.read_excel("fcc_survey.xlsx", parse_dates=date_cols)
이러한 형식은 pandas가 읽을 수 있는 형태일 때 작동합니다.
Non-Standard Dates
비정상적인 날짜와 형식을 분석하려는 경우, object타입으로 로드한 뒤,
to_datetime()
를 사용하여 날짜 형식으로 변경
Datetime Formatting
Code | Meaning | Example |
---|---|---|
%Y | Year(4-digit) | 1999 |
%m | Month(zero-padded) | 03 |
%d | Day(zero-padded) | 01 |
%H | Hour(24-hour clock) | 21 |
%M | Minute(zero-padded) | 09 |
%S | Second(zero-padded) | 05 |
Parsing Non-Standard Dates
ex) 03292016 21:27:25
format_string = "%m%d%Y %H:%M:%S"
survey_df["Part2EndTime"] = pd.to_datetime(survey_df["Part2EndTime"], format = format_string)
Introduction to databases
- 관계형 데이터베이스는 테이블의 엔티티에 대한 데이터를 구성.
- 데이터 프레임, 플랫 파일 및 많은 Excel 시트가 비슷한 방식으로 데이터를 정렬
- 관계형 데이터베이스는 고유한 레코드 식별자 또는 키를 통해 테이블을 연결하거나 관련 시킬 수 있다 는게 차이점
- 데이터베이스는 스프레드시트 또는 플랫파일보다 더 많은 데이터를 처리하고 더 많은 사용자를 지원 + 더많은 데이터 품질 관리 기능을 제공
SQL(Structured Query Language) 를 통해 데이터베이스와 인터페이스합니다.
Common Relational Databases
- Microsoft SQL server
- ORACLE
- PostgreSQL
- SQLite
다른 데이터베이스와 달리 SQLite 데이터베이스는 일반 자체 포함 된 데이터베이스로 저장
CSV 및 Excel 파일과 마찬가지로 컴퓨터 파일도 데이터 공유에 적합
Connecting to Databases
- 데이터베이스에 연결하는 방법을 만든다.
- SQL 및 Pandas를 이용한 쿼리이용
이를 위해 관계형 데이터베이스와 함께 SQLAlchemy 라이브러리를 사용
Creating a Database Engine
sqlalchemy
의 create_engine()
를 이용하여,
데이터베이스에 대한 URL(문자열)를 입력해, 데이터베이스 연결을 관리하는 엔진을 만듬
URL은 데이터베이스에 따라 약간씩 다른 패턴을 가짐.
sqlite:///filename.db
Querying Databases
pd.read_sql(query, engine)
를이용하여, 데이터를 가져올 수 있다.
query
: SQL쿼리의 문자열이거나, 전체 테이블을로드하려는 경우 테이블의 이름
engine
: 데이터베이스에 연결하는 방법
SQL Review : SELECT
SELECT [coulumn_names] FROM [table_name];
- 지정된 열에 대한 모든 행을 로드
SELECT * FROM [table_name];
- 해당 테이블에 모든 정보를 로드
일반적으로 대소 문자를 구분하지만, 모두 대문자로 입력하는 것이 일반적 + 세미클론으로 SQL 문의 끝을 표시하는 것이 모범적
Getting Data from a Database
import pandas as pd
from sqlalchemy import create_engine
engine = create_engine("sqlite:///data.db")
weather = pd.read_sql("weather", engine) # case 1
----------------
weather = pd.read_sql("SELECT * FROM weather", engine) # case 2
SELECTing Columns
SELECT [column names]
FROM [table name];
SELECT date, tavg FROM weather;
WHERE Clauses
SELECT [column_names]
FROM [table_name]
WHERE [condition];
Filtering by Numbers
=
>
and>=
<
and<=
<>
(not equal to)
SELECT *
FROM weather
WHERE tmax > 32;
Filtering Text
=
를이용하여, 문자열 필터링 가능
SELECT *
FROM hpd311calls
WHERE borough = 'BROOKLYN';
SQL and pandas
import pandas as pd
from sqlalchemy import create_engine
engine = create_engine("sqlite:///data.db")
query = """
SELECT *
FROM hpd311calls
WHERE borough ='BROOKLYN;
"""
brooklyn_calls = pd.read_sql(query, engine)
Combining Conditions : AND
and_query = """
SELECT *
FROM hpd311calls
WHERE borough ='BRONX'
AND complaint_type ='PLUMBING';
"""
bx_plumbing_calls = pd.read_sql(and_query, engine)
Combining Conditions : OR
or_query = """
SELECT *
FROM hpd311calls
WHERE complaint_type ='WATER LEAK'
OR complaint_type ='PLUMBING';
"""
bx_plumbing_calls = pd.read_sql(or_query, engine)
Getting DISTINCT values
SELECT DISTINCT [column names]
FROM [table];
SELECT DISTINCT (*)
FROM [table];
SELECT DISTINCT incident_address, borough
FROM hpd311calls;
Aggregate Functions
- SUM
- AVG
- MAX
- MIN
- COUNT
SELECT AVG(tmax)
FROM weather;
SELECT COUNT(*)
FROM [table_name];
SELECT COUNT(DISTINCT [column_names])
FROM [table_name];
GROUP BY
SELECT borough, COUNT(*)
FROM hpd311calls
WHERE complaint_type ='PLUMBING'
GROUP BY borough;
engine = create_engine("sqlite:///data.db")
query = """
SELECT borough, COUNT(*)
FROM hpd311calls
WHERE complaint_type = 'PLUMBING'
GROUP BY borough;
"""
plumbing_call_counts = pd.read_sql(query, engine)
Loading multiple tables with joins
관계형 데이터베이스의 한 가지 기능은 고유 한 레코드 식별자 또는 키를 통해 테이블을 서로 연결할 수 있다는 것
Keys
일반적으로, 레코드를 고유하게 식별하는 키가 있음.
이를 이용해, 자동으로 행 번호를 할당
Joining Tables
SELECT *
FROM hpd311calls
JOIN weather
ON hpd311calls.created_date = weather.date;
Joining and Filtering
SELECT *
FROM hpd311calls
JOIN weather
ON hpd311calls.created_date = weather.date
WHERE hpd311calls.complaint_type = 'HEAT/HOT WATER';
Joining and Aggregating
SELECT hpd311calls.borough, COUNT(*)
FROM hpd311calls
GROUP BY hpd311calls.borough;
SELECT hpd311calls.borough, COUNT(*), boro_census.total_population, boro_census.housing_units
FROM hpd311calls
GROUP BY hpd311calls.borough;
SELECT hpd311calls.borough, COUNT(*), boro_census.total_population, boro_census.housing_units
FROM hpd311calls
JOIN boro_census
ON hpd311calls.borough= boro_census.borough
GROUP BY hpd311calls.borough;
Review
- SELECT
- FROM
- JOIN
- WHERE
- GROUP BY
Javascript Object Notation (JSON)
- 일반적으로, 웹 데이터 형식
- 표 형식 X ( 모든 레코드가 동일한 속성 집합을 가질 필요는 없다. )
- 데이터는 개체 모음으로 구성 ( 파이썬 딕셔너리와 비슷 )
- 중첩 될 수 있음
Reading JSON Data
read_json()
를 통해 DataFrame으로 로드할 수 있습니다.
- JSON 읽기는 JSON 경로 문자열을 이용 or 데이터를 문자열로 제공
dtype
을 통해 형식 지정orient
를 통해, 레이아웃 플래그를 지정
Data Orientation
- JSON 데이터는 표형식이 아니므로, Pandas가 테이블을 어떻게 정리할지 추측.
- Pandas는 가장 자주 접하게 되는 레코드 및 열 방향을 자동으로 감지
Record Orientation
- 레코드 지향 JSON은 각각 테이블 레코드로 변환되는 사전목록을 구성
Column Orientation
- 속성 이름을 반복하지 않음으로써 파일 크기를 줄이기 위해 JSON은 열 지향적일 수 있습니다.
Specifying Orientation
import pandas as pd
death_causes = pd.read_json("nyc_death_causes.json", orient ="split")
Application Programming Interfaces ( API )
JSON 데이터의 가장 일반적인 소스, API
API는 응용 프로그램이 다른 프로그램과 통신 할 수 있는 정의 된 방법이며, 그 반대의 경우도 동일.
- 프로그래머가 응용 프로그램에서 데이터를 가져올 수 있다.
- 해당 애플리케이션의 데이터베이스 아키텍처에 대해 알아야한다.
- API는 공유 리소스이며, 지정된 기간 동안 얻을 수 있는 데이터 양을 제한하는 경우가 많다.
API를 사용하여 데이터를 얻는 것은 카탈로그를 사용하여 제품을 주문하는 것과 같다. 카탈로그는 사용 가능한 제품을 보여주고 주문 지침을 제공합니다. 올바른 주소로 올바르게 구성된 주문을 보내고, 주문한 것을 받는다.
API는 요청을 보낼 엔드 포인트를 제공, 문서는 포함 할 매개 변수와 같은 요청의 모양을 설명
Requests
- 요청을 통해 사용자는 모든 URL에서 데이터를 보내고 받음
- 특정 API와 관계 X.
requests.get()
를 통해 URL 데이터를 가져옴
request.get()
requests.get(url_string)
데이터를 가져올 URL 문자열을 입력받음.
API 작업에 유용한 파라미터들
params
: 매개 변수 이름 및 값 딕셔너리를 전달하여, API 요청을 사용자 정의headers
: 동일하게 이름과 값을 취함, 사용중인 API에 사용자 인증 키가 필요한 경우 헤더로 전달 결과 값은,response
객체로, 데이터와 메타 데이터를 포함
데이터만 가져오려면, response.json()
를 이용
response.json() and pandas
response.json()
: 딕셔너리 값을 반환read_json()
: 문자열 로드 ( 딕셔너리 구문은 로드할 수 없음 )- JSON 데이터를 DataFrame으로 로드하려면,
pd.DataFrame()
를 이용 (read_json
는 오류 발생)
Yelp Business Search API
API 예시코드
import requests
import pandas as pd
api_url = "https://api.yelp.com.v3/businesses/search" # End point 지정
params = {"term" : "bookstore","location":"San Francisco:"}
headers = {"Authorization" : "Bearer {}".format(api_key)}
response = requests.get(api_url, params = params, headers=headers)
Parsing Responses
data = response.json()
booksores = pd.DataFrame(data['businesses'])
Nested JSONs
JSON에는 속성 - 값 쌍이있는 개체가 포함
JSON 값 자체가 객체 인 경우 JSON은 중첩
Pandas.io.json
pandas.io.json` 하위 모듈에 읽기 및 쓰기 기능이 포함
json_normalize()
json 정규화 기능을 사용하여, 중첩 된 데이터를 평면화,
JSON 정규화는 딕셔너리 또는 사전 목록을 사용
반환 값으로, 평면화 데이터 프레임
중첩 된 속성 열 이름은 기본 패턴 속성 점 중첩 된 속성을 따름
점 구분 기호는 열 선택을 위한 pandas의 점 표기법을 방해하므로,
sep 인수와 함께 밑줄과 같은 다른 구분 기호를 지정하는 것이 좋음
Loading Nested JSON Data
import pandas as pd
import requests
from pandas.io.json import json_normalize
api_url = "https://api.yelp.com.v3/businesses/search"
headers = {"Authorization" : "Bearer {}".format(api_key)}
params = {"term" : "bookstore","location":"San Francisco:"}
response = requests.get(api_url, params = params, headers=headers)
data = response.json()
bookstores = json_normalize(data['businesses'], sep = "_")
Deeply Nested Data
사용자 지정 평면화 함수를 작성하거나 분석과 관련이 없다고 판단하여 그대로 둘 수 있습니다.
json_normalize()
record_path
string/list 레코드 경로는 파일 경로에 폴더를 나열하는 것과 같이 중첩 된 데이터에 대한 문자열 또는 속성 문자열 목록을 사용meta
결과 데이터 프레임에 포함 할 상위 레벨 속성 목록을 가져옴,meta_prefix
어디에서 왔는지 명확히하고 열 이름이 중복되지 않도록 하려면 메타 접두사를 지정
df = json_normalize(data['businesses'], sep="_", record_path = "categories", meta =["name", "alias", "rating",["coordinates","latitude"],["coordinates","longitude"]], meta_prefix = "biz_")
Combining multiple datasets
프로젝트는 여러 위치에서 데이터를 가져옵니다.
Appending
append()
는 추가 할 데이터 프레임을 인수로 사용하는 데이터 프레임 메서드
ex) df1.append(df2)
index를 무시하려면, ingnore_index = True
설정
params = {"term" : "bookstore", "location" : "San Francisco"}
first_results = requests.get(api_url, headers=headers, params = params).json()
first_20_bookstores = json_normalize(first_results["businesses"], sep="_")
bookstores = first_20_bookstores.append(next_20_bookstores, ignore_index=True)
Merging
SQL join과 비슷하게 실행됨
pandas 에서는 merge()
를 이용해서 병합
df.merge()
- 두번째 DataFrame과 병합
- 두 DataFrame 의 column이 일치하는 경우
on
파라미터를 이용하여, 병합 가능 - 서로 다를경우,
left_on
andright_on
을 사용하여 병합 - 동일한 데이터 유형이여야함
- 기본적으로 merge는 두 데이터 세트에 있는 키 값이 있는 행만 반환
merged = call_counts.merge(weather, left_on = "created_date", right_on="date")