目录
1. 学习内容
2. 准备工作
3. 文件的读写
3.1 读文件
3.2 写文件
4. pandas的基本数据结构
4.1 Series序列
4.1.1 创建
4.1.2 读取序列属性
4.1.3 提取某一元素
4.1.4 可用的方法
4.2 DataFrame数据框(表格)
4.2.1 创建
4.2.2 获取其属性
4.2.3 简单提取某一元素
4.2.4 简单提取某一列
4.2.5 按数据类型提取某些列
4.2.6 可用的方法
4.2.7 修改行名和列名
4.2.8 索引对齐
4.2.9 删除某些行或列
4.2.10 添加新的列
4.2.11 将序列转换成表格
4.2.12 将表格的行列进行互换
5. 排序操作
5.1 按值排序
5.2 按索引排序
6. 其他常用方法
6.1 head()和tail():打印表格与序列头部和尾部的若干条数据
6.2 unique():统计序列中出现的所有不同的值
6.3 nunique():统计表格与序列中各列不同的值的个数
6.4 value_counts():统计序列中所有不同的值出现的次数
6.5 count():统计表格与序列中非缺失值的个数
6.6 info():统计表格各列的名称、非空数据个数以及数据类型
6.7 describe():默认统计表格与序列中各列为数值型数据的相关统计量
6.8 idxmax()和idxmin():返回序列中最大值和最小值对应的索引
6.9 nlargest()和nsmallest():返回序列中最大和最小的前n个值的索引和值
6.10 clip():对表格与序列内的值进行闭区间的范围截取,可行可列(它无法自动筛选可操作的数据)
6.11 replace():对表格与序列内的值进行替换操作
6.12 apply():pandas中的函数式编程接口
7. 问题与练习
7.1 问题
7.2 练习
8. 参考文献
1. 了解如何用pandas保存和读取不同文件类型的数据
2. 了解如何使用pandas的两个基本数据结构及其操作
本项目参见https://github.com/datawhalechina/team-learning/tree/master/Pandas%E6%95%99%E7%A8%8B%EF%BC%88%E4%B8%8A%EF%BC%89
首先,需要保证自己的pandas是1.0.3的版本。
import numpy as np
import pandas as pd
pd.__version__
'1.0.3'
无论是读文件还是写文件,在操作之前都需要明确数据的分隔方式(即逗号分隔、空格分隔或是其他符号作为分隔符),是否需要保留索引行和列名的信息。通过对相关函数参数的修改可以保证我们得到想要的数据及格式。
一般,数据往往会保存在csv文件,txt文件和xls(或xlsx)文件中。针对这三种不同的文件,我们可以分别使用pd.read_csv(),pd.read_table()和pd.read_excel()来进行读取操作。
df_csv = pd.read_csv(r'./data/table.csv')
df_txt = pd.read_table(r'./data/table.csv', sep = ',')
df_excel = pd.read_excel('data/table.xlsx')
这里需要注意的是文本文件的读取默认的分隔符是‘\t’而不是逗号,由于我们的数据是用逗号分隔的,因此需要在函数中明确分隔符为逗号。
读文件和写文件略有不同。不同之处在于csv文件和txt文件是共用一个方法的,都是to_csv()。
df_csv.to_csv(r'./data/new_table.csv', index = False)
df_txt.to_csv(r'./data/new_table.txt', index = False)
df_excel.to_excel(r'./data/new_table2.xlsx', sheet_name = 'Sheet1')
pandas只有两种数据结构:Series(序列)和DataFrame(数据框,不过本人更喜欢称之为表格)。表格可以看作是多个具有相同索引的序列拼接而成的数据结构,表格中的每一列单独取出来数据类型就是序列。
创建一个序列时我们需要明确序列的4个属性:值(values)、索引(index)、名字(name)和类型(dtype)。
s = pd.Series(np.random.randn(5), index = ['a','b','c','d','e'], \
name = 'DemoSeries', dtype = 'float64')
print(s)
a -1.162954
b -1.067161
c -1.270187
d 0.968130
e -1.175407
Name: DemoSeries, dtype: float64
print(s.values)
print(s.index)
print(s.name)
print(s.dtype)
[-1.16295379 -1.06716099 -1.27018709 0.96812999 -1.17540694]
Index(['a', 'b', 'c', 'd', 'e'], dtype='object')
DemoSeries
float64
序列的元素访问或提取就像数组一样是用索引来实现的。只不过序列从可视化的角度来看是一个竖着放置的数组。
print(s['a'])
-1.1629537870011206
print([attr for attr in dir(s) if not attr.startswith('_')])
['T', 'a', 'abs', 'add', 'add_prefix', 'add_suffix', 'agg', 'aggregate', 'align', 'all',
'any', 'append', 'apply', 'argmax', 'argmin', 'argsort', 'array', 'asfreq', 'asof',
'astype', 'at', 'at_time', 'attrs', 'autocorr', 'axes', 'b', 'between', 'between_time',
'bfill', 'bool', 'c', 'clip', 'combine', 'combine_first', 'convert_dtypes', 'copy', 'corr',
'count', 'cov', 'cummax', 'cummin', 'cumprod', 'cumsum', 'd', 'describe', 'diff', 'div',
'divide', 'divmod', 'dot', 'drop', 'drop_duplicates', 'droplevel', 'dropna', 'dtype',
'dtypes', 'duplicated', 'e', 'empty', 'eq', 'equals', 'ewm', 'expanding', 'explode',
'factorize', 'ffill', 'fillna', 'filter', 'first', 'first_valid_index', 'floordiv', 'ge',
'get', 'groupby', 'gt', 'hasnans', 'head', 'hist', 'iat', 'idxmax', 'idxmin', 'iloc',
'index', 'infer_objects', 'interpolate', 'is_monotonic', 'is_monotonic_decreasing',
'is_monotonic_increasing', 'is_unique', 'isin', 'isna', 'isnull', 'item', 'items',
'iteritems', 'keys', 'kurt', 'kurtosis', 'last', 'last_valid_index', 'le', 'loc', 'lt',
'mad', 'map', 'mask', 'max', 'mean', 'median', 'memory_usage', 'min', 'mod', 'mode', 'mul',
'multiply', 'name', 'nbytes', 'ndim', 'ne', 'nlargest', 'notna', 'notnull', 'nsmallest',
'nunique', 'pct_change', 'pipe', 'plot', 'pop', 'pow', 'prod', 'product', 'quantile',
'radd', 'rank', 'ravel', 'rdiv', 'rdivmod', 'reindex', 'reindex_like', 'rename',
'rename_axis', 'reorder_levels', 'repeat', 'replace', 'resample', 'reset_index',
'rfloordiv', 'rmod', 'rmul', 'rolling', 'round', 'rpow', 'rsub', 'rtruediv', 'sample',
'searchsorted', 'sem', 'set_axis', 'shape', 'shift', 'size', 'skew', 'slice_shift',
'sort_index', 'sort_values', 'squeeze', 'std', 'sub', 'subtract', 'sum', 'swapaxes',
'swaplevel', 'tail', 'take', 'to_clipboard', 'to_csv', 'to_dict', 'to_excel', 'to_frame',
'to_hdf', 'to_json', 'to_latex', 'to_list', 'to_markdown', 'to_numpy', 'to_period',
'to_pickle', 'to_sql', 'to_string', 'to_timestamp', 'to_xarray', 'transform', 'transpose',
'truediv', 'truncate', 'tshift', 'tz_convert', 'tz_localize', 'unique', 'unstack',
'update', 'value_counts', 'values', 'var', 'view', 'where', 'xs']
表格的创建输入参数比较多变,这里采用字典的方式来进行创建。
df = pd.DataFrame({'col1':list('abcde'), 'col2':range(5,10), \
'col3':[1.3,2.5,3.6,4.6,5.8]}, index = list('一二三四五'))
print(df)
col1 col2 col3
一 a 5 1.3
二 b 6 2.5
三 c 7 3.6
四 d 8 4.6
五 e 9 5.8
print(df.index)
print(df.columns)
print(df.values)
print(df.shape)
Index(['一', '二', '三', '四', '五'], dtype='object')
Index(['col1', 'col2', 'col3'], dtype='object')
[['a' 5 1.3]
['b' 6 2.5]
['c' 7 3.6]
['d' 8 4.6]
['e' 9 5.8]]
(5, 3)
这里需要注意的是df.values返回的是一个numpy的数组,因此可以用该属性将表格映射成一个numpy数组。
如果将表格视作一个二维数组的话,按照习惯我们很有可能会将行索引作为第一个下标并将列名作为第二个下标。但是,需要注意的是:表格中某个元素的提取要将列名作为第一个下标,而索引要作为第二个下标。
print(df['col2']['三'])
7
由于表格是将列名作为第一个下标的,因此,如果访问时只写列名,那么将直接返回该列名对应的列,而且返回数据的格式是序列。
print(df['col1'])
一 a
二 b
三 c
四 d
五 e
Name: col1, dtype: object
print(df.select_dtypes(include = ['number']).head())
print(df.select_dtypes(include=['float']).head())
col2 col3
一 5 1.3
二 6 2.5
三 7 3.6
四 8 4.6
五 9 5.8
col3
一 1.3
二 2.5
三 3.6
四 4.6
五 5.8
print([attr for attr in dir(df) if not attr.startswith('_')])
['T', 'abs', 'add', 'add_prefix', 'add_suffix', 'agg', 'aggregate', 'align', 'all', 'any',
'append', 'apply', 'applymap', 'asfreq', 'asof', 'assign', 'astype', 'at', 'at_time',
'attrs', 'axes', 'between_time', 'bfill', 'bool', 'boxplot', 'clip', 'col1', 'col2',
'col3', 'columns', 'combine', 'combine_first', 'convert_dtypes', 'copy', 'corr',
'corrwith', 'count', 'cov', 'cummax', 'cummin', 'cumprod', 'cumsum', 'describe', 'diff',
'div', 'divide', 'dot', 'drop', 'drop_duplicates', 'droplevel', 'dropna', 'dtypes',
'duplicated', 'empty', 'eq', 'equals', 'eval', 'ewm', 'expanding', 'explode', 'ffill',
'fillna', 'filter', 'first', 'first_valid_index', 'floordiv', 'from_dict', 'from_records',
'ge', 'get', 'groupby', 'gt', 'head', 'hist', 'iat', 'idxmax', 'idxmin', 'iloc', 'index',
'infer_objects', 'info', 'insert', 'interpolate', 'isin', 'isna', 'isnull', 'items',
'iteritems', 'iterrows', 'itertuples', 'join', 'keys', 'kurt', 'kurtosis', 'last',
'last_valid_index', 'le', 'loc', 'lookup', 'lt', 'mad', 'mask', 'max', 'mean', 'median',
'melt', 'memory_usage', 'merge', 'min', 'mod', 'mode', 'mul', 'multiply', 'ndim', 'ne',
'nlargest', 'notna', 'notnull', 'nsmallest', 'nunique', 'pct_change', 'pipe', 'pivot',
'pivot_table', 'plot', 'pop', 'pow', 'prod', 'product', 'quantile', 'query', 'radd',
'rank', 'rdiv', 'reindex', 'reindex_like', 'rename', 'rename_axis', 'reorder_levels',
'replace', 'resample', 'reset_index', 'rfloordiv', 'rmod', 'rmul', 'rolling', 'round',
'rpow', 'rsub', 'rtruediv', 'sample', 'select_dtypes', 'sem', 'set_axis', 'set_index',
'shape', 'shift', 'size', 'skew', 'slice_shift', 'sort_index', 'sort_values', 'squeeze',
'stack', 'std', 'style', 'sub', 'subtract', 'sum', 'swapaxes', 'swaplevel', 'tail',
'take', 'to_clipboard', 'to_csv', 'to_dict', 'to_excel', 'to_feather', 'to_gbq', 'to_hdf',
'to_html', 'to_json', 'to_latex', 'to_markdown', 'to_numpy', 'to_parquet', 'to_period',
'to_pickle', 'to_records', 'to_sql', 'to_stata', 'to_string', 'to_timestamp', 'to_xarray',
'transform', 'transpose', 'truediv', 'truncate', 'tshift', 'tz_convert', 'tz_localize',
'unstack', 'update', 'values', 'var', 'where', 'xs']
df.rename(index = {'一': 'one'}, columns = {'col1': 'new_col1'}, inplace = False)
索引对齐是一个很重要的性质。
df1 = pd.DataFrame({'A':[1,2,3]}, index = [1,2,3])
df2 = pd.DataFrame({'A':[1,2,3]}, index = [3,1,2])
print(df1)
print(df2)
print(df1 - df2)
A
1 1
2 2
3 3
A
3 1
1 2
2 3
A
1 -1
2 -1
3 2
可以发现,df1和df2会先将索引进行对齐然后再进行减法。
删除的相关方法共有3种:drop()方法,del命令和pop()方法。其中,drop()方法很万能,可以删除行和列,而且可以控制是否对原数据进行删除操作。而del命令和pop()方法只能用来删除列,而且是直接在原数据上操作。另外,pop()方法会返回被删除的列。
df.drop(index = ['一', '五'], columns = ['col1'], inplace = False)
可以直接在表格上新建列,也可以使用assign()方法。不过assign()方法不会修改原数据。
df1['B'] = list('abc')
print(df1)
A B
1 1 a
2 2 b
3 3 c
print(df1.assign(C = pd.Series(list('def'))))
print(df1)
A B C
1 1 a e
2 2 b f
3 3 c NaN
A B
1 1 a
2 2 b
3 3 c
核心方法是t0_frame()方法。
s = df.mean()
s.name = 'to_DataFrame'
print(s)
df_s = s.to_frame()
print(df_s)
col2 7.00
col3 3.56
Name: to_DataFrame, dtype: float64
to_DataFrame
col2 7.00
col3 3.56
这里的方法跟numpy数组用T来取转置的方法是一模一样的。
print(s.to_frame().T)
col2 col3
to_DataFrame 7.0 3.56
这里的按值排序可以设置多个列名,从前到后的次序就是排序的优先级次序。
df.sort_values(by = ['Address', 'Height']).head()
有时候当我们对表格进行某些操作之后(例如上面的按值排序),索引的次序也会随之被打乱。因此,当我们需要按照索引来对数据进行排序时,就可以用如下的方法。
df.sort_index().head()
df = pd.read_csv(r'./data/table.csv')
有时候我们想观察数据的样子,而全部打印出来又没有必要,抽样又太繁琐。于是,就可以使用这两个方法来打印表格与序列头部和尾部的若干条数据。这两个方法默认打印的数据条数都是5,可以通过赋予其他的数值来进行改变。
df.head()
df.tail()
unique()方法的返回值是一个numpy数组。
df['Height'].unique()
array([173, 192, 186, 167, 159, 188, 176, 160, 162, 161, 175, 195, 187,
174, 157, 170, 193, 194, 155, 183, 171, 190, 164, 166, 158],
dtype=int64)
nunique()方法的返回值是一个序列。
df.nunique()
School 2
Class 4
ID 35
Gender 2
Address 6
Height 25
Weight 25
Math 35
Physics 7
dtype: int64
df['Physics'].value_counts()
B+ 9
B 8
B- 6
A 4
A- 3
A+ 3
C 2
Name: Physics, dtype: int64
df.count()
School 35
Class 35
ID 35
Gender 35
Address 35
Height 35
Weight 35
Math 35
Physics 35
dtype: int64
df.info()
RangeIndex: 35 entries, 0 to 34
Data columns (total 9 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 School 35 non-null object
1 Class 35 non-null object
2 ID 35 non-null int64
3 Gender 35 non-null object
4 Address 35 non-null object
5 Height 35 non-null int64
6 Weight 35 non-null int64
7 Math 35 non-null float64
8 Physics 35 non-null object
dtypes: float64(1), int64(3), object(5)
memory usage: 2.6+ KB
df.describe()
不过我们也可以根据具体需求自行调整统计量,例如添加新的分位点。
df.describe(percentiles = [.05, .25, .75, .95])
df['Physics'].describe()
count 35
unique 7
top B+
freq 9
Name: Physics, dtype: object
df['Math'].idxmax()
5
df['Math'].nlargest(3)
5 97.0
28 95.5
11 87.7
Name: Math, dtype: float64
df['Math'].clip(30, 80).head()
0 34.0
1 32.5
2 80.0
3 80.0
4 80.0
Name: Math, dtype: float64
replace()用两种替换方法:一种是先选定列,然后将旧值与新值分别写入两个列表中作为输入;另一种则是直接在表格中用字典进行替换。
df['Address'].head()
0 street_1
1 street_2
2 street_2
3 street_2
4 street_4
Name: Address, dtype: object
df['Address'].replace(['street_1', 'street_2'], ['one', 'two']).head()
0 one
1 two
2 two
3 two
4 street_4
Name: Address, dtype: object
df.replace({'Address': {'street_1': 'one', 'street_2': 'two'}}).head()
apply()方法是一个功能强大且十分灵活的方法,它可以将可迭代或遍历操作的数据与某个函数或方法关联起来。它可以大幅度地缩短代码量。后续会对它进行详细的介绍,这里请看参考文献[1]。
【问题一】 Series和DataFrame有哪些常见属性和方法?
详情请见参考文献[2][3]。
【问题二】 value_counts会统计缺失值吗?
不会。
【问题三】 与idxmax和nlargest功能相反的是哪两组函数?
idxmin()和nsmallest()。
【问题四】 在常用函数一节中,由于一些函数的功能比较简单,因此没有列入,现在将它们列在下面,请分别说明它们的用途并尝试使用。
sum/mean/median/mad/min/max/abs/std/var/quantile/cummax/cumsum/cumprod
求和、求平均、求中位数、求MAE、求最小值、求最大值、求绝对值、求标准差、求方差、求分位数、求累计最大值、求累积和和求累计积。
【问题五】 df.mean(axis = 1)是什么意思?它与df.mean()的结果一样吗?第一问提到的函数也有axis参数吗?怎么使用?
axis代表计算的方向,而默认的计算方向是0即按列方向计算。而axis取1则是按行方向计算。
略。
1. https://blog.csdn.net/stone0823/article/details/100008619
2. https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.html#pandas.Series
3. https://pandas.pydata.org/pandas-docs/stable/reference/frame.html