动手学数据分析学习笔记-Ch1

本文为Datawhale8月组队学习——动手学数据分析课程的系列学习笔记。

Datawhale-动手学数据分析

数据来源

Kaggle小白入门首选练手项目——Kaggle-泰坦尼克号存活率

Ch1 数据加载与探索性分析

数据分析包含数据加载、探索性数据分析、数据清洗、特征处理、数据建模、模型评估等多个步骤。在进行数据分析之前,需要载入我们获取的数据集,并通过探索性分析初步了解数据的结构、组成和特征。

Ch1-1 数据载入与初步观察

数据载入

载入函数

对于常见的数据文件类型(.csv/.xlsx/.tsv/...),通常使用第三方库pandas载入数据。

pandas中,常见的载入数据文件函数有以下几种:

  • read_table():可以读取常见的分隔符定界文件,sep=''参数用于选择分隔符,若该参数为空,则不予分隔(所有数据集中在一列中),支持正则表达式。
  • read_csv():读取逗号分隔符文件(.csv),同样有sep=''参数,默认为逗号(,)
  • read_excel():读取Excel文件(.xlsx),相比前两种函数,对于含有多个工作簿的excel文件,一般需要输入参数sheetname='',不输入则默认为第一张工作簿

以上函数默认返回DataFrame对象,对于excel,当读入多个工作簿(如:[1,2])时,返回一个dict对象,每个元素的值都是一个DataFrame对象。

除此之外,pandas还支持读取很多其他的文件格式(如:JSON、pickle、SQL以及常见统计软件STATA/SPSS的输出格式),具体参考pandas官方文档-IO

相对路径与绝对路径

查看当前所在路径的命令:os.getcwd()

使用前要导入python自带的输入输出库os

相对路径表述:

符号 含义
/ 根目录
./ 当前目录
../ 上一级目录
../../ 上两级目录,多级目录以此类推

逐块读取

当数据文件过大,包含数据量过多时,为了防止一次性读入所有数据服务器内存占用过大,难以处理,pandas的载入函数提供了chunksize参数以实现数据的逐块读取,该参数使得函数通过分多次将文件数据读入内存,降低了内存占用。

# 逐块读取
chunks = pd.read_csv('../../Titanic-kaggle/data/train.csv', chunksize = 1000)
print(type(chunks))
for piece in chunks:
    print(type(piece))
    print(len(piece))

当使用chunksize参数时,载入函数将返回TextFileReader对象,该对象可以使用for语句遍历,其中每个元素都是一个包含指定行数的DataFrame对象,此时就可以在循环中实现对各块数据的批处理。

设定列名和索引

  • 可以在读取数据文件时利用参数names=[]header=0index='index_col_name'设定。
  • 也可以在后期通过方法df.set_index()df.rename(colomns={})或借助属性df.columnsdf.index暴力修改

Tips:

  • 当使用read_csv()的names参数修改列名时,其实质是在原表基础上加上给定的列名,此时header会取Null;若不使用names参数,header默认取0。因此,设定列名时,应当使用header=0来表明原数据有列名,且位于第一行,这样才能实现列名的替换。
  • df.set_index()中包含drop参数,该参数应设定为True,表示删除现有索引列,否则当前索引行将变为普通列加入现有DataFrame
# 方法1:读取时设定
names = ['乘客ID','是否幸存','乘客等级(1/2/3等舱位)','乘客姓名','性别','年龄','堂兄弟/妹个数','父母与小孩个数','船票信息','票价','客舱','登船港口']
# header属性用于设置列名取自哪一行,指定names时应当设为0,否则会多出原标题行
df = pd.read_csv('../../Titanic-kaggle/data/train.csv',names= names,index_col='乘客ID',header=0)

# 方法2:更改表头和索引
column_names = {'PassengerId':'乘客ID','Survived':'是否幸存','Pclass':'乘客等级(1/2/3等舱位)','Name':'乘客姓名','Sex':'性别','Age':'年龄','SibSp':'堂兄弟/妹个数','Parch':'父母与小孩个数','Ticket':'船票信息','Fare':'票价','Cabin':'客舱','Embarked':'登船港口'}
df.rename(columns = column_names, inplace = True)
df.set_index('乘客ID', drop = True, inplace = True)

初步观察

概览数据基本信息

查看数据的基本信息主要用到以下一些方法和属性:

方法/属性 用途
df.shape 以元组形式返回dataframe对象的行列数
df.size 以整数形式返回dataframe对象的元素数(不包含索引/表头)
df.colomns 输出所有的列名
df.head(n)/df.tail(n) 查看dataframe前n行/后n行
df.info() 输出关于数据的基本描述,包含行数、各列的列名、数据类型、非空值数以及占用内存。其中verbose参数可以用于选择长/短两种描述
df.describe() 输出各列的描述性统计信息,可以迅速查看数据的统计特征(Series也有该方法)
df.value_counts() 返回一个包含不同列各值数的Series(Series也有该方法)

判断缺失值

用到两个方法:

  • df.isnull():返回一个判断是否为空的DataFrame,若为空则为True,反之为False
  • df.isnotnull():返回一个判断是否为非空的DataFrame,若为非空则为True,反之为False

数据输出

与读取的几个函数类似,语法基本一致,区别在于数据输出使用的是对象的方法,而非函数:

  • df.to_csv()
  • df.to_excel()

Notes:

  • 查阅API文档,发现没有to_table()方法,很神奇的是pandas自带了to_latex()和to_markdown()方法
  • 一般会设置编码方式参数encoding='utf-8',当元素含有中文时,若出现乱码,可以尝试使用utf_8_sig或gbk格式

Ch1-2 pandas基础

数据类型

pandas最基本的两种数据类型:DataFrame和Series。此外还需要了解numpy中的基本数据类型——ndarray。

  • ndarray:numpy中最基础的数据类型,多维数组对象,本质上就是一个n维矩阵。只能存放同类型数据。

  • Series:主要由两部分组成,index 和 values。index可以是任意类型,不一定非是数字类型,values是存放的内容,是一个1维的ndarray

  • DataFrame: 可以看作由多列Series组成,也可以看作由多行Series组成。或者可以看作columns, index, values这三部分组成。

    • columns:列名,默认也是数字升序,可以是任意类型
    • index:行名,默认数字升序,可以是任意类型
    • values:存放的内容,是一个2维的ndarray

简单来说,Series实质是一维数组,DataFrame则是多个Series组成的二维数组,当然二者相比ndarray要多出一些如索引、列名等的属性,可以看作ndarray的包装。

官方文档里写到二者的关系:

DataFrame can be thought of as a dict-like container for Series objects.(DataFrame可以看作一个类似dict的用于盛放Series的容器)

构造方法

Series

  • List + index_list
  • Dict
  • ndarray + index_list

使用 List 进行创建,自动添加0开始的行标签(索引)

Series 创建时若不注明 name 参数,相当于此列没有列名

## Series的创建

# 01 使用list
sdata = [2000,500,1000,4000]
example_1 = pd.Series(sdata)

# 02 使用dict
sdata = {'thu':1,'zju':3,'hust':8,'whu':9,'sysu':10}
example_1 = pd.Series(sdata)
example_1

# 03 使用np.ndarray
sdata = np.random.rand(10)*20
example_1 = pd.Series(sdata,index=['a','b','c','d','e','f','g','h','i','j'],name='random')

无论是字典,列表还是元组,都可以构建Series。只不过,dict自带index,而list,tuple要专门定义index(也就是每一行的行名)。系统默认的index为0,1,2,3…

DataFrame

DataFrame的创建方法有很多种,这里只列了其中几种,具体可以参考创建DataFrame的7种方法

  • DataFrame(Dict):字典内可以为列表/字典/Series
  • DataFrame.from_dict(Dict)
  • DataFrame(np.ndarray)

可以添加indexcolumns参数,不附带index参数则索引默认为自然数序列

## DataFrame的创建

# 01 使用dict,其中key为list(亦可字典套字典)
ddata = {'country':['US','Brazil','India','Europe','South Africa'],'confirmed':[5481795,3407354,2702742,930276,592744],'death':[171799,109888,51797,15836,12264]}
example_2 = pd.DataFrame(ddata)
print(example_2)
print('--------------')

# 02 from_dict()静态方法
example_2 = pd.DataFrame.from_dict(ddata)
print(example_2)
print('--------------')

# 03 二维数组
ddata = np.array([4,1,4,5,5,2,3,5,6,3,3,4,6,1,9]).reshape(5,3)
example_2 = pd.DataFrame(ddata, index=list('abcde'), columns=['four', 'one', 'three'])
print(example_2)

有些时候我们只需要选择dict中部分的键当做DataFrame的列,那么我们可以使用columns参数,例如我们只选择country和death列:

pd.DataFrame(data = ddata,columns=['country','death'])

数据操作

列选取
  • 作为属性选取:df.Cabin
  • 使用[]运算符,其实现方式是实现类的_getitem_魔术方法:df['Cabin']

很多时候会截取所有数据的一部分进行后续操作和分析,这个时候很可能需要用到reset_index(drop=True)方法来重新生成数字索引

行/列删除
  • df.drop():axis参数默认为0,即删除行,要改成列应改为1。或者忽略axis直接使用columns参数
  • del df['']:del操作符,只能用于列

很多操作方法都有inplace参数,inplace为True表示直接在原对象上进行改动,默认为False,返回一个新对象

数据筛选

Pandas有自带的访问器操作,lociloc

iloc基于位置(数字索引)选择,通过其在 DataFrame 中的数字排位进行访问。

loc 则通过自定义标签进行提取,该方法聚焦于数据的标签(索引)而不是位置(数字索引)。

## iloc
# 取出第一行的内容
df.iloc[0]
# 取出第一列的内容
df.iloc[:, 0]
# 也可以采用内嵌列表的方式
df.iloc[[0, 1, 2], 0]

## loc
# 选中第一行的Sex列对应的单元格
df.loc[0, 'Sex']
# 选中Pclass, Name, Sex这三列的数据
df.loc[:, ['Pclass', 'Name', 'Sex']]

可以使用负数来进行选择:

# 选择倒数五行的内容
df.iloc[-5:]

Notes:

  • 二者的使用方法都是使用中括号[]而不是小括号()

  • lociloc 均采用了先选行后选列的语法,这与传统的 python 语法相反二者的区别

  • iloc 的区间满足前闭后开,而 loc则满足前闭后闭。因而当我们遇到 String 类型索引,需要按照索引进行选取内容时,我们往往是希望取出区间内所有的元素,此时更好的方法是使用 loc

特定条件筛选

loc 访问器操作和[]运算符可以根据输入的逻辑值Series来筛选显示的行,将自动从中选取逻辑值为True的行。

一些常见的逻辑相关符号和方法:

  • 用于连接多个条件的符号:使用 & 表示逻辑和,使用 | 表示逻辑或
  • df.isin([]):用于判断是否包含在XXX内,相当于SQL语言中的 WHERE ... IN...
  • df.isnull():用于判断是否为空值
  • df.notnull():用于判断是否非空
# []运算符
df[(df['Age']>10) & (df['Age']<50)]
# loc访问器操作
df.loc[df['Cabin'].isin(['C123','C85'])]

Ch1-3 探索性数据分析

数据排序

可以按值排序,也可以按索引排序。

String类型自动按字母顺序排序。

  • sort_values():按值排序,by=[<列1>,<列2>]参数用于选择排序依据列,可以按多列进行综合排序
  • sort_index():按索引排序,axis用于选择按行索引/列索引排序,默认为0(列索引)

二者都有控制升降序的参数ascending=True,True表示按升序,False表示按降序

一些探索性发现

通过使用describe()info()corr()value_counts()等函数对数据进行探索性分析,有以下一些发现:

  • 船舱信息中存在大量缺失值,年龄信息也有一部分缺失,需要对这些缺失值做一定的处理。
  • 性别数据需处理为0/1变量。

得到的一些信息:

  • 大多数乘客的家庭成员都很少。
  • 乘客姓名第一个单词相同者拥有相同的船票信息、票价、登船港口、客舱、家庭成员人数,这些人应该属于同一个家族。大家族成员的存活率普遍偏低,因此,可以将家庭人数指标纳入后续的模型中。
  • 乘客整体的平均年龄在29.7岁。相比整体数据,幸存人群大约只占所有人的1/3。观察其中几个方差较小的指标,其中,幸存人数的乘客等级整体偏高。表明乘客等级确实与幸存率有着一定的关系。
  • 票价整体偏低,按照乘客舱位等级和年龄降序排序,发现前20中只有一人存活,这可能暗含着舱位较低的死亡风险更高的信息,猜测可能是舱位低安全措施越不足,安全风险更高的原因。在相关系数的分析中,票价与乘客等级负相关性较强,符合常识,可以考虑将二者结合为一个新的综合指标,进一步分析该指标和是否存活的关系。
  • 尽管船上的男性多于女性,女性的存活率却明显高于男性,女性存活率约为74.2%,相比之下男性只有18.9%的存活率。因此,性别可能也可以作为预测模型的考虑因素之一。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343