数据加载
首先在Kaggle上找到对应的竞赛页面,报名参赛下载数据,可以得到了一个train.csv和test.csv文件。
当然,如果你的电脑上已经安装了kaggle的包,当然也可以使用命令行直接下载:
kaggle competitions download -c titanic
接着载入数据,可以选择使用相对路径或绝对路径,这里将使用绝对路径,将表头修改成中文,索引改为乘客的ID,便于观察。
'''
----- kaggle_titanic
|----- train.csv
|----- test.csv
----- data_analysis.ipynb
'''
df = pd.read_csv('kaggle_titanic/train.csv', names = ['乘客ID', '是否幸存', '仓位等级', '姓名', '性别', '年龄',
'兄弟姐妹个数', '父母子女个数', '船票信息', '票价', '客舱', '登船港口'], index_col='乘客ID', header = 0)
'''
常用params:
- chunksize: number,表示在逐块提取过程中,每一块的行数。
- names: list[],和列数相同,表头修改后的别名
- index_col: 默认为False/number,表示是否重新设置新的索引index
- header: 当选择默认值或header=0时,将首行设为列名。如果为1的话,展示的表格就从第二行开始
'''
其中,chunksize是在对数据进行逐块提取时使用的参数。之所以进行逐块提取,是因为当你从一个有40亿行数据的csv文件中抽取出满足条件的某些行的数据,如果直接使用pandas的read_csv()方法去读取这个csv文件,那服务器的内存是会吃不消的,所以就非常有必要使用chunksize去分块处理。而经过chunksize后将得到一个可迭代的返回结果:
chunker = pd.read_csv(path, chunksize=100)
type(chunker) # <class 'pandas.io.parsers.TextFileReader'>
for chunk in chunker
print(chunk) # 发现每一个chunk都有100行
当然,你也可以使用其他方法去替换表头,比如说
# 方法一: 直接修改columns
df.columns = ['乘客ID', '是否幸存', '仓位等级', '姓名', '性别', '年龄',
'兄弟姐妹个数', '父母子女个数', '船票信息', '票价', '客舱', '登船港口']
# 方法二: 重命名columns
df.rename(columns={'乘客ID': 'userID', ....}, inplace=True) # 注意inplace=True时将直接修改df
# 最后,还是要设置一个新的索引
df = df.set_index(keys=['乘客ID', '是否幸存' ])
'''
np.set_index():
函数原型:DataFrame.set_index(keys, drop=True, append=False, inplace=False, verify_integrity=False)
参数解释:
- keys:列标签或列标签/数组列表,需要设置为索引的列
- drop:默认为True,删除用作新索引的列
- append:默认为False,是否将列附加到现有索引
- inplace:默认为False,适当修改DataFrame(不要创建新对象)
- verify_integrity:默认为false,检查新索引的副本。否则,请将检查推迟到必要时进行。将其设置为false将提高该方法的性能。
'''
接着你可以使用一些操作简单的看看数据。
df.info()
df.head(10) # df.tail(10)
df.isnull().head() # 判断数据是否为空,为空的地方返回True,其余地方返回False
df.to_csv(filename)
对于一个数据,你还可以从每列的数据类型来观察。当然,对于泰坦尼克号这一数据集而言,还可以进一步观察性别与生存率、仓位等级(社会等级)与生存率、家属数与生存率、年龄与生存率等数据之间的关系。
Pandas的相关知识
Pandas中有两个数据类型DataFrame和Series。
Series是一种类似于一维数组的对象。它由一组数据(各种Numpy数据类型)以及一组与之相关的数据标签(即索引)组成,它只有行索引。
DataFrame是一个表格型的数据结构,它含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔型值)。DataFrame既有行索引也有列索引,它可以被看做由Series组成的字典(共同用一个索引)。
我们比较常用的是DataFrame,通过简单的操作查看DataFrame的结构:
df.columns
df['xxx'] # 可以查看表头为xxx这列的所有项
del df['xxx'] # 列删除
当然,你依旧可以考虑用其他方法删除多余的列:
df.drop(['性别', '票价'],axis=1, inplace=True) # 删除多列
# inplace 是起了一个保存作用,如果没有它,就只是隐藏了列元而已
接着可以做一些条件筛选,比如找到年纪大于50岁的乘客,或者是找到年纪大于40和小于20的乘客,涉及到一些交并的操作:
midage = df[(df["年龄"] > 50) | (df["年龄"] < 20)] # 并集
midage = df[(df["年龄"] > 50) & (df["年龄"] < 20)] # 交集
当你想取特定行特定列的元素时,你或许需要将之前设定的“乘客id”索引给删去,这样才能完成特定行的获取。
midage = midage.reset_index(drop=True)
'''
reset_index():
函数原型:DataFrame.reset_index(level=None, drop=False, inplace=False, col_level=0, col_fill='')
参数解释:
- level:int、str、tuple或list,默认无,仅从索引中删除给定级别。默认情况下移除所有级别。
- drop:drop为False则索引列会被还原为普通列,否则会丢失
- inplace:默认为false,适当修改DataFrame(不要创建新对象)
- col_level:int或str,默认值为0,如果列有多个级别,则确定将标签插入到哪个级别。默认情况下,它将插入到第一级。
- col_fill:对象,默认‘’,如果列有多个级别,则确定其他级别的命名方式。如果没有,则重复索引名
'''
然后你就可以进行“定位”取数的操作了:
midage.loc[[100, 105, 108], ['Pclass', 'Name', 'Sex']]
midage.iloc[[100, 105, 108], [2, 3, 4]] # iloc不能直接通过列名获取数值,而是要写出第几列
另外,可进行特定行列取数的函数还有iloc()
,两者之间的差异可参考博客:https://blog.csdn.net/Leon_Kbl/article/details/97492966,写得非常清楚。
我们有的时候会对两个DataFrame相加,这时候会返回一个新的DataFrame,对应的行和列的值会想加,没有对应的就会变成空值。比如说两个DataFrame的(1, 1)位置上,都有值1,那么两者想加的结果就是2。反之一个有一个无,则得到的结果就是NaN。
数据分析探索
很多网站的表格都会做一个升序降序的功能,在数据分析的时候我们也会有这类的需求:
df.sort_value(by=['xx', 'xx'], ascending=True)
'''
params:
- by: 选择待排序的列,可以是单个也可以多个
- ascending: True/False,True是升序
'''
你还可以选择对行、列索引进行升/降序排列。
df.sort_index() # 行索引升序
df.sort_index(axis = 1) # 列索引升序,其实就是表头的排序是正确的
或者你对船上最大家族的人数感兴趣,你也可以:
max(text['兄弟姐妹个数'] + text['父母子女个数'])
# 同样的方法你可以看看其他感兴趣的数据
Pandas的describe()
函数查看数据基本统计信息:
train_data.describe()
'''
count 样本大小
mean 平均值
std 标准差
min 最小值
25% 样本数据25%时候的值
50% 50%
75% 75%
max 最大值
'''
通过describe()函数我们可以简单地看出哪些是数值型数据哪些是字符型数据,对于字符型数据我们当然要转换成数值型数据来处理,比如可以转换成0-1编码的数值型。
但需要注意的是,对于一些数值型数据却未必就不需要进一步的处理了,比如Pclass特征,从名字我们就可以看出这是标识仓位等级的特征,取值范围为[1, 2, 3],这个特征我们不应该简单地当作一个数值型数据放进分类模型中直接跑,应该把它转变为one-hot编码,标识乘客不同的仓位,这一步我们将在数据预处理步骤完成。
另外,你也可以单独看看特定列的信息统计:
text['父母子女个数'].describe() # 或许可以看出讯息,绝大多数乘客都没有带父母子女
text['票价'].describe()
课后思考
1. read_table和read_csv的异同
read_csv是pandas中专门用于csv文件读取的功能,不过这并不是唯一的处理方式。pandas中还有读取表格的通用函数read_table。两者都是加载带分隔符的数据,每一个分隔符作为一个数据的标志,但二者读出来的数据格式是不一样的。
两者在读取数据时的主要差异性如下:
默认分隔符 | 使用方式 | 输出结果 | |
---|---|---|---|
read_csv | 逗号 | pd.read_csv( ) |
每一个字符串作为一列 |
read_table | 制表符' ' | pd.read_table |
每个字符串之间有逗号相隔 |
由于read_table以制表符 作为数据的标志,也就是以行为单位进行存储。因此在读取数据的过程中:
df_csv = pd.read_csv(path)
df_table = pd.read_table(path)
print(df_csv.shape) # (891, 12)
print(df_table.shape) # (891, 1)
输出结果表明,使用read_table是对每一行作为一个维度进行了存储,可以得到一个n行1列的数组,每一行字符串为一列而不是每一个字符串。而使用read_csv是一个n行k列的数组,因为它将每一个字符串作为了一列。