Data Types for Data Science in Python 是 DataCamp 中 Python Programmer Career Track 的第二门课程。
本节课可以学习到:
- 基础数据类型的运用,包括列表、字典、元组等
- 对于 collections 模块中进阶数据类型的使用
- 通过 datetime 及第三方的 pytz 与 pendulum 等库处理日期、时间与时区转换
目录
基础数据类型
List
- 按照添加顺序维护数据
- Mutable(可变的)
- 支持索引
- 使用加法运算符可以合并列表
- 使用 .extend() 方法追加参数中的列表至实例自身(self)的末尾
- 使用 .index() 方法定位列表中数据的索引位置
- 使用 .pop() 移除并返回指定位置上的元素
- 使用 for in 循环来迭代列表元素
- 使用 .sorted() 方法返回新的排序后列表
cookies = ['chocolate chip', 'peanut butter', 'oatmeal', 'sugar'] cookies.append('Tirggel') print(cookies[2]) # oatmeal cakes = ['strawberry', 'vanilla'] desserts = cookies + cakes print(desserts) # ['chocolate chip', 'peanut butter', 'oatmeal', 'sugar', 'Tirggel','strawberry', 'vanilla'] position = cookies.index('sugar') # 3 name = cookies.pop(position) # name = 'sugar' for cookie in cookies: print(cookie) sorted_cookies = sorted(cookies)
Tuple
- 按顺序维护数据
- 可索引
- Immutable(不可变的)
- Pairing(成对的)
- Unpackable(可解包的)
- 使用 zip() 函数将多个列表纵向缝合为元素列表
- 通过多变量赋值解包元组
- 使用 enumerate() 函数将可遍历的数据对象组合为 (下标, 数据) 元组的索引序列
- 使用 () 或末尾多余逗号形成元素(后者支持单元素元组)
in_cookies = ['Punjabi', 'Fruit Cake Rusk'] us_cookies = ['Chocolate Chip', 'Brownies'] top_pairs = zip(us_cookies, in_cookies) # [('Chocolate Chip', 'Punjabi'), ('Brownies', 'Fruit Cake Rusk')] us_num_1, in_num_1 = top_pairs[0] # us_num_1 = 'Chocolate Chip', in_num_1 = 'Punjabi' for us_cookie, in_cookie in top_pairs: print(in_cookie) print(us_cookie) for idx, item in enumerate(top_pairs): us_cookie, in_cookie = item print(idx, us_cookie, in_cookie) # (0, 'Chocolate Chip', 'Punjabi') # (1, 'Brownies', 'Fruit Cake Rusk') item = ('vanilla', 'chocolate') item2 = 'butter', # item2 = ('butter',)
Set
- 元素的唯一标识
- 无序的
- 可变的
- 数学中集合论的 Python 实现
- 使用 set(iterable) 构造器从列表生成集合
- 使用 .add() 方法添加单个元素
- 使用 .update() 方法融合其他列表或集合
- 使用 .discard() 移除指定内容元素
- 使用 .pop() 随机移除元素(实际上是移除哈希序最左元素,当集合为空时会有 KeyError)
- 使用 .union() 返回两个集合的交集
- 使用 .intersection() 返回两个集合的并集
- 使用 .intersection() 返回两个集合的差集(self – arg)
cookies_eaten_today = ['chocolate chip', 'peanut butter', 'chocolate chip', 'oatmeal cream', 'chocolate chip'] types_of_cookies_eaten = set(cookies_eaten_today) # types_of_cookies_eaten = set(['chocolate chip', 'oatmeal cream', 'peanut butter']) types_of_cookies_eaten.add('biscotti') cookies_hugo_ate = ['chocolate chip', 'anzac'] types_of_cookies_eaten.update(cookies_hugo_ate) types_of_cookies_eaten.discard('biscotti') types_of_cookies_eaten.pop() cookies_jason_ate = set(['chocolate chip', 'oatmeal cream', 'peanut butter']) cookies_hugo_ate = set(['chocolate chip', 'anzac']) cookies_jason_ate.union(cookies_hugo_ate) # set(['chocolate chip', 'anzac', 'oatmeal cream', 'peanut butter']) cookies_jason_ate.intersection(cookies_hugo_ate) # set(['chocolate chip']) cookies_jason_ate.difference(cookies_hugo_ate) # set(['oatmeal cream', 'peanut butter']) cookies_hugo_ate.difference(cookies_jason_ate) # set(['anzac'])
Dictionary
- 以键/值对的方式维护数据
- Nestable(可嵌套的)
- Iterable(可迭代的)
- 使用 dict() 或 {} 生成字典
- 使用键作为索引获取对应值
- 当试图访问的键不存在时,会抛出 KeyError
- 使用 .get() 安全地访问以避免异常,不存在时返回 None 或指定返回内容参数
- 使用 .keys() 方法得到 dict_keys 类型的类数组对象
- 使用 .update() 方法从其他字典或元组中更新值到指定键
- 使用 del 删除指定键值对引用(对象后续被 GC 自动回收)
- 使用 .pop() 方法移除指定键值对
- 使用 .items() 方法返回可迭代的 dict_items 类型对象
- 使用 in 来判断字典中是否有该键存在
art_galleries = {} for name, zip_code in galleries: art_galleries[name] = zip_code for name in art_galleries: print(name) art_galleries.get('Louvre') # None art_galleries.get('Louvre', 'Not Found') # 'Not Found' art_galleries.keys() # dict_keys(['10021', '10013', '10001', '10009', '10011', '10022', ...: '10027', '10019', '11106', '10128']) galleries_11234 = [('A J ARTS LTD', '(718) 763-5473'), ('Doug Meyer Fine Art', '(718) 375-8006'), ('Portrait Gallery', '(718) 377-8762')] # Tuple into dictionary value art_galleries['11234'].update(galleries_11234) print(art_galleries['11234']) # {'Portrait Gallery': '(718) 377-8762', 'A J ARTS LTD': '(718) 763-5473', 'Doug Meyer Fine Art': '(718) 375-8006'} del art_galleries['11234'] galleries_10310 = art_galleries.pop('10310') for key, value in art_galleries.items(): print(key) print(value) '11234' in art_galleries # False if'10010'in art_galleries: print('I found: %s' % art_galleries['10010']) else: print('No galleries found.') # I found: {'Nyabinghi Africian Gift Shop': '(212) 566-3336'}
CSV
- 一些 CSV 的第一行有表头
- 需要引入 Python 的 csv 模块
- open() 函数可以指定打开模式(’r’ 或 ‘w’)返回可访问的 csv 变量
- csv.reader() 函数接受 csv 变量,返回逐行列表
- .close() 方法关闭 csv 变量
- csv.DictReader() 函数接受 csv 变量,返回逐行字典,键为表头值为该行内容
# NAME,TEL,ADDRESS1,ADDRESS2,CITY,ZIP (表头) # O'reilly William & Co Ltd,(212) 396-1822,52 E 76th St,,New York,10021 (正文) import csv csvfile = open('ART_GALLERY.csv', 'r') for row in csv.reader(csvfile): print(row) # ['NAME', 'the_geom', 'TEL', 'URL', 'ADDRESS1', 'ADDRESS2', 'CITY', 'ZIP'] # ["O'reilly William & Co Ltd",'POINT (-73.96273074561996 40.773800871637576)'(212) 396-1822', '52 E 76th St', '', 'New York', '10021'] csvfile.close() csvfile = open('ART_GALLERY.csv', 'r') for row in csv.DictReader(csvfile): print(row) # OrderedDict([('NAME', 'Odyssia Gallery'), # ('the_geom', 'POINT (-73.96269813635554 40.7618747512849)' # ('TEL', '(212) 486-7338'), # ('URL', 'http://www.livevillage.com/newyork/art/odyssia-gallery.html'), # ('ADDRESS1', '305 E 61st St'), # ('ADDRESS2', ''),('CITY', 'New York'), ('ZIP', '10021')]) csvfile.close()
collections 模块
简介
- 标准库的一部分
- 提供了进阶的数据容器
Counter
- 使用 Counter() 构造器生成空白 Counter 对象或指定可迭代对象、字典对象以生成 Counter 对象
- Counter 的实质:用于计数的特殊字典 {key: 出现次数}
- 使用 .most_common(n) 方法获取前 n 个最频繁元素及次数的元组
from collections import Counter nyc_eatery_count_by_types = Counter(nyc_eatery_types) print(nyc_eatery_count_by_type) # Counter({'Mobile Food Truck': 114, 'Food Cart': 74, 'Snack Bar': 24,'Specialty Cart': 18, 'Restaurant': 15, 'Fruit & Vegetable Cart': 4}) print(nyc_eatery_count_by_types.most_common(3)) # [('Mobile Food Truck', 114), ('Food Cart', 74), ('Snack Bar', 24)]
defaultdict
- 使用 defaultdict(type) 来生成默认为 type 类型的字典
- 当访问的键不存在时,默认使用该类型的初始化方案
from collections import defaultdict eatery_contact_types = defaultdict(int) for eatery in nyc_eateries: if eatery.get('phone'): eatery_contact_types['phones'] += 1 if eatery.get('website'): eatery_contact_types['websites'] += 1
OrderedDict
- Python 3.6 前字典无序,3.6 后默认字典是有序的
- 使用 .popitem() 方法弹出并返回最后一个元素(最晚插入的)
- 使用 .popitem(last=False) 参数弹出并返回第一个元素(最早插入的)
from collections import OrderedDict nyc_eatery_permits = OrderedDict() print(list(nyc_eatery_permits.items())[:3] print(nyc_eatery_permits.popitem()) print(nyc_eatery_permits.popitem(last=False))
namedtuple
- 每个特定列都有自己的名字
- 可以作为 pandas 中 DataFrame 的替代
- 使用 namedtuple(‘tuplename’, [fieldsname]) 来返回一个像类的 namedtuple 对象
- 可以通过点操作符访问特定域的值
from collections import namedtuple Eatery = namedtuple('Eatery', ['name', 'location', 'park_id', 'type_name']) eateries = [] details = Eatery(eatery['a'], eatery['b'], eatery['c'], eatery['d']) eateries.append(details) print(eateries[0]) # Eatery(name='Mapes Avenue Ballfields Mobile Food Truck', location='Prospect Avenue, E. 181st Street', park_id='X289', type_name='Mobile Food Truck') print(eateries[0].name) print(eateries[0].park_id) print(eateries[0].location)
日期、时间与时区
datetime
- Python 标准库中的模块
- datetime 模块中提供 datetime 类型(从 datetime 导入 datetime)
- 使用 datetime.strptme() 函数将字符串 parse 为 datetime 对象
- %d 充零二位日、%m 充零二位月、%Y 四位年
- 具体规格化约定见 Python documentation
- 使用 .strptme(format) 方法将 datetime 对象按照 format 规格字符串约定转换为字符串
- 使用 .isoformat() 方法将 datetime 对象转换为 ISO 标准字符串
- 使用点运算符访问 datetime 对象中 day, month, year, hour, minute, second 等成员
- 使用 datetime.now() 函数获得当前本地日期时间对象
- 使用 datetime.now() 函数获得当前 UTC 日期时间对象
from datetime import datetime parking_violations_date = '06/11/2016' date_dt = datetime.strptime(parking_violations_date, '%m/%d/%Y') print(date_dt) # 2016-06-11 00:00:00 date_dt.strftime('%m/%d/%Y') # '06/11/2016' date_dt.isoformat() # '2016-06-11T00:00:00' print(date_dt.day) # 11 print(datetime.now()) print(datetime.utcnow())
时区 与 pytz
- Naive datetime 对象没有时区数据
- Aware datetime 对象包含时区数据与夏令时等
- 使用 pytz 模块向 datetime 对象中指定时区数据
- 使用 .astimezone() 方法进行便捷的时区转换
- 注:目前似乎正在转为使用 dateutil,pytz 的流行度有待进一步考察
from pytz import timezone record_dt = datetime.strptime('07/12/2016 04:39PM', '%m/%d/%Y %H:%M%p') ny_tz = timezone('US/Eastern') la_tz = timezone('US/Pacific') ny_dt = record_dt.replace(tzinfo=ny_tz) la_dt = ny_dt.astimezone(la_tz) print(ny_dt) # 2016-07-12 04:39:00-04:00 print(la_dt) # 2016-07-12 01:39:00-07:00
timedelta
- timedelta 用来表示时间差
- 可以与一个 datetime 对象进行加减运算
- 将两个 datetime 对象相减得到 timedelta 对象作为时间差
from datetime import timedelta flashback = timedelta(days=90) print(record_dt) # 2016-07-12 04:39:00 print(record_dt - flashback) # 2016-04-13 04:39:00 print(record_dt + flashback) # 2016-10-10 04:39:00 time_diff = record_dt - record2_dt type(time_diff) # datetime.timedelta print(time_diff) # 0:00:04
pendulum 库
- Pendulum Documentation
- 使用 pendulum.parse() 函数将字符串 parse 为 pendulum datetime 对象,使用 tz= 参数指定时区,当字符串不严格按照标准时使用 strict=False 参数 fall back 至 dateutil 的 parser
- 使用 .in_timezone(tz) 方法将对象转换为时区 tz
- 使用 pendulum.now(tz) 获取当前 tz 时区的时间
- 使用减法得到类似 timedelta 的 pendulum 类型 Period
- 使用 .diff() 方法得到 Period
- 使用 .in_days(), .in_hours() 等等或 .in_words() 方法将 Period 以相应月、日、时的整型格式或恰当的文本表示
import pendulum occurred_dt = pendulum.parse(occurred, tz='US/Eastern') # <Pendulum [2016-06-11T14:38:00-04:00]> print(violation_dt.in_timezone('Asia/Tokyo')) # 2016-06-12T03:38:00+09:00 print(pendulum.now('Asia/Tokyo')) # <Pendulum [2017-05-06T08:20:40.104160+09:00]> diff = violation_dts[3] - violation_dts[2] <Period [2016-04-26T07:09:00-04:00 -> 2016-04-23T07:49:00-04:00]> print(diff.in_words()) # 2 days 23 hours 20 minutes print(diff.in_days()) # 2 # diff 计算是考虑时区的
评论