no image
[Python] 데이터 전처리
1. 중복 데이터 처리 - 하나의 데이터 셋에서 동일한 관측 값이 2개 이상 중복되는 경우 분석 결과를 왜곡할 수 있음 1) duplicated() - 데이터의 중복 여부를 bool의 Series로 리턴 2) drop_duplicates() - 매개변수를 대입하지 않으면 모든 컬럼의 값이 일치하는 경우 제거 - subset 옵션: [‘컬럼 이름’]이나 [[‘컬럼’, ‘이름’, ‘list’]]를 대입하면 중복을 제거하고 첫번째 데이터만 유지 - keep 옵션: 위의 경우에서 마지막 데이터를 유지 - inplace 옵션 : 원본에 직접 작업 pandas와 DataFrame은 원본을 복제해서 수정하고 리턴 실시간으로 대량 발생하는 데이터는 데이터베이스에 바로 저장 못함 데이터 -> csv 파일에 기록 (유효성..
2024.02.15
no image
[Python] 데이터 시각화
1. 데이터 시각화 - matplotlib 1) 앤스콤 데이터 - 이 데이터는 4개의 데이터 그룹으로 구성 - 앤스콤 데이터 가져오기 #앤스콤 데이터 가져오기 import seaborn as sns anscombe = sns.load_dataset("anscombe") print(anscombe.head()) print(anscombe['dataset'].unique()) dataset x y 0 I 10.0 8.04 1 I 8.0 6.95 2 I 13.0 7.58 3 I 9.0 8.81 4 I 11.0 8.33 ['I' 'II' 'III' 'IV'] # 데이터셋 분리 #dataset 별로 분리 dataset_1 = anscombe[anscombe['dataset'] == 'I'] dataset_2 = ..
2024.02.14
no image
[Python] 데이터 탐색
1. 데이터프레임에서의 데이터 선택 1) 열 선택 - 데이터프레임['컬럼이름'] 또는 데이터프레임.컬럼이름 데이터프레임.컬럼이름 으로 접근할 때는 컬럼이름이 반드시 문자열이어야 함 - 하나의 컬럼이름을 이용해서 접근하면 Series로 리턴 2) 행 선택 - loc[인덱스이름] - iloc[정수형 위치 인덱스] - Series로 리턴 3) 셀 선택 - [컬럼이름][인덱스이름] - loc[인덱스이름, 컬럼이름] - iloc[행 위치 인덱스, 열 위치 인덱스] 4) 다중 선택 - list를 이용해서 선택 DataFrame이 리턴 #item.csv 파일을 읽어서 DataFrame 만들기 #csv를 읽을 때 확인할 3가지 #한글 포함 여부 - 인코딩 # 구분자는 , 인지 #첫번째 줄이 컬럼이름인지 아니면 데이터인..
2024.02.14
no image
[Python] MySQL 데이터로 DataFrame 만들기
1. 필요한 패키지 - sqlalchemy - pymysql - mysqlclient !pip install sqlalchemy !pip install pymysql !pip install mysqlclient 2. 데이터베이스 연결 데이터베이스 접속 URL은 데이터베이스 종류마다 다름 별도의 패키지를 설치해야 하는 경우도 있음 포트는 3306이면 생략 가능 import pandas as pd from sqlalchemy import create_engine import pymysql #연결 connect = create_engine('데이터베이스종류://아이디:비밀번호@IP:포트/데이터베이스이름') df = pd.read_sql_table('테이블', connect) print(df) Empty Dat..
2024.02.14
[Python] 크롤링 - Selenium
1. 개요 - 웹 앱을 테스트하는데 사용하는 프레임워크 - WebDriver 라는 API를 이용해서 운영체제에 설치된 브라우저를 제어하는 프레임워크 - 크롤링을 할 때 JavaScript를 이용해서 비동기적으로 가져오는 데이터를 읽고자 할 때 이용할 수 있고 로그인 후 가져와야 하는 데이터를 읽어오는데 사용합니다. 메뉴얼: http://docs.seleniumhq.org/docs/ - 파이썬에서 사용 준비 pip install selenium 브라우저의 드라이버가 필요 크롬의 버전을 확인 https://googlechromelabs.github.io/chrome-for-testing/#stable 2. 크롬 브라우저 실행 1) 기본 API - 접속: get(url) - html 코드 읽어오기: page_..
2024.02.14
no image
[Python] 크롤링 - 기사 스크래핑
1. 검색어를 입력받아서 동아일보 신문 기사를 스크래핑해서 파일에 저장하기 1) 필요한 패키지 - urllib.parse.quote 함수: 검색어가 한글이라면 인코딩을 하기 위해서 - requests: 웹의 문자열을 읽어오기 위한 패키지, 기본 패키지가 아니라서 설치를 해야 함 - beautifulsoup: HTML 문자열에서 원하는 데이터를 추출하기 위해서 필요한 패키지, 기본 패키지가 아니라서 설치를 해야 함 !pip install requests !pip install beautifulsoup4 2) URL 확인 https://www.donga.com/news/search?sorting=1&check_news=91&search_date=1&v1=&v2=&more=1&query=%EB%8B%B9%EA..
2024.02.14
no image
[Python] Pandas
1. Pandas 패키지 - 데이터 분석을 위한 고수준의 자료구조, 분석 도구 제공 - 자료구조 Series: 열이 1개인 데이터 구조 DataFrame: 열이 2개 이상인 데이터 구조 2. Series - Index와 Value 1개를 가지는 자료구조 series (데이터, index=None, dtype=None, copy=False) 데이터: list, set, dict와 numpy.ndarray 가능 index: 데이터를 가리키는 이름 list · set · ndarray를 대입하면 0부터 시작하는 숫자 인덱스가 자동으로 생성 dict를 설정하면 key가 인덱스 index 옵션에 직접 인덱스 설정 가능 dtype 데이터 1개의 자료형으로 설정 -> 그 자료형으로 생성 설정 없음 -> pandas가..
2024.02.08
no image
[Python] Numpy
1. 특징 - Python에서 고성능의 과학적 계산 수행하는 패키지 (ex.선형 대수) - Python 머신러닝 스택의 기초 패키지 - 다차원 배열인 ndarray를 제공 - 벡터화 된 연산과 Broadcasting 연산 지원 2. 설치 pip install numpy *아나콘다는 자동 설치 *다른 패키지를 설치할 때 종속적으로 설치되는 경우가 있음 -> 버전 문제 발생 3. 사용 import numpy import numpy as np from numpy import * # 모듈의 모든 내용을 현재 모듈에서 사용 from numpy import ndarray # numpy 모듈 중에서 ndarray만 사용 import *을 쓰면 nupmy 써주지 않아도 사용할 수 있지만, 내장함수인지 구분이 가지 않음..
2024.02.06

[Python] 데이터 전처리

0ㅑ채
|2024. 2. 15. 17:35

1. 중복 데이터 처리

- 하나의 데이터 셋에서 동일한 관측 값이 2개 이상 중복되는 경우 분석 결과를 왜곡할 수 있음
 

1) duplicated()

- 데이터의 중복 여부를 bool의 Series로 리턴
 

2) drop_duplicates()

- 매개변수를 대입하지 않으면 모든 컬럼의 값이 일치하는 경우 제거
- subset 옵션: [‘컬럼 이름’]이나 [[‘컬럼’, ‘이름’, ‘list’]]를 대입하면 중복을 제거하고 첫번째 데이터만 유지
- keep 옵션: 위의 경우에서 마지막 데이터를 유지
- inplace 옵션 : 원본에 직접 작업

pandas와 DataFrame은 원본을 복제해서 수정하고 리턴

실시간으로 대량 발생하는 데이터는 데이터베이스에 바로 저장 못함
데이터 -> csv 파일에 기록 (유효성 검사를 할 수 없어서 잘못된 데이터가 저장되는 경우 발생) -> 데이터베이스에 반영

 

3) 중복 데이터 제거 실습

df = pd.DataFrame([['안녕하세요', '반갑습니다', '헬로우', '키아 오라', '반갑습니다'], 
                  ['한국', '한국', '미국', '뉴질랜드', '한국']])

#행 열 전치
df = df.T
df.columns = ['인사말', '국가']
print(df)
     인사말              국가
0  안녕하세요        한국
1  반갑습니다        한국
2    헬로우            미국
3  키아 오라       뉴질랜드
4  안녕하세요        한국

 
# 모든 컬럼에서 중복된 경우를 확인

print(df.duplicated())
0    False
1    False
2    False
3    False
4     True
dtype: bool

 
# 하나의 컬럼에서 중복된  경우를 확인

print(df.duplicated(subset=['국가'])) #국가 컬럼의 값이 중복된 경우 확인
0    False
1     True
2    False
3    False
4     True
dtype: bool

 
# 중복 데이터 제거

print(df.drop_duplicates(subset=['국가']))
     인사말    국가
0  안녕하세요    한국
2    헬로우    미국
3  키아 오라  뉴질랜드
  • 기본적으로는 앞의 데이터를 보존하고 뒤의 중복값을 제거한다.
  • 마지막 데이터를 보존하려면 keep 옵션 사용
print(df.drop_duplicates(subset=['국가'], keep='last')) # 마지막 데이터 보존
     인사말    국가
2    헬로우    미국
3  키아 오라  뉴질랜드
4  반갑습니다    한국

 
 
 
 

2. 함수 적용

1) apply

- Series나 DataFrame에 사용할 수 있는 함수

  • Series: 각 요소에 적용해서 결과를 Series로 리턴
  • DataFrame: 기본적으로 열 단위로 대입하고 DataFrame으로 리턴. axis=1을 설정하면 행 단위로 적용
import seaborn as sns
titanic = sns.load_dataset('titanic')
titanic.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 15 columns):
 #   Column       Non-Null Count  Dtype   
---  ------       --------------  -----   
 0   survived     891 non-null    int64   
 1   pclass       891 non-null    int64   
 2   sex          891 non-null    object  
 3   age          714 non-null    float64 
 4   sibsp        891 non-null    int64   
 5   parch        891 non-null    int64   
 6   fare         891 non-null    float64 
 7   embarked     889 non-null    object  
 8   class        891 non-null    category
 9   who          891 non-null    object  
 10  adult_male   891 non-null    bool    
 11  deck         203 non-null    category
 12  embark_town  889 non-null    object  
 13  alive        891 non-null    object  
 14  alone        891 non-null    bool    
dtypes: bool(2), category(2), float64(2), int64(4), object(5)
memory usage: 80.7+ KB
df = titanic[['sex', 'age']]
print(df.head())
      sex   age
0    male  22.0
1  female  38.0
2  female  26.0
3  female  35.0
4    male  35.0

 
# 사용자 함수

# 실수 1개를 받아서 1을 더해서 리턴하는 함수
def plusone(data:float) -> float:
    return data + 1

# 함수를 만들어서 적용
df['age'] = df['age'].apply(plusone)
print(df.head())
      sex   age
0    male  23.0
1  female  39.0
2  female  27.0
3  female  36.0
4    male  36.0

 
# 람다 함수

# 람다 함수를 이용해서 위와 동일한 작업 수행
df['age'] = df['age'].apply(lambda data : data+1)

 
# 브로드캐스트

df['age'] = df['age'] + 1

 
# 열의 모든 내용 대문자로 변경

# 문자열 클래스에 대문자로 변경해주는 메소드가 있는지 확인
df['sex'] = df['sex'].apply(str.upper)
print(df.head())
       sex       age
0    MALE     25.0
1  FEMALE  41.0
2  FEMALE  29.0
3  FEMALE  38.0
4    MALE     38.0

 
# 주의 에러

df = df.apply(str.upper)
print(df.head())

TypeError: descriptor 'upper' for 'str' objects doesn't apply to a 'Series' object

  • 데이터 프레임에 apply를 사용하면 함수에 이 대입
  • 하나의 열에 str.upper를 적용한 것이므로 에러 발생
  • 데이터 프레임에 apply를 적용할 때는 Series를 매개변수로 받아서 처리하는 함수 필요
#Series를 받아서 각 데이터가 null인지 확인
def missing_value(series: pd.Series) -> pd.Series:
    return series.isnull()

result = df.apply(missing_value)
print(result.head())
     sex    age
0  False  False
1  False  False
2  False  False
3  False  False
4  False  False
*SQL에서 where name = null을 하면 데이터가 없다고 나온다. insull을 사용해야 한다.
* null을 연산하면 null이 된다. null and False면 null이다. 
  그래서 항상 if(!=null)을 넣어줬음.
* 프로그래밍 언어에서는 Φ 이런게 null
* 데이터분석은 코드를 끊어서 봐야 한다.

 
 

2) pipe

- DataFrame 객체를 함수에 매핑할 때 사용

  • 하나의 값으로 작업하는 함수를 대입하면 동일한 구조의 데이터를 리턴
    • 모든 요소에 함수를 적용해서 그 결과를 가지고 데이터를 다시 생성해서 리턴
  • 집계 함수를 대입하면 열 단위로 함수를 적용해서 Series 리턴
  • Series를 리턴하는 함수를 호출해서 집계하면 하나의 값을 리턴
#Series를 받아서 Nan 여부를 리턴하는 함수
def missing_value(x:pd.Series) -> pd.Series:
    return x.isnull()

#Series를 받아서 True의 개수를 리턴하는 함수
def missing_count(x:pd.Series) -> int:
    return missing_value(x).sum()

#DataFrame을 받아서 총 Nan의 개수를 리턴하는 함수
def total_number_missing(x:pd.DataFrame) -> int:
    return missing_count(x).sum()
  • dataframe을 직접 넣기보다는 series로 작업을 많이 함!

 

 

타이타닉

df = titanic[['age', 'embarked']]
print(df.info())
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 2 columns):
 #   Column    Non-Null Count  Dtype  
---  ------    --------------  -----  
 0   age       714 non-null    float64
 1   embarked  889 non-null    object 
dtypes: float64(1), object(1)
memory usage: 14.1+ KB
None
print(df.pipe(missing_value))
       age  embarked
0    False     False
1    False     False
2    False     False
3    False     False
4    False     False
..     ...       ...
886  False     False
887  False     False
888   True     False
889  False     False
890  False     False

[891 rows x 2 columns]
print(df.pipe(missing_count))
age         177
embarked      2
dtype: int64
  • Series를 받아서 1개의 데이터(정수)를 리턴하는 함수 적용
  • Series를 리턴 - 각 열의 결과
print(df.pipe(total_number_missing))
  • DataFrame을 받아서 집계한 후 하나의 값을 리턴함수를 적용
  • 하나의 값을 리턴
179

 
 
 

3. 컬럼 재구성

1) 열 순서 변경  sorted()

- DataFrame[재구성할 열 이름의 list]

columns = list(titanic.columns.values) #원래는 ndarray
print(columns)
['survived', 'pclass', 'sex', 'age', 'sibsp', 'parch', 'fare', 'embarked', 'class', 'who', 'adult_male', 'deck', 'embark_town', 'alive', 'alone']

 
# 열 정렬 

titanic_sorted = titanic[sorted(columns)]
titanic_sorted

 

2) 날짜 컬럼 분할  split()

df = pd.read_excel('./data/주가데이터.xlsx')
print(df.info())
print(df.head())
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 20 entries, 0 to 19
Data columns (total 7 columns):
 #   Column  Non-Null Count  Dtype         
---  ------  --------------  -----         
 0   연월일     20 non-null     datetime64[ns]
 1   당일종가    20 non-null     int64         
 2   전일종가    20 non-null     int64         
 3   시가      20 non-null     int64         
 4   고가      20 non-null     int64         
 5   저가      20 non-null     int64         
 6   거래량     20 non-null     int64         
dtypes: datetime64[ns](1), int64(6)
memory usage: 1.2 KB


         연월일   당일종가  전일종가     시가     고가     저가     거래량
0 2018-07-02  10100         600        10850  10900  10000  137977
1 2018-06-29  10700         300        10550  10900   9990  170253
2 2018-06-28  10400         500        10900  10950  10150  155769
3 2018-06-27  10900         100        10800  11050  10500  133548
4 2018-06-26  10800         350        10900  11000  10700   63039

 
# - 기준으로 분할  str.split()

#날짜 컬럼 문자열로 변환
df['연월일'] = df['연월일'].astype('str')

dates = df['연월일'].str.split("-")
0    [2018, 07, 02]
1    [2018, 06, 29]
2    [2018, 06, 28]
3    [2018, 06, 27]
4    [2018, 06, 26]
df['연'] = dates.str.get(0)
df['월'] = dates.str.get(1)
df['일'] = dates.str.get(2)
          연월일   당일종가  전일종가     시가     고가     저가     거래량     연   월   일
0  2018-07-02  10100   600  10850  10900  10000  137977  2018  07  02
1  2018-06-29  10700   300  10550  10900   9990  170253  2018  06  29
2  2018-06-28  10400   500  10900  10950  10150  155769  2018  06  28
3  2018-06-27  10900   100  10800  11050  10500  133548  2018  06  27
4  2018-06-26  10800   350  10900  11000  10700   63039  2018  06  26

 
 
 
 

4. 필터링

- 조건에 맞는 데이터만 추출

titanic = sns.load_dataset('titanic')

 
# age가 10 ~ 19인 데이터만 추출

ages = titanic[(titanic['age'] >= 10) & (titanic['age'] <20)]
ages['age'].unique()
array([14. , 15. , 19. , 18. , 11. , 17. , 16. , 14.5, 12. , 10. , 13. ])

 
# age가 10세 미만이고 sex가 female인 데이터 중에서 age,sex,alone 컬럼만 추출  loc[ [ ] ]

condition = (titanic['age']<10) & (titanic['sex']== 'female')
result = titanic.loc[condition, ['age','sex','alone']]
     age     sex  alone
10   4.0  female  False
24   8.0  female  False
43   3.0  female  False
58   5.0  female  False
119  2.0  female  False

 
# sibsp가 3, 4, 5인 데이터 추출  isin()

#sibsp가 3, 4, 5인 데이터 추출
조건 = (titanic['sibsp'].isin([3, 4, 5]))
결과 = titanic.loc[조건, :]
print(결과['sibsp'].unique())
[3 4 5]

 
 
 
 

5. 데이터 결합

- 데이터가 분할된 경우 합치는 기능
-  join처럼 키를 가지고 옆으로 결합하거나, 동일한 컬럼이면 세로로 결합
 

1) concat

- 구성 형태와 속성이 동일하면 행 또는 열 방향으로 이어붙임
- Series끼리는 옆으로 합쳐 DataFrame 생성
- DataFrame끼리는 상하로 합쳐서 하나의 DataFrame으로 생성

  • 한쪽에만 존재하는 컬럼도 합쳐짐, 값은 Nan

- axis=1을 설정하면 옆으로 결합

  • 이 경우에는 join 옵션 사용
  • 기본은 outer,  inner 설정 가능
df1 = pd.DataFrame({'a': ['a0', 'a1', 'a2', 'a3'],
                    'b': ['b0', 'b1', 'b2', 'b3'],
                    'c': ['c0', 'c1', 'c2', 'c3']},
                    index=[0, 1, 2, 3])
 
df2 = pd.DataFrame({'a': ['a2', 'a3', 'a4', 'a5'],
                    'b': ['b2', 'b3', 'b4', 'b5'],
                    'c': ['c2', 'c3', 'c4', 'c5'],
                    'd': ['d2', 'd3', 'd4', 'd5']},
                    index=[2, 3, 4, 5])

 
#세로 결합

print(pd.concat([df1, df2]))
    a   b   c    d
0  a0  b0  c0  NaN
1  a1  b1  c1  NaN
2  a2  b2  c2  NaN
3  a3  b3  c3  NaN
2  a2  b2  c2   d2
3  a3  b3  c3   d3
4  a4  b4  c4   d4
5  a5  b5  c5   d5
  • concat 옵션이 없는 경우: Set 연산처럼 세로 방향으로 결합
  • 컬럼의 이름이 다른 경우는 NaN 값으로 컬럼을 생성해서 결합

#가로 결합

print(pd.concat([df1, df2], axis=1))
       a       b      c       a        b      d
0   a0      b0   c0      NaN  NaN  NaN
1   a1      b2   c2      NaN  NaN  NaN
2   a2      b2   c2       a4     b4     b4
3   a3      b3   c3       a5     b5     b5
4  NaN  NaN  NaN   a6     a6    a6
5  NaN  NaN  NaN   a7     a7     a7
  • 기본적으로 index를 기준으로 결합
  • Outer Join처럼 수행

# inner join

print(pd.concat([df1, df2], axis=1, join='inner'))
      a   b     c    a    b   d
2  a2  b2  c2  a4  b4  b4
3  a3  b3  c3  a5  b5  b5

 
 

2) append

python에서 append가 _append(프라이빗)으로 변경됐음

- 인덱스와 상관없이 컬럼 이름만으로 상하 결합
- 최신 버전에서 API 변경
 
 

3) combine_first

- 두 데이터 셋의 인덱스가 겹치는 경우 데이터 정렬 기능까지 제공

print(df1.combine_first(df2))
     a    b     c       d
0  a0  b0   c0    NaN
1  a1  b2   c2    NaN
2  a2  b2   c2     b4
3  a3  b3   c3     b5
4  a6  a6  NaN   a6
5  a7  a7  NaN   a7

 
 

4) merge

- 2개의 데이터프레임을 합치는 메소드
- 데이터프레임만 설정하면 동일한 이름의 컬럼을 가지고 JOIN 수행
- key 옵션: 컬럼 설정 가능
- left_on right_on 옵션: 컬럼의 이름이 다른 경우, 직접 컬럼 이름 설정
- how 옵션: inner, left, right, outer 설정으로 outer join 수행
- suffixes 옵션: 튜플로 2개의 문자열을 설정하면 동일한 이름이 있는 경우 _이름 추가

  • 생략하면 _x, _y

- sort 옵션: 기본적으로 key를 기준으로 정렬 수행. 정렬 하지 않으려면 sort  = False
 
 

5) join

- merge와 유사
-  기본적으로 행 인덱스를 키 사용
- 키 설정이 가능하고 how 옵션 존재
- merge는 pandas 함수, join은 DataFrame의 메소드

price = pd.read_excel('./data/stock price.xlsx')
valuation = pd.read_excel('./data/stock valuation.xlsx')

 
#기본 조인

  • 아무런 옵션이 없으면 동일한 컬럼으로 Join
  • 기본적으로 Inner Join 수행
print(pd.merge(price, valuation))
print(pd.merge(price, valuation, how='outer', on='id'))

 
# join하는 컬럼의 이름이 다를 때

print(pd.merge(price, valuation, how='right', left_on='stock_name', right_on='name'))
#기본적으로 index로 조인
price.index=price['id']
valuation.index = valuation['id']

#동일한 컬럼 이름 제거
price.drop(['id'], axis=1, inplace=True)
valuation.drop(['id'], axis=1, inplace=True)

print(price.join(valuation))

 
 
 
 
 

6. 그룹연산

1) 그룹화

- 어떤 기준에 따라 그룹별로 나누어서 관찰
- groupby 함수 이용, 컬럼 이름이나 컬럼 이름의 list를 대입해서 그룹화
- 그룹화 후 get_group(그룹이름)을 이용하면 그룹화된 개별 그룹의 데이터를 가져오는 것이 가능
- 그룹화한 데이터는 iteration(for 사용)이 가능

  • 2개의 데이터를 튜플로 리턴
  • (그룹의 이름, 그룹의 데이터)

# titanic 데이터를 class 별로 그룹화

df = titanic[['age', 'sex', 'class', 'fare', 'survived']]
grouped = df.groupby(['class'])
for key, group in grouped:
    print(key, group)

 
# 그룹 count

#count
for key, group in grouped:
    print(key, len(group))
('First',) 216
('Second',) 184
('Third',) 491

 
# 특정 그룹의 데이터 선택

group3 = grouped.get_group('Third')

 
# 2개 열로 그룹화

grouped = df.groupby(['class', 'sex'])
for key, group in grouped:
    print(key)
('First', 'female')
('First', 'male')
('Second', 'female')
('Second', 'male')
('Third', 'female')
('Third', 'male')
  • key 가 2개 항목의 튜프로 생성
group3m = grouped.get_group(('Third', 'male'))

 
 
 

2) 집계

- count(null 제외), size(null 포함), mean, std, min, max,
  quantile(q=0.25|0.5|0.75), sum, var, sem, describe, first, last, nth
 
#표준편차

df = titanic[['class', 'age']]
grouped = df.groupby(['class'])
std_all = grouped.std()
print(std_all)

 
- 사용자 정의 함수 적용: agg 함수 호출해서 넘겨주기

#데이터 모임을 가지고 하나의 값을 리턴하는 함수
def min_max(x):
    return x.max() - x.min()

#사용자정의 함수 집계
result = grouped.agg(min_max)
result

 
- 사용자 정의 함수 적용해서 데이터 변환 : transform 함수 호출

  • map: 하나의 데이터를 받아서 하나의 데이터를 리턴하는 함수 생성해서 데이터 묶음에 적용하면
             하나 하나의 데이터를 함수에 대입해서 호출한 후 결과를 묶어서 데이터의 묶음을 리턴하는 함수

Z-score: (값-평균) / 표준편차

def z_score(x):
    return (x-x.mean()) / x.std()
    
age_zscore = grouped.transform(z_score)
age_zscore
  • 음수는 평균보다 아래
  • 양수는 평균보다 위

 
 

3) 멀티 인덱스

- 인덱스가 1 Level이 아닌 여러 Level로 구성되는 것
- 그룹화를 할 때 하나의 컬럼이 아니라 여러 컬럼으로 하는 경우 멀티 인덱스 생성

df = titanic[['class', 'sex', 'age']]
grouped = df.groupby(['class', 'sex'])

for key in grouped:
    print(key)

...
gdf = grouped.mean()
gdf

 
# 특정 class 출력

gdf.loc['First']

 
# 특정 sex 출력

gdf.xs('male', level='sex')

 
# 특정 행 출력

gdf.loc[('First', 'female')]
age    85
Name: (First, female), dtype: int64

 
 
 

4) pivot table

- 데이터를 그룹화하기 위한 함수

- 멀티 인덱스는 한 방향에 인덱스가 여러 개 적용
- 피벗 테이블은 양 방향에 인덱스를 적용

df = titanic[['class', 'sex', 'age']]
result = pd.pivot_table(df, index='class', columns='sex', values='age',
                       aggfunc='sum')
result

 
 
 
 
 

7. 데이터 구조화

- stacked와 unstacked

  • stacked: 가로 방향으로 넓게 펼쳐진 데이터를 세로 방향으로 길게 만드는 작업 - 컬럼을 인덱스로 활용
  • unstacked: 세로 방향으로 길게 펼쳐진 데이터를 가로 방향으로 넓게 만드는 작업 - 인덱스를 다시 컬럼으로 활용

- stacked 작업을 할 때는 NaN 데이터를 어떻게 처리할 것인지 결정
 

 

1) stack()

- stacked 작업을 수행해주는 함수

mul_index = pd.MultiIndex.from_tuples([('cust_1', '2015'), ('cust_1', '2016'),
                                      ('cust_2', '2015'), ('cust_2', '2015')])

data = pd.DataFrame(data=np.arange(16).reshape(4,4), index=mul_index, 
                   columns=['prd_1', 'prd_2', 'prd_3', 'prd_4'], dtype='int')
print(data)
stacked = data.stack()
cust_1  2015  prd_1     0
              prd_2     1
              prd_3     2
              prd_4     3
        2016  prd_1     4
              prd_2     5
              prd_3     6
              prd_4     7
cust_2  2015  prd_1     8
              prd_2     9
              prd_3    10
              prd_4    11
        2016  prd_1    12
              prd_2    13
              prd_3    14
              prd_4    15
dtype: int32

 
 

2) unstack

- unstacked 작업을 수행해주는 함수

  • 멀티인덱스인 경우 어떤 
#첫 레벨의 인덱스가 컬럼이 됩니다. cust_1 > 2015,6 > prd
unstacked1 = stacked.unstack(level=0)
unstacked2 = stacked.unstack(level=1)

print(unstacked1)
print(unstacked2)

#다단으로 구성된 인덱스의 경우는 여러 번 unstack 가능
print(unstacked2.unstack())
            cust_1  cust_2
2015 prd_1       0       8
     prd_2       1       9
     prd_3       2      10
     prd_4       3      11
2016 prd_1       4      12
     prd_2       5      13
     prd_3       6      14
     prd_4       7      15

              2015  2016
cust_1 prd_1     0     4
       prd_2     1     5
       prd_3     2     6
       prd_4     3     7
cust_2 prd_1     8    12
       prd_2     9    13
       prd_3    10    14
       prd_4    11    15
        2015                    2016      
            
       prd_1 prd_2 prd_3 prd_4 prd_1 prd_2 prd_3 prd_4
cust_1     0     1     2     3     4     5     6     7
cust_2     8     9    10    11    12    13    14    15

 
 

 

 

8. 숫자 데이터 전처리

1) 단위 환산

- 하나의 데이터 셋에서 서로 다른 측정 단위를 사용하게 되면 전체 데이터의 일관성 측면에서 문제가 발생할 수 있기 때문에 측정 단위를 동일하게 맞춰야 함

  • mpg 데이터는 자동차에 대한 연비인데, 미국에서는 갤런당 마일을 사용하고 우리나라에서는 L당 km 사용
  • 이럴 때 단위환산이 편리하다.
  • 1마일은 1.60934 km, 1갤런은 3.7841 L
mpg = pd.read_csv('./data/auto-mpg.csv', header=None)
mpg.columns = ['mpg', 'cylinders', 'displacement', 'horsepower', 'weight', 'acceleration', 'model year', 'origin', 'name']
#갤런 당 마일을 리터 당 킬로미터로 변환하는 상수
mpg_to_kpi = 1.60934 / 3.7841
mpg['kpi'] = mpg['mpg'] * mpg_to_kpi

 
 

2) 자료형 변환

- 컬럼의 자료형은 dtypes 속성이나 info()를 이용해서 가능
- 엑셀 파일이나 csv를 읽다보면 숫자 데이터를 문자열로 읽어오는 경우가 있음

  • 엑셀 파일에서 천 단위 구분 기호가 있는 경우: thousand 옵션에 (,)를 설정해서 읽어오면 해결

- 숫자로 인식할 수 없는 데이터가 포함된 경우

  • 숫자로 인식할 수 없는 데이터를 숫자로 변환하거나 제거한 후 숫자로 변경
mpg.dtypes
mpg                    float64
cylinders             int64
displacement      float64
horsepower        object
weight                float64
acceleration       float64
model year        int64
origin                 int64
name                 object
dtype: object

 
# 숫자로 변환

mpg['horsepower'] = mpg['horsepower'].astype('float')
mpg.dtypes

ValueError: could not convert string to float: '?'
 
# 인식할 수 없는 데이터 확인

mpg['horsepower'].unique()

 
# Null로 치환하여 제거하고 숫자로 변환

#?를 NaN으로 치환
mpg['horsepower'].replace('?', np.nan, inplace=True)

#NaN 제거
mpg.dropna(subset=['horsepower'], inplace=True)

#실수 자료형으로 변경
mpg['horsepower'] = mpg['horsepower'].astype('float')

mpg.dtypes
...
horsepower      float64
...

 
- 자료형을 범주형으로 변경하고자 하면 category로 자료형 설정

  • origin은 국가를 의미하는 범주형 인데 숫자 자료형, Category나 String으로 변경해주는게 좋다.
  • origin의 데이터를 1 -> USA,  2-> EU,  3-> JAPAN으로 치환
  • replace에 dict를 대입하면 key를 찾아서 value로 치환
mpg['origin']
0      1
1      1
2      1
3      1
4      1
mpg['origin'].replace({1:'USA', 2:'EU', 3:'JAPAN'}, inplace=True)
mpg['origin'].unique()
mpg['origin'].head()
array(['USA', 'JAPAN', 'EU'], dtype=object)

0    USA
1    USA
2    USA
3    USA
4    USA
Name: origin, dtype: object

 

- model year 컬럼의 값을 범주형(category)로 치환

  • category: 특정 값만을 가져야 하는 자료형
  • 문자열이나 숫자 자료형은 원핫 인코딩이 안되는 경우가 발생할 수 있음
    • 원핫 인코딩: 범주형의 데이터를 숫자형으로 만들 때 각각의 값을 컬럼으로 만드는 건데 문자열이나 숫자형은 안될 수 있음
mpg['model year'] = mpg['model year'].astype('category')
mpg.info()
 6   model year    392 non-null    category

 

 

 

 

 

 

 

 # 서울시 구별 CCTV와 인구 관계 분석

 

 

[전처리] 서울시 구별 CCTV와 인구 관계 분석

1. 서울시 자치구별 CCTV 현황 데이터 가져오기 - http://data.seoul.go.kr/ 열린데이터광장 메인 데이터분류,데이터검색,데이터활용 data.seoul.go.kr - CCTV 검색 - xlsx 파일을 다운로드(파일 이름을 cctv로 수

yachae4910.tistory.com

 

 

# 지도 출력

 

[전처리] 지도 출력 Choropleth

https://github.com/southkorea/southkorea-maps 한국 지리정보 사이트 1. 데이터 읽어오기 state_unemployment = 'data/US_Unemployment_Oct2012.csv' state_data = pd.read_csv(state_unemployment) print(state_data.head()) State Unemployment 0 AL 7.1

yachae4910.tistory.com

 

 

 

# 서울시 범죄 현황 시각화

 

[전처리] 서울시 범죄 현황 시각화

- https://data.seoul.go.kr/ - 서울시 5대 점죄 발생현황 통계 데이터 - crime.txt 1. 데이터 가져오기 import pandas as pd import folium import json criminal = pd.read_csv('./data/crime.txt', sep='\t', thousands=',', encoding='utf-8') 2.

yachae4910.tistory.com

 

 

 

# Cartogram

 

 

[전처리] 인구 소멸 지역 Cartogram

- 국가 통계 포털에서 인구 정보 내려받기 http://kosis.kr/statHtml/statHtml.do?orgId=101&tblId=DT_1IN1509& KOSIS kosis.kr 기본코드 import pandas as pd import numpy as np import platform import matplotlib.pyplot as plt %matplotlib inline p

yachae4910.tistory.com

 

'Python' 카테고리의 다른 글

[Python] 확률  (0) 2024.02.21
[Python] 데이터 스케일링  (1) 2024.02.16
[Python] 데이터 시각화  (0) 2024.02.14
[Python] 데이터 탐색  (0) 2024.02.14
[Python] MySQL 데이터로 DataFrame 만들기  (0) 2024.02.14

[Python] 데이터 시각화

0ㅑ채
|2024. 2. 14. 16:24

1. 데이터 시각화 - matplotlib

1) 앤스콤 데이터

- 이 데이터는 4개의 데이터 그룹으로 구성

- 앤스콤 데이터 가져오기

#앤스콤 데이터 가져오기
import seaborn as sns
anscombe = sns.load_dataset("anscombe")
print(anscombe.head())
print(anscombe['dataset'].unique())
  dataset     x     y
0       I     10.0  8.04
1       I      8.0  6.95
2       I     13.0  7.58
3       I      9.0  8.81
4       I     11.0  8.33

['I' 'II' 'III' 'IV']

 

# 데이터셋 분리

#dataset 별로 분리
dataset_1 = anscombe[anscombe['dataset'] == 'I']
dataset_2 = anscombe[anscombe['dataset'] == 'II']
dataset_3 = anscombe[anscombe['dataset'] == 'III']
dataset_4 = anscombe[anscombe['dataset'] == 'IV']

print(dataset_1)

 

   dataset     x      y
0        I  10.0   8.04
1        I   8.0   6.95
2        I  13.0   7.58
3        I   9.0   8.81
4        I  11.0   8.33
5        I  14.0   9.96
6        I   6.0   7.24
7        I   4.0   4.26
8        I  12.0  10.84
9        I   7.0   4.82
10       I   5.0   5.68
  • 데이터셋 네개의 평균, 표준편차를 구해보면 모두 같다.
  • 상관계수도 큰 차이가 없다.
  • 그렇다고 해서 데이터들의 특성이 비슷할 것이라 판단하면 안됨!

 

# 앤스콤 데이터 각 세트 시각화

## 데이터 시각화
import matplotlib.pyplot as plt
fig = plt.figure()

axes1 = fig.add_subplot(2, 2, 1)
axes2 = fig.add_subplot(2, 2, 2)
axes3 = fig.add_subplot(2, 2, 3)
axes4 = fig.add_subplot(2, 2, 4)

axes1.plot(dataset_1['x'], dataset_1['y'], 'o')
axes2.plot(dataset_2['x'], dataset_2['y'], 'o')
axes3.plot(dataset_3['x'], dataset_3['y'], 'o')
axes4.plot(dataset_4['x'], dataset_4['y'], 'o')

axes1.set_title("dataset_1")
axes2.set_title("dataset_2")
axes3.set_title("dataset_3")
axes4.set_title("dataset_4")

  • axes4는 상관계수가 전혀 보이지 않는데
  • 이상치 하나가 평균이나 상관계수에 영향을 많이 준 것이다.

 

2) 자주 사용되는 시각화 라이브러리

- matplotlib: 가장 기본이 되는 라이브러리

- seaborn

- plotnine

- polt.ly

- pyecharts

- folium: 지도 시각화

 

 

3) matplotlib

- 시각화(그래프, 이미지)에 가장 많이 이용하는 라이브러리

- 파이썬의 대다수 시각화 기능

- 설치 필요

* 아나콘다는 내장

 

# 엑셀 파일 읽기

df = pd.read_excel('./data/시도_별_이동자수.xlsx', header=0)
df.head()

 

# 엑셀에서 셀 병합이 있으면 천번째를 제외하고는 NaN으로 처리

df = df.fillna(method="ffill")
df.head()

 

# 조건에 맞는 데이터 필터링

#전출지별 : 서울특별시
#전입지별 : 서욱특별시가 아닌 데이터
mask = (df['전출지별'] == '서울특별시') & (df['전입지별'] != '서울특별시')
df_seoul = df[mask]
df_seoul

 

# 컬럼 삭제

df_seoul = df_seoul.drop(['전출지별'], axis=1, inplace=True)

 

# 컬럼 이름변경

df_seoul.rename({'전입지별':'전입지'}, axis=1, inplace=True)

 

# 인덱스 설정

df_seoul.set_index('전입지', inplace=True)

 

 

4) 라인그래프 그리기

# 인덱스가 전라남도인 데이터 추출
sr_one = df_seoul.loc['전라남도']
sr_one

import matplotlib.pyplot as plt
plt.plot(sr_one.index, sr_one.values)
plt.show()
1970    10513
1971    16755
1972    20157
1973    22160

....

 

- matplotlib을 사용했을 때의 문제점

  • 한글이나 음수는 제대로 출력되지 않음

 

한글 처리

import matplotlib.pyplot as plt
#그래프 크기 설정 - 단위는 inch
plt.figure(figsize=(14, 5))
#x축 눈금 라벨 회전
plt.xticks(size=10, rotation='vertical')
plt.title('seoul->전라남도', size=20)
plt.plot(sr_one.index, sr_one.values)
plt.show()

 

from matplotlib import font_manager, rc
import platform

font_name = font_manager.FontProperties(fname="c:/Windows/Fonts/malgun.ttf").get_name()
rc('font', family=font_name)

 

#라인 그래프 출력
plt.plot(sr_one.index, sr_one.values, marker='o', markersize=5)

#축 제목
plt.xlabel('기간', size=20)
plt.ylabel('이동 인구수', size=20)

#범례
plt.legend(labels=['서울 -> 전라남도'], loc='best', fontsize=15)

plt.show()

5) 막대그래프 그리기

#그래프 크기 설정 - 단위는 inch
plt.figure(figsize=(14, 5))

# 제목 설정
plt.title('서울->전라남도', size=20)

# x축 눈금 라벨 회전
plt.xticks(size=10, rotation='vertical')

#막대 그래프
plt.bar(sr_one.index, sr_one, width =1.0)

plt.show()

 

6) 빈도수 그래프 (히스토그램)

df = pd.read_csv('./data/lovefruits.csv', encoding='cp949')
df
  • 웹사이트는 euk-kr
  • 파일은 cp949
data = df['선호과일'].value_counts(sort=False)
data
선호과일
사과      4
바나나     3
포도      5
복숭아    11
체리      8
Name: count, dtype: int64

 

막대그래프로 그리기 - 직접 빈도수 구해야 함

data = df['선호과일'].value_counts(sort=False)
plt.bar(range(0, len(data), 1), data)
plt.xticks(range(0, len(data), 1), data.index)

plt.show()

히스토그램 - 알아서 빈도수 구해줌

plt.hist(df['선호과일'])
plt.show()

 

 

7) 산포도(scatter)

- 데이터 분포나 상관관계를 파악하기 위한 그래프

- x와 y 옵션에 데이터를 설정

- s 옵션: 사이즈를 설정해서 크기로 다른데이터를 반영하는 것이 가능

mpg = pd.read_csv('./data/auto-mpg.csv', header=None)
mpg.columns = ['mpg', 'cylinders', 'displacement', 'horsepower', 'weight', 'acceleration', 'model year', 'origin', 'name']
plt.scatter(x=mpg['weight'], y=mpg['mpg'])
plt.show()

size = mpg['cylinders'] / mpg['cylinders'].max() * 200
plt.scatter(x=mpg['weight'], y=mpg['mpg'], s=size, c='coral', alpha=0.5)
plt.show()

 

 

8) pie 

- 기여도를 나타냄

 

9) box plot

- 데이터의 범위를 표현

 

10) fill_between

- 데이터 크기를 영역으로 나타내는 그래프 

 

 

 

2. Seaborn

- matplotlob 기반으로 다양한 색상 테마와 통계용 차트의 기능을 추가한 패키지

- numpy와 pandas의 자료구조 지원

- 샘플데이터 

  • 내장되어 있음
  • load_dataset 메소드로 호출, DataFrame으로 리턴
#회귀에서 사용하는 데이터 셋 가져오기
import seaborn as sns
tips = sns.load_dataset("tips")
print(tips.head())

 

1) 산점도와 회귀식을 출력

  • regplot(), implot() 이용
  • 산점도와 회귀선 같이 출력
  • 회귀선 출력하지 않으려면 fit_reg 옵션 설정을 수정
  • data에 데이터프레임을 설정하고 x와 y에 컬럼 이름 설정
plt.figure(figsize=(8,6)) #캔버스 크기 설정
sns.regplot(x="total_bill", y="tip", data=tips)
plt.show()

 

# 회귀선 두개 옵션

plt.figure(figsize=(8,6)) #캔버스 크기 설정
sns.lmplot(x="total_bill", y="tip", hue = 'smoker', data=tips)
plt.show()

 

2) heatmap

- 기간별 추세를 알아보고자 할 때 사용

- 가로와 세로 모두 기간을 설정하고 색상을 이용해서 크기 설정

- 라인 그래프는 일반적으로 가로 방향에만 기간 설정

- 히트맵을 출력할 때는 범례나 레이블을 출력해줘야 값의 변화를 파악하기 쉽다. 

flights = sns.load_dataset("flights")
print(flights)
     year month  passengers
0    1949   Jan         112
1    1949   Feb         118
2    1949   Mar         132
3    1949   Apr         129
4    1949   May         121
..    ...   ...         ...
print(flights.pivot(columns=("month", "year", "passengers")))
Empty DataFrame
Columns: []
Index: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...]

[144 rows x 0 columns]
data = flights.pivot(index="month", columns="year", values="passengers")
print(data)
year   1949  1950  1951  1952  1953  1954  1955  1956  1957  1958  1959  1960
month                                                                        
Jan     112   115   145   171   196   204   242   284   315   340   360   417
Feb     118   126   150   180   196   188   233   277   301   318   342   391
Mar     132   141   178   193   236   235   267   317   356   362   406   419
Apr     129   135   163   181   235   227   269   313   348   348   396   461
May     121   125   172   183   229   234   270   318   355   363   420   472
Jun     135   149   178   218   243   264   315   374   422   435   472   535
Jul     148   170   199   230   264   302   364   413   465   491   548   622
Aug     148   170   199   242   272   293   347   405   467   505   559   606
Sep     136   158   184   209   237   259   312   355   404   404   463   508
Oct     119   133   162   191   211   229   274   306   347   359   407   461
Nov     104   114   146   172   180   203   237   271   305   310   362   390
Dec     118   140   166   194   201   229   278   306   336   337   405   432
sns.heatmap(data, annot=True, fmt='d')
기본  annot = True fmt = 'd'

 

 

3) 데이터 분포를 출력해주는 다양한 그래프

- boxplot: 4분위수와 IQR * 1.5배 되는 데이터의 위치 및 그 이외의 데이터 분포 확인

* IQR: (3/4-1/4)

 

- violinplot: 4분위 수 대신에 두께를 이용해서 데이터의 밀집 형태 판단할 수 있음

 

- stripplot: 두께가 아니라 점으로 데이터의 밀집 형태 표시 (점이 겹침)

 

- swarmplot: 두께가 아니라 점으로 데이터의 밀집 형태 표시 (점이 겹치지 않음)

 

- box plot과 swarmplot을 같이 추력하면 데이터의 밀집 형태 확인 가능

 

- pairplot: 데이터프레임의 컬럼이 숫자로만 된 경우 2개씩 조합해서 모든 경우의 조합의 산포도 출력

 

# boxplot

tips = sns.load_dataset('tips')
sns.boxplot(x='day', y='total_bill', data=tips)
plt.show()

 

# violinplot

sns.violinplot(x='day', y='total_bill', data=tips)
plt.show()

  • 데이터의 밀집 형태를 두께감으로 표시

# stripplot

sns.stripplot(x='day', y='total_bill', hue='smoker', data=tips)
plt.show()

# swarmplot

sns.swarmplot(x='day', y='total_bill', data=tips)
plt.show()

# box plot과 swarmplot을 같이

sns.boxplot(x='day', y='total_bill', data=tips)
sns.swarmplot(x='day', y='total_bill', data=tips)
plt.show()

# pariplot

sns.pairplot(tips)
plt.show()

  • tip과 total_bill만 상관관계
sns.pairplot(tips[['total_bill', 'tip', 'size']])
plt.show()
  • 숫자 데이터만 넣어주는게 바람직

 

 

3. Plotnine

- R의 ggplot2에 기반해서 그래프를 그려주는 라이브러리

- 기본 패키지가 아니라서 설치 필요

- 도큐먼트: https://plotnine.readthedocs.io/en/stable 

- 파이썬을 매개변수를 설정할 때 쉼표(,)로 구분하는데, R은 +로 결합 가능

import plotnine
df = pd.DataFrame({
    'letter':["Alpha", 'Beta', 'Delta', 'Gamma'] * 2,
    'pos':[1, 2, 3, 4] * 2,
    'num_of_letters': [5, 4, 5, 5] * 2
})

(plotnine.ggplot(df)
+ plotnine.geom_col(plotnine.aes(x='letter', y='pos', fill='letter')) 
+ plotnine.geom_line(plotnine.aes(x='letter', y='num_of_letters', color='letter'), size=1) 
+ plotnine.scale_color_hue(I=0.45)
+ plotnine.ggtitle('Greek Letter Analysis')
)

 

 

4. plotly

- 인터럭티브한 그래프를 그려주는 라이브러리

- https://plotly.com/python 

- D3.js 라이브러리 활용

  • 자바스크립트로 차트를 html에 표현하는 라이브러리
  • 웹상에서 동적인 차트 가능

- 설치: chart_studio 라이브러리도 함께 설치

 

 

5. folium

- 지도를 그려주는 라이브러리

- 자바스크립트 기반으로 인터럭티브한 그래프

- 설치 필요

- Map() 함수를 이용해서 지도 객체를 생성

  • locations 옵션에 중앙점의 위도와 경도 설정하고 zoom_start 옵션에 초기 확대 축소 배율 설정

- Chrome 브라우저를 사용하는 Jupyter Notebook에서는 바로 출력이 가능, 그 이외의 경우에는 html로 저장해서 확인

- 단계 구분도 생성 가능

import folium

m = folium.Map(location = [37.572656, 126.973300], zoom_start=15)
m

 

지도 위에 마커 표시

folium.Marker(location=[위도, 경도], popup='보여지는 문자열', icon=이미지모양).add_to(맵객체)
folium.Marker(location=[37.572656, 126.973300], popup='여기예요', icon=folium.Icon(color='red')).add_to(m)
m

 

 

 

 

 

 

 

'Python' 카테고리의 다른 글

[Python] 데이터 스케일링  (1) 2024.02.16
[Python] 데이터 전처리  (0) 2024.02.15
[Python] 데이터 탐색  (0) 2024.02.14
[Python] MySQL 데이터로 DataFrame 만들기  (0) 2024.02.14
[Python] 크롤링 - Selenium  (0) 2024.02.14

[Python] 데이터 탐색

0ㅑ채
|2024. 2. 14. 16:24

1. 데이터프레임에서의 데이터 선택

1) 열 선택

- 데이터프레임['컬럼이름'] 또는 데이터프레임.컬럼이름 

  • 데이터프레임.컬럼이름 으로 접근할 때는 컬럼이름이 반드시 문자열이어야 함

- 하나의 컬럼이름을 이용해서 접근하면 Series로 리턴

 

2) 행 선택

- loc[인덱스이름] 

- iloc[정수형 위치 인덱스] 

- Series로 리턴

 

3) 셀 선택

- [컬럼이름][인덱스이름]

- loc[인덱스이름, 컬럼이름]

- iloc[행 위치 인덱스, 열 위치 인덱스]

 

4) 다중 선택

- list를 이용해서 선택

  • DataFrame이 리턴
#item.csv 파일을 읽어서 DataFrame 만들기
#csv를 읽을 때 확인할 3가지
#한글 포함 여부 - 인코딩
# 구분자는 , 인지
#첫번째 줄이 컬럼이름인지 아니면 데이터인지
#컬럼 중에 primary key의 역할을 할 수 있는게 있는지

item = pd.read_csv('./data/item.csv')
print(item.head())
item.info()
   code  manufacture            name  price
0     1        korea           apple   1500
1     2        korea      watermelon  15000
2     3        korea  oriental melon   1000
3     4  philippines          banana    500
4     5        korea           lemon   1500

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 6 entries, 0 to 5
Data columns (total 4 columns):
 #   Column       Non-Null Count  Dtype 
---  ------       --------------  ----- 
 0   code         6 non-null      int64 
 1   manufacture  6 non-null      object
 2   name         6 non-null      object
 3   price        6 non-null      int64 
dtypes: int64(2), object(2)
memory usage: 324.0+ bytes

 

#현재 사용 중인 컬럼을 인덱스로 활용

item.index = item['code']
item.index = ['사과', '수박', '참외', '바나나', '레몬', '망고']
print(item)
     code  manufacture            name  price
사과      1        korea           apple   1500
수박      2        korea      watermelon  15000
참외      3        korea  oriental melon   1000
바나나     4  philippines          banana    500
레몬      5        korea           lemon   1500
망고      6        korea           mango    700

 

#열 하나 선택

print(item['name']) 
print(item.price)

print(item[['name']])

#type
print(type(item['name']))
print(type(item[['name']]))
사과              apple
수박         watermelon
참외     oriental melon
바나나            banana
레몬              lemon
망고              mango
Name: name, dtype: object
사과      1500
수박     15000
참외      1000
바나나      500
레몬      1500
망고       700
Name: price, dtype: int64
               name
사과            apple
수박       watermelon
참외   oriental melon
바나나          banana
레몬            lemon
망고            mango
<class 'pandas.core.series.Series'>
<class 'pandas.core.frame.DataFrame'>

 

#여러 열 선택

print(item[['name', 'price']])
               name  price
사과            apple   1500
수박       watermelon  15000
참외   oriental melon   1000
바나나          banana    500
레몬            lemon   1500
망고            mango    700

 

#행선택

print(item.iloc[0]) #0번째 행
print(item.loc['apple']) #사과라는 인덱스를 가진 행
code               1
manufacture    korea
name           apple
price           1500
Name: 사과, dtype: object

 

#셀선택

print(item['name'][2]) #name 컬럼의 3번째 데이터
oriental melon

 

 

5) 범위를 이용한 행 인덱싱

[시작위치 : 종료위치 : 간격] 

print(item.iloc[1:4]) #위치 인덱스에서는 마지막 위치가 포함되지 않음
print(item.loc["수박":"바나나"]) #이름 인덱스 에서는 마지막 위치가 포함됨
     code  manufacture            name  price
수박      2        korea      watermelon  15000
참외      3        korea  oriental melon   1000
바나나     4  philippines          banana    500
     code  manufacture            name  price
수박      2        korea      watermelon  15000
참외      3        korea  oriental melon   1000
바나나     4  philippines          banana    500

 

6) Boolean 인덱싱

- bool 타입의 Seriest를 대입하면 True 인 행 만 선택

- Series객체 비교연산자 값 이용하면 bool 타입의 Series를 리턴

  • item['price'] > 3000: price 가 3000 이하이면 False 3000 초과면 True를 리턴

- & 와 | 를 이용한 결합도 가능

#price가 1500 미만인 행만 추출
print(item[item['price'] < 1500])

#price가 1000 ~ 1500 인 데이터만 추출
print(item[(item['price']>=1000) & (item['price'] <= 1500)])
     code  manufacture            name  price
참외      3        korea  oriental melon   1000
바나나     4  philippines          banana    500
망고      6        korea           mango    700
    code manufacture            name  price
사과     1       korea           apple   1500
참외     3       korea  oriental melon   1000
레몬     5       korea           lemon   1500

 

- isin([데이터 나열]): 데이터 안에 속하면 True 그렇지 않으면 False를 리턴

#price 가 1000 또는 500 인 데이터 추출
print(item[item['price'].isin([1000, 500])])
     code  manufacture            name  price
참외      3        korea  oriental melon   1000
바나나     4  philippines          banana    500

 

 

 

2. 내용 확인

1) head 와 tail

- DataFrame의 데이터 중에서 앞 이나 뒤에서 몇 개의 데이터를 확인하고자 할 때 사용

 

2) shape

- 행과 열의 개수를 tuple 형식으로 리턴

 

3) info()

- DataFrame의 기본 정보를 리턴하는 함수

  • 데이터 유형
  • 행 인덱스의 구성
  • 열 이름
  • 각 열의 자료형 과 데이터 개수
  • 메모리 사용량

 

4) dtypes

- 각 열의 자료형 정보를 리턴

 

5) count()

- 데이터의 개수

 

6) value_counts()

- Series에서만 사용이 가능한데 고유한 값의 종류 와 개수 정보

 

7) describe()

- 기술 통계 정보를 출력

- 옵션이 없으면 숫자 데이터의 평균, 표준 편차, 최대값, 최소값, 중간값

- include='all' 옵션으로 추가하면 숫자 데이터가 아닌 열의 unique, top, freq 를 출력

 

8) auto-mpg.csv 파일의 데이터 확인

- 자동차 연비 와 관련된 데이터 셋으로 회귀에 사용

- 컬럼

  • mpg: 연비
  • cylinders: 실린더 개수
  • displacement: 배기량
  • horsepower: 출력
  • weight: 중량
  • acceleration: 가속 능력
  • model_year: 출시 년도
  • origin: 제조국
  • name: 모델명

- 데이터 확인

#헤더가 없어서 컬럼 이름을 직접 설정
df = pd.read_csv('./data/auto-mpg.csv', header=None)
df.columns = ['mpg', 'cylinders', 'displacement', 'horsepower', 'weight', 'acceleration', 'model year', 'origin', 'name']
#처음 5개의 데이터만 확인
print(df.head())
    mpg  cylinders  displacement horsepower  weight  acceleration  model year  \
0  18.0          8         307.0      130.0  3504.0          12.0          70   
1  15.0          8         350.0      165.0  3693.0          11.5          70   
2  18.0          8         318.0      150.0  3436.0          11.0          70   
3  16.0          8         304.0      150.0  3433.0          12.0          70   
4  17.0          8         302.0      140.0  3449.0          10.5          70   

   origin                       name  
0       1  chevrolet chevelle malibu  
1       1          buick skylark 320  
2       1         plymouth satellite  
3       1              amc rebel sst  
4       1                ford torino  
#행 과 열의 수 확인
print(df.shape)
#자료형 확인
print(df.dtypes)
#데이터 개수
print(df.count())
(398, 9)

mpg             float64
cylinders         int64
displacement    float64
horsepower       object
weight          float64
acceleration    float64
model year        int64
origin            int64
name             object
dtype: object

mpg             398
cylinders       398
displacement    398
horsepower      398
weight          398
acceleration    398
model year      398
origin          398
name            398
dtype: int64
#앞의 3가지 정보를 전부 확인 가능하고 null(None)도 확인 가능
df.info()

#기술 통계 확인 - 숫자 데이터의 기술 통계
print(df.describe())

#기술 통계 확인 - 모든 데이터의 기술 통계
print(df.describe(include='all'))
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 398 entries, 0 to 397
Data columns (total 9 columns):
 #   Column        Non-Null Count  Dtype  
---  ------        --------------  -----  
 0   mpg           398 non-null    float64
 1   cylinders     398 non-null    int64  
 2   displacement  398 non-null    float64
 3   horsepower    398 non-null    object 
 4   weight        398 non-null    float64
 5   acceleration  398 non-null    float64
 6   model year    398 non-null    int64  
 7   origin        398 non-null    int64  
 8   name          398 non-null    object 
dtypes: float64(4), int64(3), object(2)
memory usage: 28.1+ KB

              mpg   cylinders  displacement       weight  acceleration  \
count  398.000000  398.000000    398.000000   398.000000    398.000000   
mean    23.514573    5.454774    193.425879  2970.424623     15.568090   
std      7.815984    1.701004    104.269838   846.841774      2.757689   
min      9.000000    3.000000     68.000000  1613.000000      8.000000   
25%     17.500000    4.000000    104.250000  2223.750000     13.825000   
50%     23.000000    4.000000    148.500000  2803.500000     15.500000   
75%     29.000000    8.000000    262.000000  3608.000000     17.175000   
max     46.600000    8.000000    455.000000  5140.000000     24.800000   

       model year      origin  
count  398.000000  398.000000  
mean    76.010050    1.572864  
std      3.697627    0.802055  
min     70.000000    1.000000  
25%     73.000000    1.000000  
50%     76.000000    1.000000  
75%     79.000000    2.000000  
max     82.000000    3.000000  

               mpg   cylinders  displacement horsepower       weight  \
count   398.000000  398.000000    398.000000        398   398.000000   
unique         NaN         NaN           NaN         94          NaN   
top            NaN         NaN           NaN      150.0          NaN   
freq           NaN         NaN           NaN         22          NaN   
mean     23.514573    5.454774    193.425879        NaN  2970.424623   
std       7.815984    1.701004    104.269838        NaN   846.841774   
min       9.000000    3.000000     68.000000        NaN  1613.000000   
25%      17.500000    4.000000    104.250000        NaN  2223.750000   
50%      23.000000    4.000000    148.500000        NaN  2803.500000   
75%      29.000000    8.000000    262.000000        NaN  3608.000000   
max      46.600000    8.000000    455.000000        NaN  5140.000000   

        acceleration  model year      origin        name  
count     398.000000  398.000000  398.000000         398  
unique           NaN         NaN         NaN         305  
top              NaN         NaN         NaN  ford pinto  
freq             NaN         NaN         NaN           6  
mean       15.568090   76.010050    1.572864         NaN  
std         2.757689    3.697627    0.802055         NaN  
min         8.000000   70.000000    1.000000         NaN  
25%        13.825000   73.000000    1.000000         NaN  
50%        15.500000   76.000000    1.000000         NaN  
75%        17.175000   79.000000    2.000000         NaN  
max        24.800000   82.000000    3.000000         NaN

 

 

 

3. DataFrame 이름변경

1) rename()

- 인덱스나 컬럼의 이름을 변경하고자할 때 사용

- index: 딕셔너리 형태로 {기존 인덱스 : 새로운 인덱스, ...} 설정

  • index 변경은 메소드를 이용 X
  • list나 Series 형태로 설정 가능

- Columns: 딕셔너리 형태로 {기존 컬럼 이름 : 새로운 컬럼 이름, ...} 설정하면 컬럼 이름 변경

- inplace: 이 옵션의 기본값은 False 인데 False 가 설정되면 복제본을 만들어서 리턴하고 True를 설정하면 원본이 변경

- rename: 함수는 첫번째 매개변수로 변환 함수를 대입하고 두번째 옵션에 axis 에 index 나 columns를 설정해서 변환 함수를 이용해서 변경하는 것도 가능

 

# 컬럼 이름 변경

import pandas as pd
item = pd.read_csv('./data/item.csv')

item.rename(columns={"code":"코드", "manufacture":"원산지", "name":"이름", "price":"가격"})

 

 

  • 만약에 아래와 같이 한다면 아무 일도 일어나지 않는다.
names = {"code":"코드", "manufacture":"원산지", "name":"이름", "price":"가격"}
item.rename(columns=names)

#아무 일도 일어나지 않는다
#numpy나 pandas의 대다수 메소드는 원본을 변경하지 않고 수정해서 리턴
  • 원본을 수정할 때 inplace 옵션 사용
item.rename(columns=names, inplace=True)
#inplace 옵션이 있는지 확인하고 True로 해주면 원본을 수정

 

 

2) 인덱스의 재구성

- 인덱스

  • 행을 구별하기 위한 이름
  • 의미있는 이름을 인덱스로 설정
    • 관계형 데이터베이스에서 기본키처럼 데이터 식별이 가능한 값
  • 기본값은 0부터 일련번호
  • index: 데이터 프레임 생성하면서 인덱스 지정 
  • reindex: index를 재배치, 추가, 삭제 가능
  • set_index(열이름 or 열이름 나열): 컬럼을 인덱스로 사용하는 것이 가능, 컬럼 중에서는 제거
  • reset_index(): 기본 인덱스 제거, 0부터 시작하는 일련번호 다시 부여. 피봇 형태에서 많이 사용

 

index 옵션 활용

# item에서 '코드'를 가져와서 인덱스로 설정, 컬럼으로 존재
item.index = item.코드
print(item)
    코드          원산지              이름     가격
코드                                        
1    1        korea           apple   1500
2    2        korea      watermelon  15000
3    3        korea  oriental melon   1000
4    4  philippines          banana    500
5    5        korea           lemon   1500
6    6        korea           mango    700

 

set_index 옵션 활용

#컬럼에서 제거되고 index로 설정
item.set_index("코드")
print(item.set_index("코드"))
            원산지              이름     가격
코드                                    
1         korea           apple   1500
2         korea      watermelon  15000
3         korea  oriental melon   1000
4   philippines          banana    500
5         korea           lemon   1500
6         korea           mango    700

 

reset_index 옵션 활용

item = item.reset_index()
print(item)
   코드          원산지              이름     가격
0   1        korea           apple   1500
1   2        korea      watermelon  15000
2   3        korea  oriental melon   1000
3   4  philippines          banana    500
4   5        korea           lemon   1500
5   6        korea           mango    700

 

 

 

2. 데이터 삭제

1) drop 

- 행이나 열을 삭제

- 인덱스나 컬럼 이름을 하나 또는 list 형태로 대입

  • axis=0  : 행 제거
  • axis=1  : 열 제거

- inplace 옵션 존재  추천 X

#2행 삭제
print(item.drop([1], axis=0))

#code 열 삭제
print(item.drop(['code'], axis=1))

 

2) del

- 컬럼 제거 del DataFrame이름['컬럼이름']   추천 X

  • 다른 변수에 수정한 값을 넣으면, 원본을 보존할 수 있음

 

 

3. 데이터 수정 및 추가

- 컬럼 이름이나 인덱스는 유일무이

- DataFrame은 dict처럼 동작

DataFrame[컬럼이름] = 데이터
  • 데이터를 대입할 때 하나의 값이나 Vector 데이터 (list, ndarray, Series, dict) 사용

- 행 수정 및 추가

DataFrame.loc[인덱스이름] = 데이터
  • 인덱스 이름이 존재하지 않으면 추가, 인덱스 이름이 존재하면 수정!

# 하나의 값을 설정하면 모든 행 값이 동일한 값으로 대입

item['description'] = '과일'
print(item)
   code  manufacture            name  price description
0     1        korea           apple   1500          과일
1     2        korea      watermelon  15000          과일
2     3        korea  oriental melon   1000          과일
3     4  philippines          banana    500          과일
4     5        korea           lemon   1500          과일
5     6        korea           mango    700          과일

 

# dict를 이용하면 key와 index가 일치할 때 값을 대입

item['description'] = ['사과', '수박', '참외', '바나나', '레몬', '망고']
print(item)
   code  manufacture            name  price description
0     1        korea           apple   1500          사과
1     2        korea      watermelon  15000          수박
2     3        korea  oriental melon   1000          참외
3     4  philippines          banana    500          바나나
4     5        korea           lemon   1500         레몬
5     6        korea           mango    700          망고

 

# 컬럼 수정 - Series나 dict는 인덱스나 키 이름대로 대입

item['description'] = {0:'사과', 1:'수박', 2:'딸기', 5:'포도', 4:'바나나', 3:'망고'}
print(item)
   code  manufacture            name  price description
0     1        korea           apple   1500          사과
1     2        korea      watermelon  15000          수박
2     3        korea  oriental melon   1000          딸기
3     4  philippines          banana    500          망고
4     5        korea           lemon   1500         바나나
5     6        korea           mango    700          포도

 

# 행 추가

item.loc[6] = [7, '한국', '무화과', 3000, '무화과']
print(item)
   code  manufacture            name  price description
0     1        korea           apple   1500          사과
1     2        korea      watermelon  15000          수박
2     3        korea  oriental melon   1000          딸기
3     4  philippines          banana    500          망고
4     5        korea           lemon   1500         바나나
5     6        korea           mango    700          포도
6     7           한국             무화과   3000         무화과

 

# 특정 셀 수정

item.loc[6, 'name'] = "fig"
print(item)
   code  manufacture            name  price description
0     1        korea           apple   1500          사과
1     2        korea      watermelon  15000          수박
2     3        korea  oriental melon   1000          딸기
3     4  philippines          banana    500          망고
4     5        korea           lemon   1500         바나나
5     6        korea           mango    700          포도
6     7           한국             fig   3000         무화과

 

 

 

4. 연산

1) 전치 연산

- 행과 열을 전환하는 연산

- T 속성 이용

- transpose() 함수 이용

 

2) 산술 연산

- numpy와 동일한 방식으로 연산 수행 (브로드캐스트 연산)

- numpy는 위치 기반으로 연산을 수행하지만, Series나 DataFrame은 인덱스 기반으로 연산수행

- 한쪽에만 존재하는 경우 NaN으로 결과 설정

- 산술 연산자 사용 가능

- add, sub, div, mul 메소드 이용 가능. fill_value 옵션에 한쪽에만 존재하는 인덱스에 기본값 설정

 

item1 = {
    "1":{'price':1000}, 
    "2":{'price':2000}
}

item2 = {
    "1":{'price':1000}, 
    "3":{'price':3000}
}

df1 = pd.DataFrame(item1).T
df2 = pd.DataFrame(item2).T
   price
1   1000
2   2000

   price
1   1000
3   3000

 

# 브로드캐스트 연산

print(df1 + 200) #200을 df1의 개수만큼 복제해서 연산
   price
1   1200
2   2200

 

# 데이터프레임끼리 산술 연산

print(df1 + df2)
    price
1  2000.0
2     NaN
3     NaN
  • 존재하지 않는 인덱스 결과는 Nan(None과 조금 다름)

# 함수 사용 연산

print(df1.add(df2, fill_value=0))
    price
1  2000.0
2  2000.0
3  3000.0
  • 한쪽에만 존재하는 인덱스에 기본값 설정해서 연산 수행

# 행 단위 연산

print(df1.add(df2, axis=0))
    price
1  2000.0
2     NaN
3     NaN

 

 

3) 기본 통계 함수

- count, min, max, sum, mean, median, mode(최빈값)

- var(분산), std(표준 편차), kurt(첨도), skew(왜도), sem(평균의 표준 오차)

- argmin, argmax, dixmin, dixmax

- quantile(4분위수)

- describe(기술 통계 정보 요약)

- cumsum, cummin, cummax, cumprod: 누적합, 누적최소, 누적최대, 누적곱

- diff(산술적인 차이)

- pct_change(이전 데이터와의 백분율)

- unique(): Series에서만 사용 가능한데 동일한 값을 제외한 데이터의 배열 리턴하는 데 skipna 옵션을 이용해서 NaN 제거 가능

 

mpg = pd.read_csv("./data/auto-mpg.csv", header=None)
mpg.columns = ['mpg', 'cylinders', 'displacement', 'horsepower', 'weight', 
              'acceleration', 'model year', 'origin', 'name']
print(mpg.head())
    mpg  cylinders  displacement horsepower  weight  acceleration  model year  \
0  18.0          8         307.0      130.0  3504.0          12.0          70   
1  15.0          8         350.0      165.0  3693.0          11.5          70   
2  18.0          8         318.0      150.0  3436.0          11.0          70   
3  16.0          8         304.0      150.0  3433.0          12.0          70   
4  17.0          8         302.0      140.0  3449.0          10.5          70   

   origin                       name  
0       1  chevrolet chevelle malibu  
1       1          buick skylark 320  
2       1         plymouth satellite  
3       1              amc rebel sst  
4       1                ford torino  

 

# 기술 통계 함수

print(mpg[['mpg']].mean())

print(mpg[['mpg', 'weight']].mean())
mpg    23.514573
dtype: float64

mpg         23.514573
weight    2970.424623
dtype: float64

 

# describe()

print(mpg.describe())
              mpg   cylinders  displacement       weight  acceleration  \
count  398.000000  398.000000    398.000000   398.000000    398.000000   
mean    23.514573    5.454774    193.425879  2970.424623     15.568090   
std      7.815984    1.701004    104.269838   846.841774      2.757689   
min      9.000000    3.000000     68.000000  1613.000000      8.000000   
25%     17.500000    4.000000    104.250000  2223.750000     13.825000   
50%     23.000000    4.000000    148.500000  2803.500000     15.500000   
75%     29.000000    8.000000    262.000000  3608.000000     17.175000   
max     46.600000    8.000000    455.000000  5140.000000     24.800000   

       model year      origin  
count  398.000000  398.000000  
mean    76.010050    1.572864  
std      3.697627    0.802055  
min     70.000000    1.000000  
25%     73.000000    1.000000  
50%     76.000000    1.000000  
75%     79.000000    2.000000  
max     82.000000    3.000000  
  • 무의미한 컬럼(origin)의 기술통계가 같이 구해짐
mpg['origin'] = mpg['origin'].astype('str')
print(mpg.describe())
  • 형변환 해주기!

 

4) 상관관계 파악

- 상관관계: 2개의 데이터의 동일한 또는 반대되는 경향을 갖는 관계

  • 상관관계가 높다는 것은 동일한 경항 또는 완전히 반대되는 경향을 갖는 경우

- cov(): 공분산 

  • 거리의 제곱

- corr(): 상관계수

  • 공분산과 데이터의 스케일을 맞추지 않고 모든 값이 동일한 스케일을 갖도록 값을 수정
  • -1 ~ 1이 되도록 수정
  • 절대값 1에 가까워지면 상관관계가 높고, 0에 가까워지면 상관관계가 낮음
print(mpg[['mpg', 'cylinders', 'displacement']].corr())
                               mpg              cylinders         displacement
mpg                    1.000000        -0.775396          -0.804203
cylinders            -0.775396       1.000000            0.950721
displacement    -0.804203        0.950721           1.000000

 

 

5) 정렬

- 인덱스나 컬럼 이름에 따른 정렬

  • sort_index() 메소드 이용 
  • 기본은 인덱스가 기준
  • 오름차순이 기본. 내림차순을 할 때는 ascending = False 설정
  • axis=1 : 컬럼 이름을 기준으로 정렬 수행

- 컬럼의 값을 기준으로 정렬

  • sort_values(by = 열 이름 또는 열 이름의 list, ascending=bool 또는 bool의 list)

 

6) 순위

- rank 함수 이용

  • 기본 오름차순
  • ascending = False 내림차순
  • axis로 행 열 단위 설정

- 동일한 점수가 있는 경우 기본적으로 순위의 평균 리턴

  • method 옵션에 max, min, first 설정해서 동일한 점수 처리하는 것이 가능

- 순위는 컬럼 단위로 연산 수행

  • 컬럼의 개수가 2개면 순위도 2개 리턴

#내림차순

print(mpg.sort_values(by=['mpg'], ascending=[False]))
      mpg  cylinders  displacement horsepower  weight  acceleration  \....
322  46.6          4          86.0      65.00  2110.0          17.9   
329  44.6          4          91.0      67.00  1850.0          13.8   
325  44.3          4          90.0      48.00  2085.0          21.7   
394  44.0          4          97.0      52.00  2130.0          24.6   
326  43.4          4          90.0      48.00  2335.0          23.7   
..    ...        ...           ...        ...     ...           ...   

 

#오름차순

print(mpg.sort_values(by=['mpg', 'displacement'], ascending=[True, True]))
      mpg  cylinders  displacement horsepower  weight  acceleration  \
28    9.0          8         304.0      193.0  4732.0          18.5   
26   10.0          8         307.0      200.0  4376.0          15.0   
25   10.0          8         360.0      215.0  4615.0          14.0   
27   11.0          8         318.0      210.0  4382.0          13.5   
124  11.0          8         350.0      180.0  3664.0          11.0   
..    ...        ...           ...        ...     ...           ...   

 

#동일한 값은 순위의 평균

print(mpg.rank())
       mpg  cylinders  displacement  horsepower  weight  acceleration  \
0    116.0      347.0         324.0        74.0   290.0          36.5   
1     61.5      347.0         352.5       132.5   309.0          27.0   
2    116.0      347.0         334.0       111.5   284.0          15.0   
3     81.0      347.0         315.0       111.5   283.0          36.5   
4     96.0      347.0         306.0        87.0   287.0          11.0   
..     ...        ...           ...         ...     ...           ...   
  • .5는 같은 값이 2개라는 거

 

#동일한 값은 낮은 순위 부여

print(mpg.rank(method='min'))
       mpg  cylinders  displacement  horsepower  weight  acceleration  \
0    108.0      296.0         323.0        72.0   290.0          32.0   
1     54.0      296.0         344.0       131.0   309.0          24.0   
2    108.0      296.0         326.0       101.0   284.0          12.0   
3     75.0      296.0         312.0       101.0   283.0          32.0   
4     93.0      296.0         301.0        84.0   287.0          11.0   
..     ...        ...           ...         ...     ...           ...   

 

'Python' 카테고리의 다른 글

[Python] 데이터 전처리  (0) 2024.02.15
[Python] 데이터 시각화  (0) 2024.02.14
[Python] MySQL 데이터로 DataFrame 만들기  (0) 2024.02.14
[Python] 크롤링 - Selenium  (0) 2024.02.14
[Python] 크롤링 - 기사 스크래핑  (0) 2024.02.14

1. 필요한 패키지

- sqlalchemy

- pymysql

- mysqlclient

!pip install sqlalchemy
!pip install pymysql
!pip install mysqlclient

 

2. 데이터베이스 연결

  • 데이터베이스 접속 URL은 데이터베이스 종류마다 다름
  • 별도의 패키지를 설치해야 하는 경우도 있음
  • 포트는 3306이면 생략 가능
import pandas as pd
from sqlalchemy import create_engine
import pymysql

#연결
connect = create_engine('데이터베이스종류://아이디:비밀번호@IP:포트/데이터베이스이름')
df = pd.read_sql_table('테이블', connect)
print(df)
Empty DataFrame
Columns: [num, name, vendor, description]
Index: []

 

테이블 가져와서 데이터프레임 만들기 

dataframe = pandas.read_sql_table('테이블이름', database_connection)

 

 

실습 데이터

create table dbms(
	num int(10) NOT NULL AUTO_INCREMENT,
	name varchar(255) NOT NULL,
	vendor varchar(255) NOT NULL,
	description varchar(255),
	PRIMARY KEY(num)
);

INSERT INTO dbms(name, vendor, description) values('Oracle', 'Oracle', '금융과 대기업에서 많이 사용하는 가장 안정적인 데이터베이스');

INSERT INTO dbms(name, vendor, description) values('HANA DB', 'SAP', '오라클 대체용으로 사용하는 데이터베이스로 현대 자동차에서 사용');

INSERT INTO dbms(name, vendor, description) values('MySQL', 'Oracle', '현재 가장 많이 사용한다고 알려진 관계형 데이터베이스로 중소 기업이나 플랫폼 기업에서 주로 이용');

INSERT INTO dbms(name, vendor, description) values('Maria DB', 'Open Source', 'MySQL의 fork로 현재는 Kakao에서 사용하고 있습니다.');

INSERT INTO dbms(name, vendor, description) values('PostgreSQL', 'Open Source', '요즈음 많이 사용되는 데이터베이스');

.

import pandas as pd
from sqlalchemy import create_engine
import pymysql

#연결
connect = create_engine('mysql+mysqldb://root:0000@localhost/python_dataframe')
df = pd.read_sql_table('dbms', connect)
print(df)

 

 

 

3. 그 외의 데이터 사용

1) R의 데이터 활용

- pyreadr 이라는 패키지를 사용

- 읽는 방법

pyreadr.readr('rds 파일 경로')[None]

 

2) 통계 프로그램 데이터 읽어오기

- pyreadstat 패키지를 이용하면 SPSS, Stata, SAS 프로그램의 데이터를 읽을 수 있음

 

3) 최근 pySpark의 dataframe을 이용하는 경우가 많음

-  pySpark가 가져올 수 있는 데이터의 종류가 더 많고
- pySpark에서는 SQL을 그대로 사용할 수 있기 때문에 SQL을 아는 것이 중요

 

'Python' 카테고리의 다른 글

[Python] 데이터 시각화  (0) 2024.02.14
[Python] 데이터 탐색  (0) 2024.02.14
[Python] 크롤링 - Selenium  (0) 2024.02.14
[Python] 크롤링 - 기사 스크래핑  (0) 2024.02.14
[Python] Pandas  (1) 2024.02.08

[Python] 크롤링 - Selenium

0ㅑ채
|2024. 2. 14. 12:55

1. 개요

- 웹 앱을 테스트하는데 사용하는 프레임워크

- WebDriver 라는 API를 이용해서 운영체제에 설치된 브라우저를 제어하는 프레임워크

- 크롤링을 할 때 JavaScript를 이용해서 비동기적으로 가져오는 데이터를 읽고자 할 때 이용할 수 있고 로그인 후 가져와야 하는 데이터를 읽어오는데 사용합니다.

 

메뉴얼: http://docs.seleniumhq.org/docs/

 

- 파이썬에서 사용 준비

pip install selenium
  • 브라우저의 드라이버가 필요
  •  크롬의 버전을 확인

https://googlechromelabs.github.io/chrome-for-testing/#stable

 

2. 크롬 브라우저 실행

1) 기본 API

- 접속: get(url)

- html 코드 읽어오기: page_source

- 일정 시간 대기: implicitly_wait(시간)

- 브라우저 종료: quit()

- 카카오 접속

from selenium import webdriver
import os

os.environ['webdriver.chrome.driver'] = '크롬드라이버 경로'
while(True):
	pass
#사이트 접속
driver.get("https://www.kakao.com")
#html 읽어오기
html = driver.page_source
print(html)
while(True):
	pass

 

2) element 접근 API

- 하나만 찾는 API

find_element_by_name(이름)
find_element_by_id(아이디)
find_element_by_xpath(xpath)

 

- 배열로 찾는 API

find_element_by_css_selector(선택자)
find_element_by_css_class_name(클래스 이름)
find_element_by_tag_name(태그)

 

3) Element 동작 API

send_keys(값): 값이 입력됨
click(), submit(): 클릭

 

4) 스크립트 실행

execute_script(스크립트 코드)

 

5) 유튜브 스크롤

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import bs4
import os
import time

#드라이버 경로 설정
os.environ['webdriver.chrome.driver'] = 'C:\\Users\\USER\\Downloads\\chromedriver-win64\\chromedriver-win64\\chromedriver'
driver = webdriver.Chrome()
#사이트 접속
driver.get("https://www.youtube.com/results?search_query=%EB%8B%B9%EA%B7%BC%20%ED%9B%84%EA%B8%B0")
#5초 대기
time.sleep(5)

i = 0

body = driver.find_element(By.TAG_NAME, 'body')
while i < 10:
    body.send_keys(Keys.PAGE_DOWN)
    time.sleep(2)
    i = i + 1

#html 읽어오기
html = driver.page_source
print(html)
while(True):
	pass

 


6) 네이버 로그인

  • 아이디 와 비밀번호를 입력했을 때 capture 가 보이는 경우는 입력을 직접하지 않고 자바스크립트를 이용하면 보이지 않을 것
from selenium import webdriver
from selenium.webdriver.common.by import By
import os

#드라이버 경로 설정
os.environ['webdriver.chrome.driver'] = 'C:\\Users\\USER\\Downloads\\chromedriver-win64\\chromedriver-win64\\chromedriver'
driver = webdriver.Chrome()
#사이트 접속
driver.get("https://nid.naver.com/nidlogin.login")
#5초간 대기
driver.implicitly_wait(5)

#userid 와 password 에 아이디와 비밀번호를 직접 입력하면 자동 로그인이 됩니다.
userid = input("아이디")
password = input("비밀번호")

driver.execute_script("document.getElementsByName('id')[0].value=\'" + userid + "\'")
driver.execute_script("document.getElementsByName('pw')[0].value=\'" + password + "\'")
driver.find_element(By.XPATH, '//*[@id="log.login"]').click()
while(True):
	pass

 

 

 

 

 

'Python' 카테고리의 다른 글

[Python] 데이터 탐색  (0) 2024.02.14
[Python] MySQL 데이터로 DataFrame 만들기  (0) 2024.02.14
[Python] 크롤링 - 기사 스크래핑  (0) 2024.02.14
[Python] Pandas  (1) 2024.02.08
[Python] Numpy  (0) 2024.02.06

1. 검색어를 입력받아서 동아일보 신문 기사를 스크래핑해서 파일에 저장하기

1) 필요한 패키지

- urllib.parse.quote 함수: 검색어가 한글이라면 인코딩을 하기 위해서

- requests: 웹의 문자열을 읽어오기 위한 패키지, 기본 패키지가 아니라서 설치를 해야 함

- beautifulsoup: HTML 문자열에서 원하는 데이터를 추출하기 위해서 필요한 패키지, 기본 패키지가 아니라서 설치를 해야 함

!pip install requests
!pip install beautifulsoup4

 

2) URL 확인

https://www.donga.com/news/search?sorting=1&check_news=91&search_date=1&v1=&v2=&more=1&query=%EB%8B%B9%EA%B7%BC%20%ED%9B%84%EA%B8%B0

=> query: 검색어

 

3) 검색어 입력받아 URL 만들기

from urllib.parse import quote

#검색어를 입력받아서 인코딩
string = input("검색어를 입력하세요:")
keyword = quote(string)
#print(keyword)

target_URL = "https://www.donga.com/news/search?query=" + keyword
print(target_URL)

=> 검색어를 입력하세요: 당근 후기
https://www.donga.com/news/search?sorting=1&check_news=91&search_date=1&v1=&v2=&more=1&query=%EB%8B%B9%EA%B7%BC%20%ED%9B%84%EA%B8%B0

 

 

4) 첫 화면의 HTML 가져오기

# 정적인 웹의 데이터를 가져올 때 사용하는 패키지
import requests
html = requests.get(target_URL).text
print(html)

 

 

5) 기사 개수 가져오기

#HTML, XML 파싱에 사용하는 패키지
from bs4 import BeautifulSoup

#HTML 텍스트는 메모리에 트리 형태로 펼치기
bs = BeautifulSoup(html, 'html.parser')

#선택자는 동일한 데이터가 있을 수 있으므로 list
cnt = bs.select('div.cntPage > span')

#데이터가 1건이라서 반복문을 돌리지 않고 첫번재 데이터에서 바로 추출
'''
for x in cnt:
    print(x.getText())
'''
cnt = cnt[0].getText()
#print(cnt)
cnt = int(cnt[0:-1].replace(",", ""))
print(cnt)

=> 73

 

6) 기사 링크 가져오기

#페이지 개수 만들기
pageno = int(cnt / 15 + 0.99)

#기사의 링크를 저장할 list
links = []
#페이지 개수 만큼 순회하면서 html을 읽어서 파싱해서 저장
for i in range(0, pageno):
    #기사 링크와 제목이 나오는 페이지를 읽기
    url = "https://www.donga.com/news/search?p=" + str(i*15+1) + "&query=" + keyword + "&check_news=91&more=1&sorting=1&search_date=1&v1=&v2="
    html = requests.get(url).text
    soup = BeautifulSoup(html, "html.parser")
    linktag = bs.select('span.tit > a')
    for tag in linktag:
        #a 태그의 href 속성의 값을 가져오기
        links.append(tag['href'])
        
print(links)

 

 

7) 기사 링크에 가서 기사를 읽어서 텍스트 파일에 저장

#기록할 텍스트 파일을 생성
output_file = open(string + ".txt", 'w', encoding='utf8')

for link in links:
    html = requests.get(link).text
    bs = BeautifulSoup(html, "html.parser")
    articles = bs.select('#article_txt')
    for article in articles:
        #파일에 기록
        output_file.write(article.getText())

output_file.close()

 

 

 

 

 

 

 

 

 

 

 

'Python' 카테고리의 다른 글

[Python] MySQL 데이터로 DataFrame 만들기  (0) 2024.02.14
[Python] 크롤링 - Selenium  (0) 2024.02.14
[Python] Pandas  (1) 2024.02.08
[Python] Numpy  (0) 2024.02.06
Day10. REST API  (0) 2024.01.26

[Python] Pandas

0ㅑ채
|2024. 2. 8. 17:48

1. Pandas 패키지

- 데이터 분석을 위한 고수준의 자료구조, 분석 도구 제공

- 자료구조

  • Series: 열이 1개인 데이터 구조
  • DataFrame: 열이 2개 이상인 데이터 구조

 

2. Series

- Index와 Value 1개를 가지는 자료구조

series (데이터, index=None, dtype=None, copy=False)
  • 데이터: list, set, dict와 numpy.ndarray 가능
  • index: 데이터를 가리키는 이름
    • list · set · ndarray를 대입하면 0부터 시작하는 숫자 인덱스가 자동으로 생성
    • dict를 설정하면 key가 인덱스
    • index 옵션에 직접 인덱스 설정 가능
  • dtype
    • 데이터 1개의 자료형으로 설정 -> 그 자료형으로 생성
    • 설정 없음 -> pandas가 추론
  • copy: True -> 데이터 복제해서 생성 / False -> 참조를 가져와서 생성

 

- index와 values 속성

  • index 속성 호출 : 인덱스를 numpy의 ndarray로 리턴
  • values 속성 호출: 값들을 numpy의 ndarray로 리턴

* 딥러닝은 기본적으로  numpy의 ndarray로 수행하는데, 데이터가 pandas의 자료구조면 values 속성을 호출해서 numpy의 ndarray로 수행해야 함.

* pandas를 사용해야 하는 이유: 다양한 데이터를 불러올 수 있기 때문! pandas로 불러오고 numpy 배열로 바꿔줘야 한다.

 

- 하나의 데이터를 접근

  • Series[index]

- numpy와 동일한 형태로 연산 수행하고 numpy의 함수 사용 가능

  • numpy의 1차원 배열과 Series의 차이는 Index의 여부!!!
#시리즈를 생성
price = pd.Series([1000, 3000, 2000, 4000])
#시리즈를 출력 - 자동 생성된 인덱스 와 값이 출력
print(price)
#1이라는 인덱스를 가진 데이터를 조회
print(price[1])
#인덱스를 직접 설정
price.index = ["사탕", "과자", "음료수", "과일"]
print(price)
#인덱스가 사탕이라는 데이터를 조회: 1000
print(price["사탕"])
0    1000
1    3000
2    2000
3    4000
dtype: int64

3000

사탕     1000
과자     3000
음료수    2000
과일     4000
dtype: int64

1000
파이썬을 쓰는 것은 숫자가 항상 0부터 시작하고, n-1까지인데
개발자가 아닌 경우 1부터 시작하고 마지막을 포함한다. (ex.R)
pandas는 데이터분석을 위한 패키지기 때문에 (1, n)으로 인식한다.

 

x = price["사탕":"음료수"] #사탕부터 음료수까지의 데이터의 참조를 가져온 것
#x의 데이터를 변경하면 원본인 price 의 데이터도 수정
x["사탕"] = 800
print(x)
print(price)
print("=============================================")
y = price[["사탕","음료수"]] #사탕과 음료수의 데이터를 복제해 온 것
#y의 데이터를 변경해도 원본인 price의 데이터를 변경되지 않는 것
y["사탕"] = 2000
print(y)
print(price)
사탕      800
과자     3000
음료수    2000
dtype: int64

사탕      800
과자     3000
음료수    2000
과일     4000
dtype: int64

=============================================

사탕     2000
음료수    2000
dtype: int64

사탕      800
과자     3000
음료수    2000
과일     4000
dtype: int64
  • x는 참조를 가져와서 쓴 것. 따라서 x의 데이터를 변경하면 원본인 price의 데이터도 변경된다. 
  • y는 데이터를 복제함. y의 데이터를 변경해도 원본인 price의 데이터는 변경되지 않았다.
배열은 데이터의 연속적인 모임이다. array는 연속이 전제된다.
물리적으로 연속되면 array list (혹은 dense list)라고 하고, 논리적으로 연속되면 linked list라고 한다.

대괄호를 쓴 건 복제를 하겠다는 뜻

 

 

 

- Series와 Series의 연산은 인덱스를 기준

  • 동일한 인덱스가 없으면 연산을 수행하지 못한다. 
s1 = pd.Series([100, 200, 300, np.nan], index=["사과", "배", "한라봉", "천혜향"])
print(s1)
s2 = pd.Series([100, 200, 300, 500], index=["사과", "한라봉", "천혜향", "무화과"])
print(s2)

print(s1 + s2)
사과     100.0
배      200.0
한라봉    300.0
천혜향      NaN
dtype: float64

사과     100
한라봉    200
천혜향    300
무화과    500
dtype: int64

무화과      NaN
배        NaN
사과     200.0
천혜향      NaN
한라봉    500.0
dtype: float64
  • 시리즈는 인덱스를 일치하는 데이터끼리 연산을 수행
  • 한쪽에만 존재하거나 np.nan인 데이터가 있으면 결과가 np.nan
  • None은 데이터가 없다는 뜻이고, np.nan은 숫자로 볼 수 없다는 뜻. 

 

 

 

3. DataFrame

- 인덱스를 가진 테이블 형태의 자료구조

- 관계형 데이터베이스의 테이블과 유사하지만 인덱스를 직접 설정할 수 있다는 것이 다르다.

- dict를 이용해서 주로 생성.

  • dict의 키가 컬럼(열)의 이름이 되고 값이 셀 값이 된다.
  • head(n), tail(n)로 앞 또는 뒤에서 n 개의 데이터를 추출할 수 있다.
    • 기본적으로 5개를 가져온다.
    • 데이터를 제대로 가져왔는지 확인할 때 많이 사용한다.

- idex: DataFrame의 index를 리턴하고 설정할 수 있는 속성

  • 0부터 연속되는 숫자로 인덱스가 생성. index 속성으로 인덱스 직접 설정 가능

- columns: 컬럼의 이름을 리턴하고 이름을 수정할 수 있는 속성

  • columns = [리스트]  하면 컬럼의 이름을 직접 설정하는 것도 가능

- values: DataFrame의 데이터를 2차원 ndarray로 리턴

 

- info()는 데이터프레임의 개요를 리턴

#DataFrame 생성
source = {
    "code":[1, 2, 3, 4],
    "name":["카리나", "지젤", np.nan, "윈터"],
    "age": [23, 22, 34, 21]
}

df = pd.DataFrame(source)
print(df)

print(df.head(2)) #앞에서 2개

print(df.tail(2)) #뒤에서 2개

df.info()
   code name  age
0     1  카리나   23
1     2   지젤   22
2     3  NaN   34
3     4   윈터   21

   code name  age
0     1  카리나   23
1     2   지젤   22

   code name  age
2     3  NaN   34
3     4   윈터   21

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4 entries, 0 to 3
Data columns (total 3 columns):
 #   Column  Non-Null Count  Dtype 
---  ------  --------------  ----- 
 0   code    4 non-null      int64 
 1   name    3 non-null      object
 2   age     4 non-null      int64 
dtypes: int64(2), object(1)
memory usage: 224.0+ bytes

 

 

 

 

4. Pandas를 이용한 데이터 수집

1) 클립보드의 내용 읽어오기

pandas.read_clipboard()

 

 

2) 자주 사용하는 데이터셋

scikit-learn

https://scikit-learn.org/stable/datasets/toy_dataset.html

load_digits(): 숫자 데이터 셋 - 분류에 사용
load_iris(): 붓꽃 데이터 - 분류에 사용
load_diabetes(): 당뇨병 데이터 - 회귀에 사용
load_linnerud(): 체력 검사 데이터 - 회귀에 사용
load_wine(): 와인 품질 데이터 - 분류에 사용
load_breast_cancer(): 유방암 데이터 - 분류에 사용

 

UCI 머신러닝 데이터 저장소: https://archive.ics.uci.edu/ml/index.php

kaggle: https://www.kaggle.com

데이콘: https://dacon.io/

 

#사이킷런(scikit-learn)에서 제공하는 데이터를 사용
from sklearn import datasets
#iris 데이터 읽어오기
iris = datasets.load_iris()
#print(iris)
#데이터프레임이 아니고 Bunch 클래스의 인스턴스
print(type(iris))
  • type은 <class 'sklearn.utils._bunch.Bunch'>
  • 데이터프레임이 아니라 Bunch 클래스의 인스턴스임

 

키 확인

print(iris.keys())

dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename', 'data_module'])

  • data가 피처, target이 레이블
  • 레이블은 target, 목표값이다.
  • 어떤 target을 찾을 수 있는 열을 feature라고 한다.

 

데이터 확인

print(iris.data)

[[5.1 3.5 1.4 0.2]
 [4.9 3.  1.4 0.2]
 [4.7 3.2 1.3 0.2]

....

  • type은 ndarray

 

 

 

 

5. 텍스트 파일의 데이터 읽기

1) fwf 파일 읽기

2017-04-10다음32000
2017-04-11다음34000
2017-04-12다음33000
  • 일정한 간격을 가지고 컬럼을 구분하는 텍스트파일
  • 텍스트 파일은 포맷과 인코딩 방식 확인

인코딩 방식: utf-8, euc-kr, cp949(윈도우 한글 기본 포맷)

pandas.read_fwf('파일 경로', widths = (글자 사이의 간격), names = (컬럼 이름나열), encoding = 인코딩 방식)

#fwf 파일 읽기
df = pd.read_fwf('C:\\Users\\USER\\Downloads\\data\\data\\data_fwf.txt', 
                 widths=(10, 2, 5), 
                 names = ('날짜', '이름', '가격'),
                 encoding = 'utf-8')
print(df)
  • 윈도우에서 파일의경로를 설정할 때 역슬래시는 두번씩 입력
           날짜  이름     가격
0  2017-04-10  다음  32000
1  2017-04-11  다음  34000
2  2017-04-12  다음  33000

 

2) csv 파일 읽기

- csv: 구분 기호로 분리된 텍스트 파일

  • pandas.read_csv: 기본 구분자가 쉼표(,)
  • pandas.read_table: 기본 구분자가 탭

- 첫번째 매개변수로 파일 경로 설정

  • 아무런 옵션이 없으면 첫 번째 줄 데이터를 컬럼 이름으로 사용
#item.csv 파일 읽기
item = pd.read_csv('C:\\Users\\USER\\Downloads\\data\\data\\item.csv')
print(item)
print(item.info())
   code  manufacture            name  price
0     1        korea           apple   1500
1     2        korea      watermelon  15000
2     3        korea  oriental melon   1000
3     4  philippines          banana    500
4     5        korea           lemon   1500
5     6        korea           mango    700

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 6 entries, 0 to 5
Data columns (total 4 columns):
 #   Column       Non-Null Count  Dtype 
---  ------       --------------  ----- 
 0   code         6 non-null      int64 
 1   manufacture  6 non-null      object
 2   name         6 non-null      object
 3   price        6 non-null      int64 
dtypes: int64(2), object(2)
memory usage: 324.0+ bytes
None

 

옵션

- path: 데이터의 경로

- sep, delimiter: 구분자 설정. 기본은   ,

- header: 컬럼이름의 행번호 설정. 기본은 0, 없을 때는 None을 설정

- index_col: 인덱스로 사용할 컬럼 번호나 컬럼 이름 설정

- names: 컬럼 이름으로 사용할 list를 설정할 수 있는데 header=None일 때만 사용

- skiprows: 읽지 않을 행의 개수

- nrows: 읽을 행의 개수

- skip_footer: 무시할 마지막 행 개수

- endocing

- thousands: 천 단위 구분 기호. 설정하지 않으면 문자로 인식함

- na_values: NA 값으로 처리할 문자의 list

- parse_dates: 날짜 텍스트를 문자열이 아닌 날짜로 인식하게 하는 설정. 기본은 False라서 문자열로 인식

 

* csv 파일을 읽을 때는 먼저 파일을 열어서 첫번째 행이 컬럼의 이름인지, 한글이 포함되어있는지, 구분기호가 뭔지 확인

 

#item.csv 파일 읽기
good = pd.read_csv('C:\\Users\\USER\\Downloads\\data\\data\\good.csv')
print(good)
    apple  10   1500
0  banana   5  15000
1   melon   7   1000
2    kiwi  20    500
3   mango  30   1500
4  orange   4    700
  • 첫번째 행이 컬럼 이름이 되어버렸다. 
  • 첫번째 행을 컬럼 이름이 아니고 데이터로 만들기
#item.csv 파일 읽기
good = pd.read_csv('C:\\Users\\USER\\Downloads\\data\\data\\good.csv', 
                  header=None, names=['제품이름', '수량', '가격'])
print(good)

 

     제품이름  수량     가격
0   apple  10   1500
1  banana   5  15000
2   melon   7   1000
3    kiwi  20    500
4   mango  30   1500
5  orange   4    700

 

- 데이터 양이 아주 많은 경우에 한 번에 읽으려고 하면 실패

  • nrows 속성을 이용해서 시작 위치에서 일부분의 데이터만 읽어오고 skiprows를 이용해서 읽을 수 있음
#item.csv 파일 읽기
parser = pd.read_csv('C:\\Users\\USER\\Downloads\\data\\data\\good.csv', 
                  header=None, nrows=2, skiprows=4)
print(parser)
        0   1     2
0   mango  30  1500
1  orange   4   700
  • 반복문을 사용하면
#item.csv 파일 읽기
for i in range(0, 3):
    parser = pd.read_csv('C:\\Users\\USER\\Downloads\\data\\data\\good.csv', 
                      header=None, nrows=2, skiprows=i*2)
    print(parser)
        0   1      2
0   apple  10   1500
1  banana   5  15000
       0   1     2
0  melon   7  1000
1   kiwi  20   500
        0   1     2
0   mango  30  1500
1  orange   4   700
  • 데이터 갯수가 몇개인지 모르면 while문
i = 0
while True:
    try:
        parser = pd.read_csv('C:\\Users\\USER\\Downloads\\data\\data\\good.csv', 
                          header=None, nrows=2, skiprows=i*2)
        print(parser)
        i = i + 1
    except:
        break
  • chunksize를 설정해서 한 번에 읽을 데이터의 개수를 설정하고 이때 리턴되는 TextParser 객체를 순회하면서 읽을 수 있음
parser = pd.read_csv('C:\\Users\\USER\\Downloads\\data\\data\\good.csv', 
                      header=None, chunksize=2)
for piece in parser:
    print(piece)

 

- 탭으로 구분된 파일 읽기

ParserError: Error tokenizing data. C error: Expected 1 fields in line 326, saw 2
  • 탭으로 구분돼있음을 확인
gapminder = pd.read_csv('C:\\Users\\USER\\Downloads\\data\\data\\gapminder.tsv', 
                       sep = 'Wt')
print(gapminder.head())
       country continent  year  lifeExp       pop   gdpPercap
0  Afghanistan      Asia  1952   28.801   8425333  779.445314
1  Afghanistan      Asia  1957   30.332   9240934  820.853030
2  Afghanistan      Asia  1962   31.997  10267083  853.100710
3  Afghanistan      Asia  1967   34.020  11537966  836.197138
4  Afghanistan      Asia  1972   36.088  13079460  739.981106

 

 

csv로 저장

- Series나 DataFrame의 to_csv 메소드 호출

- 첫 번째 매개변수로 파일 경로 설정

- 기본적으로는 index와 컬럼 이름이 저장되는데 index와 header에 False 설정하면 출력되지 않음

- sep: 구분자 설정

- na_rep: NaN 값을 원하는 형식으로 설정

- cols: 컬럼 이름을 list로 설정하면 설정한 컬럼만 파일에 저장

data.to_csv('test.csv', index=False)

 

 

 

3) 엑셀 파일 읽기

pandas.io.excel.read_excel("파일 경로")
  • read_csv와 유사한데 sep는 없음
  • sheet_name: 시트 선택해서 불러오기

- xlrd 패키지 설치

pip install xlrd

* anaconda는 패키지가 내장되어있음

 

- DataFrame으로 만들기

df = pd.read_excel('C:\\Users\\USER\\Downloads\\2023-2 FOLLOW 순모임 출석체크.xlsx')
df

 

 

엑셀 파일 저장

- openpyxl 패키지 설치

*아나콘다는 내장

 

- 엑셀파일 경로를 갖는 라이터변수

!pip install xlsxwriter

writer = pandas.ExcelWriter("엑셀파일 경로", engine="xlsxwriter")
df.to_excel(writer, sheet_name='시트이름')
writer.close()
  • 저장했지만 여전히 쥬피터가 df를 쓰고 있기 때문에 작업이 완전히 끝난 후에 자유롭게 쓸 수 있음!

 

 

6. Web의 데이터 읽기

1) HTML에 있는 table 태그의 모든 가져오기

- pandas.read_html('파일의 경로나 URL')을 이용하면 table 태그의 내용을 DF로 만들어서 list 리턴

- 옵션으로 천단위 구분 기호 설정, 인코딩 방식, na 데이터 설정 등

 

https://ko.wikipedia.org/wiki/인구순_나라_목록

https://ko.wikipedia.org/wiki/%EC%9D%B8%EA%B5%AC%EC%88%9C_%EB%82%98%EB%9D%BC_%EB%AA%A9%EB%A1%9D

  • URL에는 한글을 직접 사용하지 않고 인코딩된 URL을 사용해야 함

 

li = pd.read_html('https://ko.wikipedia.org/wiki/%EC%9D%B8%EA%B5%AC%EC%88%9C_%EB%82%98%EB%9D%BC_%EB%AA%A9%EB%A1%9D')
print(li[0])
  • 인덱스를 이용해 원하는 테이블을 선택해야 함
      순위       나라          인구   갱신 년도  \
0      1       인도  1428627663  2024.0   
1      2  중화인민공화국  1409670000  2024.0   
2      3       미국   334914895  2023.0   
3      4    인도네시아   279476346  2023.0   
4      5     파키스탄   247653551  2023.0   
..   ...      ...         ...     ...   
236  237     토켈라우        1893  2023.0   
237  238      니우에        1681  2022.0   
238  239   바티칸 시국         764  2023.0   
239  240   코코스 제도         593  2021.0   
240  241   핏케언 제도          47  2021.0   

                                               기타  
0    공식 인구시계 UN 프로젝션[1][2][3] UN 예상치 인구가 가장 많은 국가  
1                                         공식 인구시계  
2                                         공식 인구시계  
3                                         공식 인구시계  
4                                         공식 인구시계  
..                                            ...  
236                                        UN 예상치  
237                                        공식 추계치  
238                  바티칸 시국 인구통계 인구가 가장 적은 UN 가입국  
239                                        공식 추계치  
240                                  인구가 가장 적은 속령  

[241 rows x 5 columns]

 

 

2) 웹에서 데이터 활용

- 웹에서 데이터 가져오기

- 데이터를 파싱 (데이터를 해석해서 원하는 데이터를 추출)

- 웹에서 제공되는 텍스트 데이터 종류

 

XML

  • 데이터를 태그 형식으로 표현하는데 해석은 사용자가 함
<Persons>
    <Person>
        <name>귀도반로썸</name>
        <language>파이썬</language>
    </Person>
    <Person>
        <name>제임스 고슬링</name>
        <language>자바</language>
</Persons>

 

JSON

  • 자바스크립트의 객체 표현법으로 데이터를 표현하는 방식
  • 최근의 API에서는 대부분 JSON만 지원

{"persons" : [{"name" : "하일스베르", "language" : "C#"}, {"name" : "데니스 리치히", "language" : "C"}]}

 

YAML (yml, 야믈)

  • 가장 최근에 등장한 포맷으로 이메일 형식으로 데이터 표현하는 방식
  • 클라우드 환경에서 설정 파일의 대부분은 YAML
persons:
    person:
        name:하일스베르
        language: typescript
    person:
        name: 래리앨리슨
        language: 오라클

 

HTML

  • 웹 브라우저가 해석해서 화면에 랜더링하기 위한 포맷
  • 구조적이지 않아서 데이터를 표현하는 데는 사용하기 어려움
  • API를 제공하지 않는 사이트에서 화면에 보여지는 데이터를 추출하기 위해 다운로드 받아서 사용

 

 

3) 웹에서 데이터 가져오기

- urllib와 urllib2라는 파이썬 내장 모듈을 이용해서 웹의 데이터를 가져올 수 있음

  • 내장 모듈의 request 객체의 urlopen이라는 메소드에 url을 문자열로 대입하면 url에 해당하는 데이터를 response 타입의 객체로 리턴
  • response객체의 getheaders()를 이용하면 제공하는 데이터의 정보를 읽을 수 있고 read()를 호출하면 내용을 읽을 수 있다.
  • read().decode("인코딩정보"): 읽온 내용이 한글이 포함되어 있다면 인코딩 설정
import urllib.request
from urllib.parse import quote

keyword = quote("네이버")

result = urllib.request.urlopen("https://search.hani.co.kr/search?searchword="+ keyword)
print(result.read())

 

- URL 한글 인코딩

  • 문자열을 인코딩하고자 하면 urllib.parse 모듈의 quote_plus와 qoute 함수 이용
  • 두 함수의 차이는 공백을 +로 처리하느냐 %20으로 처리하느냐의 차이

 

- 한겨례 신문사에서 '네이버' 검색 결과 가져오기

https://search.hani.co.kr/search?searchword=%EB%84%A4%EC%9D%B4%EB%B2%84

  • https://search.hani.co.kr/search?searchword=검색어
  • 한글을 치면 인코딩 에러가 나기 때문에 변수 keyword
import urllib.request
from urllib.parse import quote

keyword = quote("네이버")

result = urllib.request.urlopen("https://search.hani.co.kr/search?searchword="+ keyword)
print(result.read())

 

 

- requests 패키지를 활용한 웹의 데이터 가져오기

  • GET, POST, PUT, DELETE 요청을 사용할 수 있고 데이터 인코딩이 편리한 패키지
  • 파라미터로 넘겨줄 데이터를 dict로 만들어서 GET이나 POST 등에서 사용하면 인코딩을 자동으로 수행
requests.get("url")
  • 웹 페이지의 결과를 Response 객체를 리턴
    • Response.txt를 이용하면 문자열을 가져올 수 있고 
    • content 속성을 호출하면 bytes를 리턴
pip install requests

import requests
resp = requests.get("http://httpbin.org/get")
print(resp.text)
{
  "args": {}, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate, br", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.31.0", 
    "X-Amzn-Trace-Id": "Root=1-65c46116-58a3d4551f99f24768fa4fe0"
  }, 
  "origin": "118.131.111.158", 
  "url": "http://httpbin.org/get"
}

 

#파라미터 만들기
param = {"id":"itstudy", "name":"군계", "age":53}
resp = requests.post('http://httpbin.org/post', data=param)
print(resp.text)
{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {
    "age": "53", 
    "id": "itstudy", 
    "name": "\uad70\uacc4"
  }, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate, br", 
    "Content-Length": "41", 
    "Content-Type": "application/x-www-form-urlencoded", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.31.0", 
    "X-Amzn-Trace-Id": "Root=1-65c4619a-6cea70d6665e833a7d02a84f"
  }, 
  "json": null, 
  "origin": "118.131.111.158", 
  "url": "http://httpbin.org/post"
}

 

- 이미지 파일 다운로드

#이미지 파일 다운로드
imageurl = "https://search.pstatic.net/common/?src=http%3A%2F%2Fblogfiles.naver.net%2FMjAyMTA1MTVfMjg1%2FMDAxNjIxMDA0ODI5MDc0.Q17_bqOFXmCDBx4kAr_UQl3vGPfvY4wNAS48RCfwja8g.UM29jj3Mra_yEHXChamjsDevclJMy13NgQRRzEbWyPAg.JPEG.gody97%2Fresized%25A3%25DFoutput%25A3%25DF1906874251.jpg&type=sc960_832"

filename ="redpanda.jpg"

try:
    #다운로드
    resp = requests.get(imageurl)
    #파일에 저장
    with open(filename, "wb") as h:
        #다운로드 받은 내용을 bytes로 리턴
        img = resp.content
        h.write(img)
except Exception as e:
    print(e)

 

 

 

 4) json 데이터 파싱

방법

- requests를 이용해서 다운로드 받은 후 직접 파싱 - 옵션이 많을 때 좋음

- pandas.read_json을 이용해서 자동으로 파싱 - 데이터의 구조가 단순할 때 좋음

 

pandas.read_json을 이용해서 파싱

df = pd.read_json("http://swiftapi.rubypaper.co.kr:2029/hoppin/movies?version=1&page=1&count=30&genreId=&order=releasedateasc") 
hoppin = df["hoppin"]
print(hoppin)
movies        {'movie': [{'genreNames': '코미디,드라마', 'genreIds...
totalCount                                                 4266
Name: hoppin, dtype: object

 .

movies = hoppin['movies']
print(movies)
movie = movies['movie']
print(movie)

 .

for item in movie:
    print(item["title"] + ":" + item["ratingAverage"])
인포먼트:6.7
엣지 오브 다크니스:6.9
베이비 돌:6
황야의 역마차:6.3
전원 교향곡:8
아버지의 깃발:8
여덟번의감정:6
레드:8.7
영광의 탈출:6.8
크로싱:8.8
맨 인 블랙:8.9
차형사:8.4
에이지 오브 드래곤:3.9
로드 오브 워리어:7.4
[메이킹 다큐] 도둑들 영화를 만들다!:7.9
괜찮아요 수달씨:7.5
파파:9
이케맨 뱅크:6.7
다중인격소녀 ISOLA:5.7
위조지폐:6.5
카인과 아벨:6.9
돌핀 블루:8.2
더 코드:7.6
철권 블러드 벤전스:8
블루 엘리펀트 (우리말 더빙):8.8
해결사 (2010):8.3
하나오니 2: 사랑의 시작:8.5
하나오니 3: 복수의 시간:8.5
아테나 전쟁의 여신 극장판:7.7
아이스 프린세스:8.8

 

- 파이썬의 기본 모듈을 이용해서 json 파싱

  • jsonloads("문자열") 
  • json 문자열을 파싱해서 파이썬 dict나 list 생성
  •   {   로 시작하면 dict
  •   [   로 시작하면 list

 

 

 

5) 카카오 검색 API 데이터를 가져와서 MySQL에 저장

2024.03.15 - [Python/Python 실전편] - [Python] Pandas 실습 _ 카카오 검색 API 데이터 가져오기

 

[Python] Pandas 실습 _ 카카오 검색 API 데이터 가져오기

- 카카오 검색 API developers.kakao.com - 애플리케이션 생성 후 REST API 키 복사 a89507c93f15074167c0700239d4b1d0 블로그 검색 메서드URL인증 방식 GET https://dapi.kakao.com/v2/search/blog REST API 키 헤더 Authorization Authoriz

yachae4910.tistory.com

 

 

6) XML 파싱

RSS

- 사용할 URL:  https://www.hankyung.com/feed/it

- 파싱 방법:

import xml.etree.ElementTree as et

# urllib.request를 이용해서 읽어온 데이터: res

#메모리에 펼치기
tree = et.parse(res)

#루트 찾기
xroot = tree.getroot()

#특정 태그의 데이터 가져오기
items = xroot.findall('태그')

#태그는 여러개 나올 수 있으므로 반복문 수행
for node in items:
    node.find(태그).text : 태그 안의 데이터
import urllib.request
url = "https://www.chosun.com/arc/outboundfeeds/rss/category/economy/?outputType=xml"
request = urllib.request.Request(url)
response = urllib.request.urlopen(request)

#xml 파싱
import xml.etree.ElementTree as et
#메모리에 트리 형태로 펴맃기
tree = et.parse(response)
print(tree)

 

 

 

7) HTML 파싱

# BeautifulSoup 패키지 이용

!pip install beautifulsoup4

* 아나콘다에는 내장

 

  • 모듈을 import 할 때는 bs4를 import

 

# 메모리에 펼치기

bs4.BeautifuleSoup(파싱할 html, "html.parser")

 

 

# 태그 안의 데이터 찾기

bs.태그이름 나열.get_text

*별로 쓰지 않음. 

 

 

import requests
import bs4

resp = requests.get("http://finance.daum.net/")
html = resp.text
print(html)

</html lang="ko">
 
 
</meta http-equiv="content-type" content="text>
 
</meta http-equiv="x-ua-compatible" content="ie=edge" >
 
</meta property="og:site_name" content="다음금융" >


...

#html 파싱
bs = bs4.BeautifulSoup(html, 'html.parser')
#html에서 body 태그 안의 span 태그의 텍스트 가져오기
print(bs.body.span.get_text())

금융

 

 

 

- find 함수

find(태그, attributes, recursive, text, limit, keywords)
  • 태그: 찾고자 하는 태그를 설정
  • attributes: 태그 중에서 특정 속성의 값만 가져올 때 사용
  • recursive: False면 최상위 태그에서만 찾고, True면 하위로 들어가면서도 찾음
  • 일치하는 태그 1개를 찾아온다.
  • 일치하는 태그 여러개를 찾으려면 find_all 사용

 

 

- select 함수

선택자를 이용해서 찾아오는 함수

 

 

 

- bs4.element.Tag

  • find와 select의 결과는 Tag 클래스의 list
  • Tag 클래스에서 getText()를 호출하면 태그가 감싸고 있는 텍스트를 가져올 수 있고
  • get('속성이름')은 속성의 값을 가져올 수 있다.

 

선택자는 앞에서부터 생략도 가능

https://news.naver.com/section/105

 

import requests
import bs4

resp = requests.get("https://search.hankyung.com/search/total?query=%ED%94%8C%EB%9E%AB%ED%8F%BC")
html = resp.text
# print(html)

#html 파싱
bs = bs4.BeautifulSoup(html, 'html.parser')
tags = bs.select('div > a')

#html에서 body 태그 안의 span 태그의 텍스트 가져오기
for tag in tags:
    print(tag.getText())
    print(tag.get('href'))
    print()
개발자 10명 중 8명 "생성형 AI, 개발 대체할 것" [Geeks' Briefing]

https://www.hankyung.com/article/202402084600i


https://www.hankyung.com/article/2024020844441


'공정위 혼자 왜이리 급하냐'…국회도 혀 찬 플랫폼법 독주

https://www.hankyung.com/article/2024020844441


https://www.hankyung.com/article/202402083905i

 

 

 

 

'Python' 카테고리의 다른 글

[Python] 크롤링 - Selenium  (0) 2024.02.14
[Python] 크롤링 - 기사 스크래핑  (0) 2024.02.14
[Python] Numpy  (0) 2024.02.06
Day10. REST API  (0) 2024.01.26
Day9. 웹 서버 만들기  (1) 2024.01.24

[Python] Numpy

0ㅑ채
|2024. 2. 6. 18:20

1. 특징

- Python에서 고성능의 과학적 계산 수행하는 패키지 (ex.선형 대수)

- Python 머신러닝 스택의 기초 패키지

- 다차원 배열인 ndarray를 제공

- 벡터화 된 연산과 Broadcasting 연산 지원

 

 

2. 설치

pip install numpy

*아나콘다는 자동 설치

*다른 패키지를 설치할 때 종속적으로 설치되는 경우가 있음 -> 버전 문제 발생

 

 

3. 사용

import numpy
import numpy as np
from numpy import * # 모듈의 모든 내용을 현재 모듈에서 사용
from numpy import ndarray # numpy 모듈 중에서 ndarray만 사용
  • import *을 쓰면 nupmy 써주지 않아도 사용할 수 있지만, 내장함수인지 구분이 가지 않음!

 

 

 

4. ndarray

- array, 배열

- list나 tuple보다 생성 방법이 다양하고 가능한 작업 많음

- id의 모임이 아니라 값의 모임

  • list나 tuple은 id의 모임이기 때문에 보기에는 자료형이 달라도 같은 자료형(id)으로 취급해서 생성이 가능했다.
  • 그런데 ndarray는 동일한 자료형의 grid
  • ndarray를 생성할 때 다른 자료형을 대입하면 추론을 통해 하나의 자료형으로 변환해서 생성

 

 

 

5. 속도

import datetime

li = range(1, 100000)

#현재 시간 저장
start = datetime.datetime.now()

#모든 요소에 10 곱하기
for i in li:
    i = i * 10
    
#현재 시간 저장
end = datetime.datetime.now()
print(start, end)

🤍

2024-02-06 12:39:02.822362 2024-02-06 12:39:03.379676

.

import numpy as np

ar = np.arange(1, 10000000)

#현재 시간 저장
start = datetime.datetime.now()

ar = ar * 10

#현재 시간 저장
end = datetime.datetime.now()
print(start, end)

🤍

2024-02-06 12:39:03.403699 2024-02-06 12:39:03.418701
  • numpy가 더 빠름

 

 

 

6. 생성

numpy.array(object, dtype=None, copy=True)
  • object: Vector 자료형 (데이터의 모임 - list, tuple, set 등의 데이터)
  • dtype: 요소의 자료형, 생략 시 numpy가 알아서 추론
  • copy: 복제 여부. 기본값은 True라서 원본 데이터를 복제해서 생성
numpy.asarray(object, dtype = None)
  • object가 ndarray 자료형이면 데이터를 copy하지 않음

 

 

 

 

7. ndarray의 정보 확인 속성

- dtype: 데이터 한 개의 자료형

- ndim: 배열의 차원

- shape: 각 차원의 크기를 튜플로 리턴

- size: 데이터 개수

- itemsize: 하나의 항목이 차지하는 메모리 크기

- nbytes: 전체가 차지하는 메모리 크기

 

차원 확인

import numpy as np

#list를 이용해서 array 생성
ar = np.array([1, 2, 3])

#1차원
print(ar.ndim) 
print(ar.shape)  #1차원 3개의 데이터로 구성 (3, )

#2차원
table = np.array([[1, 2, 3], [4, 5, 6]])
print(table.ndim) 
print (table.shape) # 2행 3열의 배열 (2, 3)

 

 

 

 

8. 배열을 생성하는 다른 방법

numpy.arange(start, stop, step, dtype=None)
  • start부터 stop까지 step 간격으로 생성
  • dtype은 데이터 1개의 하나의 자료형
  • stop 값만으로 생성할 수 있음
  • 샘플 데이터 만들 때 자주 사용
ar = np.arange(1, 10, 2)
print(ar)
[1 3 5 7 9]

 

numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0)
  • start부터 stop까지 num만큼 배열로 생성
  • endpoint는 마지막 값 포함 여부
  • axis는 축
  • 샘플 데이터 만들 때 자주 사용
numpy.zeros(), numpy.ones()
  • 차원을 매개변수로 받아서 0이나 1로 채워주는 함수들
numpy.zeros_like(), numpy.ones_like()
  • 배열을 매개변수로 받아서 동일한 크기의 배열을 만들고 0이나 1로 채워주는 함수들
numpy.empty(), numpy.empty_like()
  • 초기화하지 않은 데이터(의미없는 값)의 배열 생성
numpy.eye(N, M, k=0, dtype=None)
  • N은 행의 개수, M은 열의 수, k는 대각 위치로
    k=0이면 주대각선 방향만 1로 채워주고 k != 0이면 좌우로 대각 방향을 이동해서 1을 채워주는 행렬 생성
  • N과 M 둘 중 하나의 값만 입력하면 하나의 값을 복사해서 정방행렬 생성
numpy.diag(행렬)
  • 행렬에서 주 대각선 방향의 데이터만 골라 행렬 생성
#주대각선 방향이 1인 3*3 정방 행렬 생성
ar = np.eye(3)
print(ar)

print()
#행렬에서 주 대각선의 데이터만 골라서 다시 배열 생성
print(np.diag(ar))

🤍

[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]

[1. 1. 1.]

 

 

 

 

 

9. 자료형

- numpy의 ndarray는 모든 요소의 자료형이 동일해야 한다.

  • 데이터의 자료형이 다르면 하나의 자료형으로 형변환해서 생성
  • 정수와 실수가 같이 있으면 실수로, 숫자와 문자열이 같이 있으면 문자열로 생성

- 요소의 자료형은 dtype 속성으로 확인 가능

 

자료형

정수: numpy .int8, int16, .int32, .int64, .unit8, .unit16, .unit32, .unit64 - unit은 양수만 저장

실수: float16, float32, float64, float128

복소수: complex64, complex128,  complex256

boolean: bool

문자열: string_

유니코드: unicode_

객체: object

 

- 만들어진 배열의 자료형을 변경해서 다시 생성

  • ndarray.astype(자료형)

- 형 변환을 하는 이유

  • 머신러닝에서는 숫자 데이터만 사용 가능하기 때문에
  • 서로 다른 배열끼리 연산을 하는 경우에
  • 메모리를 효율적으로 사용하기 위해서
색상값 0~255까지의 숫자를 표현해야 하는 경우

int8는 8비트이다. 
int는 양수와 음수를 같이 표현한다.
양수와 음수의 모양이 각각 128가지 (-128 ~ 127)이다. 그래서 색상값 표현이 안된다. 
따라서 int16을 사용해서 표현해야 함! 

그런데 unit는 마찬가지로 모양이 256가지인데
음수를 표현하지 않기 떄문에
0~255 범위의 데이터를 표현하는 것이 가능하다.
메모리 효율 달성~

 

#데이터 타입 확인과 형변환
ar = np.array([1, "2", 3]) # 숫자 -> 문자열로 바뀜
print(ar.dtype)

ar2 = np.array([1, 2.3, 3]) # 정수 -> 실수로 바뀜
print(ar2.dtype)

#ar 배열의 자료형을 정수로 변환
ar3 = ar.astype(np.int32)
print(ar3.dtype)

🤍

<U11
float64
int32

 

 

 

 

 

10. 배열 차원 변환

머신러닝이나 딥러닝을 하다보면 특정한 차원의 데이터를 요구

현재 가지고 있는 데이터가 요구하는 차원과 맞지 않으면 차원을 변경해서 사용해야 함

 

차원 변경 함수

  • reshape: 차원을 튜플로 받아서 튜플에 해당하는 차원으로 변경
  • flatten: 무조건 1차원 배열로 변환
  • 튜플을 대입하지 않고 -1을 대입하면 1차원으로 변경
  • 튜플로 숫자를 설정할 때 마지막 값을 -1로 설정하면 numpy가 알아서 마지막 값 추론하고 설정

 

10개의 데이터가 있는 1차원 1배열 -> 2차원 배열로 변경

#0부터 19까지의 숫자를 가지고 1차원 배열 생성
ar = np.arange(20)
print(ar)

print()
#ar을 4*5짜리 2차원배열로 변환
#5 대신에 -1을 대입해도 결과는 동일
#20개의 데이터는 4행으로 만들려면 5열밖에 안됨
matrix = ar.reshape((4, -1))
print(matrix)

print()
#다차원 데이터를 1차원으로 변환
br = matrix.flatten()
print(br)

.

[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19]

[[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]
 [15 16 17 18 19]]

[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19]

 

 

 

 

11. 배열의 부분 사용

1) 하나의 요소 사용 Indexing

- 일차원 배열의 경우 배열명[인덱스]의 형태로 접근

  • 앞에서부터 접근할 때는 0부터 시작, 맨 뒤에서 접근할 때는 -1, -2 ...

- 이차원 배열의 경우 배열명[행번호, 열번호] 또는 배열명[행번호][열번호]

- 삼차원 배열의 경우 사용할 수 있는 번호만 늘리기

#배열에서 하나의 요소 접근
ar = np.arange(10)
matrix = ar.reshape((2, -1)) #행 2개, 열은 알아서
print(ar)
print(matrix)

#일차원 배열에 요소 접근
print(ar[0]) #첫번째 데이터
print(ar[-1]) #마지막 데이터

#이차원 배열에서 요소 접근
print(matrix[0, 2])
print(matrix[0][2])

🤍

[0 1 2 3 4 5 6 7 8 9]
[[0 1 2 3 4]
 [5 6 7 8 9]]
0
9
2
2

 

 

2) 여러 개의 데이터 접근: Slicing

하나의 행 또는 열 단위로 접근

#배열에서 범위를 이용한 접근
ar = np.arange(10)
matrix = ar.reshape((2, -1))

print(ar[1:4]) #1에서 3까지
print(ar[5:]) #5부터 마지막값까지
print(ar[:4]) #시작위치부터 3까지
print(ar[:]) #전체

#이차원 배열에서의 접근
print(matrix[1][1:3]) 
print(matrix[1]) #1행 전체
print(matrix[:,1]) #1열 전체

🤍

[1 2 3]
[5 6 7 8 9]
[0 1 2 3]
[0 1 2 3 4 5 6 7 8 9]

[6 7]
[5 6 7 8 9]
[1 6]

 

 

 

3) 복사 방법

인덱싱이나 슬라이싱은 원본 데이터의 *참조만* 가져오는 것
- 인덱싱이나 슬라이싱으로 가져온 데이터를 변경하면, 원본의 데이터도 수정
- 복제를 하려면 copy()를 호출해야 함

 

- 참조 복사

  • 데이터의 위치를 복사
  • 원본이나 사본에 영향을 준다. 
  • 지역 변수의 참조를 전역변수에 대입해서 사라지지 않도록 하기 위해 사용

- weak copy(얕은 복사)

  • 데이터 참조를 한 번만 찾아가서 복사
  • 데이터가 다른 데이터의 참조인 경우 원본에 영향

- deep copy(깊은 복사)

  • 데이터의 참조를 재귀적으로 찾아가서 실제 데이터 복사
  • 어떠한 경우에도 다른 데이터에 영향 줄 수 없음
  • 데이터를 다른 변수로 참조하고자 할 때 권장하지만, 메모리가 부족한 경우 얕은 복사나 참조 복사를 하기도 함
#배열 생성
ar = np.arange(10)
print(ar)

#범위를 이용해서 데이터를 가져오는 것 - 참조를 복사
br = ar[0:4]
print(br)

#br[0]을 수정하면 ar의 데이터도 영향
br[0] = 42
print(br)
print(ar)

🤍

[0 1 2 3 4 5 6 7 8 9]
[0 1 2 3]
[42  1  2  3]
[42  1  2  3  4  5  6  7  8  9]

 

* 원본 데이터를 수정하는 것은 위험

#데이터를 복제해서 br이 가리키도록 하려면

ar = np.arange(10)
br = ar[0:4].copy() # 원본 데이터 영향없음
print(br)

.

[0 1 2 3]

 

 

4) Fancy Indexing

- 데이터를 선택할 때 list 이용해서 선택

- 연속된 범위가 아니더라도 선택이 가능

- 데이터는 복제됨!

ar = np.arange(10)

#Fancy Indexing
br = ar[[1, 3, 5, 7]]
print(br)
br[0] = 15700
print(br)
print(ar)

.

[1 3 5 7]
[15700     3     5     7]
[0 1 2 3 4 5 6 7 8 9]

🤍

matrix = ar.reshape((2, -1))
print(matrix)

print(matrix[:, 0])
#이차원 배열에서 list를 이용해서 행 번호나 열 번호를 지정하면 이차원 배열이 만들어짐
print(matrix[:, [0]])

🤍

[[0 1 2 3 4]
 [5 6 7 8 9]]
[0 5]
[[0]
 [5]]
  • numpy의 ndarray나 pandas의 DataFrame에서 
    하나의 열을 선택할 때 구조를 유지하기 위해서는 list로 설정

 

5) 조건에 맞는 데이터 선택

- 브로드캐스트 연산: numpy의 ndarray는 차원이 다른 데이터끼리 연산을 수행하면 순회하면서 연산 수행

- 산술 연산 -> 결과 리턴: 수치 데이터

- 논리 연산 -> 결과 리턴: bool의 배열

- 인덱싱 때 bool 배열을 대입 -> True인 데이터만 추출

- 논리 연산을 결합할 때 and, or를 사용하지 않고 &와 |를 사용해야 함

  • and, or는 하나의 연산을 하나의 결과 (True or False)로 보기 때문!
    and와 or는 좌측과 우측의 데이터를 무조건 하나의 데이터로 간주
    &와 |는 하나의 데이터끼리 연산을 하면 하나의 결과를 만들고 배열끼리 연산을 하면 배열을 만듦

- 파이썬에서 None, 숫자 0, 데이터가 없는 벡터 데이터 => False로 간주, 나머지 데이터는 True

print(matrix)
print(ar)

#브로드캐스트 연산

#numpy와 ndarray와 논리연산을 수행하면 bool의 배열이 만들어짐
print(ar==3)

#인덱스의 bool 배열을 대입하면 True인 데이터만 추출
print(ar[ar%2 ==1])

#홀수이거나 4의 배수인 데이터만 골라내기
print(ar[(ar % 2 == 1) | (ar % 4 == 0)])
  • 차원이 다른경우 차원을 순회하면서 연산 수행
  • 연산은 구조를 맞춰놓고 해야 한다.
[[0 1 2 3 4]
 [5 6 7 8 9]]
[0 1 2 3 4 5 6 7 8 9]
[False False False  True False False False False False False]
[1 3 5 7 9]
[0 1 3 4 5 7 8 9]

 

 

 

 

12. 연산

1) 포함 여부를 판단하는 연산

- in: 데이터가 포함돼있으면 True, 아니면 False

- not in: 데이터가 포함돼있으면 True, 아니면 False

 

 

2) 배열의 모든 요소에 함수 적용

- numpy.vectorize(함수)를 이용해서 벡터화된 함수 생성

  • 벡터화된 함수에 numpy의 배열을 대입하면 함수의 결과를 다시 배열로 만들어서 리턴
  • 함수는 반드시 리턴을 해야 한다. 
  • list에서 사용하는 map()함수와 동일한 작업
matrix = np.array([1, 2, 3])
print(matrix)

#요소의 제곱을 수행하는 람다 함수
square_lambda = lambda x : x * x

#함수를 배열의 모든 요소에 적용해서 결과를 배열로 만들기
vectorized_func = np.vectorize(square_lambda)

result = vectorized_func(matrix)
print(result)

🤍

[1 2 3]
[1 4 9]

 

데이터가 None 이면 0 100보다 크면 100 으로 한 결과 배열 생성
#None을 걸러내는 작업을 먼저 해야 합니다.

ar = np.array([80, 70, 80, None, 120])

def preprocessing(data) -> int:
    if data == None:
        return 0
    elif data > 100:
        return 100
    else:
        return data
    
vec_func = np.vectorize(preprocessing)
print(vec_func(ar))

🤍

[ 80  70  80   0 100]

 

 

3) 배열의 전치와 축 변경

- 전치: 행과 열 반전

- 축 변경: 3차원 이상에서 데이터의 축 순서를 바꾸는 것

- 머신러닝 등 데이터의 증강(늘리는 것)이나 다양한 패턴을 찾을 때 사용

- 행렬은 T라는 속성으로 전치 가능

- numpy의 배열에는 transpose 메소드에서 축 순서를 설정하면 축 순서를 변경

  • 축의 순서는 기본적으로 행(0), 열(1), 면(2)...

- 실제적으로 3차원 이상의 데이터는 차원 변경을 잘 하지 않음

  • 3차원 이상의 차원 변경은 애니메이션에서 수행
#행렬의 전치 - 축변경
original = np.array([[1, 2, 3], [4, 5, 6]])

print(original)
print(original.T)
print(original.transpose(1, 0))

🤍

[[1 2 3]
 [4 5 6]]

[[1 4]
 [2 5]
 [3 6]]

[[1 4]
 [2 5]
 [3 6]]

 

 

4) 랜덤

- 머신러닝 · 데이터 분석에서 샘플데이터 추출할 때 사용

  • 정수인 seed 를 설정해서 난수표를 만들고 순서대로 데이터를 가져오는 것
  • seed 값을 실시간으로 변경
    • 프로그래밍 언어 별로 seed 값이 실시간으로 변경되는 언어가 있고, 고정된 언어가 있음
    • 머신러닝에서는 seed를 고정한다.

메소드

numpy.random.seed(seed)
  • 시드 설정
  • seed: 시드 번호
numpy.random(데이터 개수)
  • 0.0 ~ 1.0 사이의 숫자를 개수만큼 추출
numpy.randint(최소, 최대, 데이터 개수)
  • 최소와 최대 사이에서 개수만큼 정수를 추출
numpy.rand(데이터 개수)
  • 균등 분포에서 데이터 개수만큼 추출
numpy.randn(데이터 개수)
  • 표준 편차가 1, 평균이 0인 정규 분포에서 데이터 개수만큼 추출
numpy.binomial(n, p, size)
  • 이항분포에서 추출.
  • n: 0부터 나올 수 있는 숫자까지의 범위
  • p: 확률
  • size: 개수
numpy.random.permutation(x)
  • 정수를 설정해서 랜덤한 배열을 생성
numpy.random.shuffle(x)
  • 랜덤한 배열을 생성
numpy.random.choice()
  • 배열에서 복원 추출

 

- 복원 추출:  이번에 생성된 데이터를 그룹에 다시 포함시켜 추출하는 것

- 비복원 추출:  생성된 데이터를 그룹에 포함시키지 않고 추출

 

파이썬은 실행될 때 seed를 설정하지 않으면 seed를 실행 시간을 기준으로 설정

#랜덤한 숫자 추출의 개념

#seed를 설정하지 않으면 실행 시간을 기준으로 seed 가 설정되므로 
#실행할 때 마다 다른 숫자가 리턴
result = np.random.normal(size = 5)
print(result)

#seed를 42로 고정하면 실행할 때 마다 동일한 데이터가 리턴
np.random.seed(seed=42)
result = np.random.normal(size = 5)
print(result)

🤍

[ 0.30064545 -1.12631817  0.86785173  0.76195105  0.9716669 ]
[ 0.49671415 -0.1382643   0.64768854  1.52302986 -0.23415337]

 

 

 

13. Numpy 메소드

1) 메소드 분류

- Unary Function: 매개변수가 1개인 경우

- Binary Function: 매개변수가 2개인 경우

 

 

2)기본 통계 함수

- sum: 합계

- prod: 곱
- nanprod: None 을 1로 간주하고 곱
- nansum: None을 0으로 간주하고 합

- mean: 평균
- median: 중앙값
- max: 최대
- min: 최소

- std: 표준편차
- var: 분산

- percentile: 백분위수

  • axis: 2차원 배열에서 행이나 열방향 과 관련된 옵션
  • ddof: 표준 편차 와 분산은 ddof를 1로 설정해서 비편향 표준 편차 와 분산을 계산.
  • 자유도는 다른 데이터의 값이 결정되면 자동으로 값이 결정되는 데이터의 개수
#4행 3열짜리 배열 생성
matrix = np.arange(1, 13).reshape((4, -1))
print(matrix)

#전체 데이터의 합계
print(np.sum(matrix))

#열의 합계
print(np.sum(matrix, axis=0))

#행의 합계
print(np.sum(matrix, axis=1))

🤍

[[ 1  2  3]
 [ 4  5  6]
 [ 7  8  9]
 [10 11 12]]
78
[22 26 30]
[ 6 15 24 33]

 

 

 

- 피보나치 수열

  • 첫번째 와 두번째는 무조건 1 이고 세번째부터는 앞 2개의 항의 합으로 만들어지는 수열
  • 1, 1, 2, 3, 5, 8, 13, 21, 34, 55...
#피보나치 수열

def fibo(n: int) -> int:
    if n == 1 or n == 2:
        return 1
    else:
        return fibo(n-1) + fibo(n-2)
print(fibo(6))

def norecursion_fibo(n:int) -> int:
    n1 = 1
    n2 = 1
    v = 1
    for i in range(3, n+1):
        v = n1 + n2
        n2 = n1
        n1 = v
    return v
print(norecursion_fibo(6))

8

8

 

- 표준 편차와 분산

  • 표준 편차 와 분산은 ddof 옵션에 따라 값이 다르게 나옴
  • 표준 편차 와 분산은 평균이 결정되고 전체 데이터 개수 - 1 만큼의 값을 알게되면
  • 나머지 1개의 값은 자동으로 결정된다.
  • 자동으로 결정되는 값을 빼고 계산하거나 포함시켜 계산할 수 있다.
  • 이 옵션이 ddof 옵션
matrix = np.arange(1, 13).reshape((4, -1))
print(np.var(matrix))
print(np.var(matrix, ddof=1))

🤍

11.916666666666666
13.0

 

 

3) 기술 통계

- argmin, argmax: 최소값 과 최대값의 인덱스

- cumsum: 누적합

- cumprod: 누적곱

- diff: 차분은 이전 값을 뺀 값, n 이라는 옵션으로 차수를 설정할 수 있습니다.

 

 

4) 소수 관련 함수

- 소수를 버리거나 올림하거나 반올림해주는 함수를 제공

 

 

5) 숫자 처리 관련 함수

- 절대값, 제곱, 제곱근, 부호 판별 함수를 제공

 

 

6) 논리 함수

- numpy.isnan(배열): 배열에 None, NULL 등이 포함 여부를 리턴

- numpy.nanNone을  표현

- logical_not( ): 조건에 맞지 않는 데이터 인지 여부를 리턴

#배열 생성
ar = np.array([10, 2, 3, 4, np.nan, 32, 42])

#배열에 None 데이터가 있는지 확인
print(np.isnan(ar)) #결측치 확인

#결측치를 제외하고 가져오기
result = ar[np.logical_not(np.isnan(ar))]
print(result)

#결측치를 제외하고 가져오기 - 결측치를 제거하지 않고 수행하면 nan 이 포함됩니다.
#ar을 가지고 수행하면 np.nan 이 포함되고 result를 가지고 수행하면 np.nan이 제거
result = result[np.logical_not(result > 10)]
print(result)

ar = np.array([2, 5, 23, 34, 21, 42, np.nan, 25])
print(ar)
#3의 배수이거나 4의 배수인 데이터만 추출 np.nan을 제거
temp = ar[np.logical_not(np.isnan(ar))]
result = temp[(temp % 3 == 0) | (temp % 4 ==0)]
print(result)

🤍

[False False False False  True False False] #결측치 확인
[10.  2.  3.  4. 32. 42.] #결측치 제외한 값
[10.  2.  3.  4.]
[ 2.  5. 23. 34. 21. 42. nan 25.]
[21. 42.]

 

 

7) 2개의 배열로 작업하는 함수

- add, subtract, multiply, divide, floor_divide(몫만 가져오기), mod

- power

- maximum, fmax, minimum, fmin

  • f 가 붙는 함수는 np.nan을 무시

- greater, greater_equal, less, less_equal, equal, not_equal: 결과가 bool 의 배열

- logical_and, logical_or, logical_xor

  • eXclusive OR(배타적 논리합, 같으면 False 다르면 True, True 와 True 또는 False 와 False 이면 False 가 되고 True 와 False로 데이터가 다르면 True 가 되는 연산)

- where(bool 배열, True 일 때 선택할 배열, False 일 때 선택할 배열)

 

 

8) 집합 관련 함수

- unique(): 중복을 제거

  • 범주형에서 이상치를 찾는 데 사용

- intersect1d(): 교집합

- union1d(): 합집합

- in1d(): 데이터의 존재 여부를 bool 배열로 리턴

- setdiff1d(): 차집합

- setxor1d(): 한쪽에만 존재하는 데이터의 집합

#아래 데이터는 1, 2, 3, 4 중에 하나를 선택하는 범주형 데이터의 집합
#이상한 값이 있는지 확인
ar = np.array([2, 1, 3, 4, 5, 1, 2, 3])
print(np.unique(ar))

🤍

[1 2 3 4 5]

 

 

9) ndarray.sort()

  • numpy sort는 리턴,  ndarray sort는 리턴X
  • 내림차순 정렬은 numpy의 sort를 이용
  • 2차원 배열은 numpy에서는 sort 를 잘 사용하지 않음 - (데이터의 인덱스가 깨짐)
ar = np.array([2, 1, 3, 4, np.nan])
print(ar.sort())
print(ar)
print(np.sort(ar)[::-1])
matrix = np.array([[1, 3, 2, 4], [9, 4, 1, 8]])
matrix.sort(axis = 0)
print(matrix)

🤍

None #리턴X
[ 1.  2.  3.  4. nan]
[nan  4.  3.  2.  1.]
[[1 3 1 4]
 [9 4 2 8]]

 

 

 

10)배열 분할

- numpy.split: 배열 그리고 개수 와 axis 옵션을 설정

 

 

 

11) 배열 결합

- numpy.concatenate ( 배열 2개, axis )

- hstack, vstack, dstack, stack, r_, c_, tile 함수

 

* hstack, vstack 자주 씀

테이블의 데이터가 너무 많아서 조회가 느린 경우 테이블을 분할해서 저장할 수 있는데
열을 분할하거나 행을 분할(Partition)한다.

열 단위로 분할할 때, 기본키를 양쪽 테이블에 갖게 하고 자주 사용하는 열과 자주 사용하지 않는 열로 나눈다.
1:1의 관계를 갖는 구조.

데이터베이스에서는 조인을 통해 하나의 테이블로 변환하는데
hstack은 행의 개수가 같을 때 옆으로 갖다 붙이자! 
vstack은 열의 개수가 같을 때 위아래로 갖다 붙이자! 

 

hstack: 행의 개수가 같은 두개 이상의 배열을 옆으로 연결하는 함수

vstack:  열의 개수가 같은 두개 이상의 배열을 상하로 연결하는 함수

dstack: 차원을 늘려서 결합

stack: dstack 함수를 확장한 것으로 차원의 위치(axis)를 직접 설정

-------------------------------------------------------------

r_: hstack과 유사한 예전 API

c_: vstack과 유사한 예전 API

tile: 배열을 반복해서 하나의 배열을 만드는 것     tile(배열, 반복횟수)

 

#htstack
ar = np.array([[1, 2, 3], [4, 5, 6]])
print(ar)
br = np.array([[11, 22, 33], [44, 55, 66]])
print(br)
print(np.hstack([ar, br]))
print(np.vstack([ar, br]))
print(np.dstack([ar, br]))

🤍

[[1 2 3]
 [4 5 6]]
 
[[11 22 33]
 [44 55 66]]
 
[[ 1  2  3 11 22 33]
 [ 4  5  6 44 55 66]]
 
[[ 1  2  3]
 [ 4  5  6]
 [11 22 33]
 [44 55 66]]
 
[[[ 1 11]
  [ 2 22]
  [ 3 33]]

 [[ 4 44]
  [ 5 55]
  [ 6 66]]]

 

 

 

 

14. 배열의 저장과 불러오기

1) 배열을 저장

numpy.save('파일 경로', 배열)
  • 파일의 확장자는 관습적으로 npy 를 사용

2) 배열의 데이터 불러오기

numpy.load('파일 경로')

3) 여러 개의 배열을 저장

numpy.savez('파일 경로', 이름 = 데이터, ...

이렇게 저장한 데이터는 불러올 때 numpy.load('파일 경로', '이름') 사용

4) 머신 러닝 중 자주 사용하는 데이터가 있다면 npy 로 저장한 후 호출하는 것이 효율적

 

 

 

 

'Python' 카테고리의 다른 글

[Python] 크롤링 - 기사 스크래핑  (0) 2024.02.14
[Python] Pandas  (1) 2024.02.08
Day10. REST API  (0) 2024.01.26
Day9. 웹 서버 만들기  (1) 2024.01.24
Day8. 가상환경 만들기  (1) 2024.01.19