Python数据分析及可视化实例之Pandas十分钟入门
发布时间:2021-12-03
公开文章
直接上源码,内含Bokeh初尝鲜:
# coding: utf-8
# # 十分钟上手 Pandas 2016-07-05整理
# `pandas` 是一个 `Python Data Analysis Library`。
#
# 安装请参考官网的教程,如果安装了 `Anaconda`,则不需要安装 `pandas` 库。
# In[1]:
get_ipython().magic('matplotlib inline')
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# ## 产生 Pandas 对象
# `pandas` 中有三种基本结构:
#
# - `Series`
# - 1D labeled homogeneously-typed array
# - `DataFrame`
# - General 2D labeled, size-mutable tabular structure with potentially heterogeneously-typed columns
# - `Panel`
# - General 3D labeled, also size-mutable array
# ### Series
# 一维 `Series` 可以用一维列表初始化:
# In[2]:
s = pd.Series([1,3,5,np.nan,6,8]);s
# 默认情况下,`Series` 的下标都是数字(可以使用额外参数指定),类型是统一的。
#
# ### DataFrame
#
# `DataFrame` 则是个二维结构,这里首先构造一组时间序列,作为我们第一维的下标:
# In[3]:
dates = pd.date_range('20170101', periods=6)
dates
# 然后创建一个 `DataFrame` 结构:
# In[4]:
df = pd.DataFrame(np.random.randn(6,4), index=dates, columns=list('ABCD'))
df
# 默认情况下,如果不指定 `index` 参数和 `columns`,那么他们的值将用从 `0` 开始的数字替代。
#
# 除了向 `DataFrame` 中传入二维数组,我们也可以使用字典传入数据:
# In[5]:
df2 = pd.DataFrame({'A' : 1.,
'B' : pd.Timestamp('20130102'),
'C' : pd.Series(1,index=list(range(4)),dtype='float32'),
'D' : np.array([3] * 4,dtype='int32'),
'E' : pd.Categorical(["test","train","test","train"]),
'F' : 'foo' })
df2
# 字典的每个 `key` 代表一列,其 `value` 可以是各种能够转化为 `Series` 的对象。
#
# 与 `Series` 要求所有的类型都一致不同,`DataFrame` 值要求每一列数据的格式相同:
# In[6]:
df2.dtypes
# ## 查看数据
# ### 头尾数据
# `head` 和 `tail` 方法可以分别查看最前面几行和最后面几行的数据(默认为 5):
# In[7]:
df.head()
# 最后 3 行:
# In[8]:
df.tail(3)
# ### 下标,列标,数据
# 下标使用 `index` 属性查看:
# In[9]:
df.index
# 列标使用 `columns` 属性查看:
# In[10]:
df.columns
# 数据值使用 `values` 查看:
# In[11]:
df.values
# ### 统计数据
# 查看简单的统计数据:
# In[12]:
df.describe()
# ### 转置
# In[13]:
df.T
# ## 排序
# `sort_index(axis=0, ascending=True)` 方法按照下标大小进行排序,`axis=0` 表示按第 0 维进行排序。
# In[14]:
df.sort_index(ascending=False) # 对index进行排序
# In[15]:
df.sort_index(axis=1, ascending=False) # 对columns进行排序
# `sort_values(by, axis=0, ascending=True)` 方法按照 `by` 的值的大小进行排序,例如按照 `B` 列的大小:
# In[16]:
df.sort_values(by="B")
# ## 索引
# 虽然 `DataFrame` 支持 `Python/Numpy` 的索引语法,但是推荐使用 `.at, .iat, .loc, .iloc 和 .ix` 方法进行索引。
# ### 读取数据
# 选择单列数据:
# In[17]:
df["A"]
# 也可以用 `df.A`:
# In[18]:
df.A
# 使用切片读取多行:
# In[19]:
df[0:3]
# `index` 名字也可以进行切片:
# In[20]:
df["20130101":"20130103"]
# ### 使用 `label` 索引
# `loc` 可以方便的使用 `label` 进行索引:
# In[21]:
df.loc[dates[0]]
# 多列数据:
# In[22]:
df.loc[:,['A','B']]
# 选择多行多列:
# In[23]:
df.loc['20130102':'20130104',['A','B']]
# 数据降维:
# In[24]:
df.loc['20130102',['A','B']]
# 得到标量值:
# In[25]:
df.loc[dates[0],'B']
# 不过得到标量值可以用 `at`,速度更快:
# In[26]:
get_ipython().magic("timeit -n100 df.loc[dates[0],'B']")
get_ipython().magic("timeit -n100 df.at[dates[0],'B']")
df.at[dates[0],'B']
# ### 使用位置索引
# `iloc` 使用位置进行索引:
# In[27]:
df.iloc[3] # 第3行数据
# 连续切片:
# In[28]:
df.iloc[3:5,0:2]
# 索引不连续的部分:
# In[29]:
df.iloc[[1,2,4],[0,2]]
# 索引整行:
# In[30]:
df.iloc[1:3,:]
# 整列:
# In[31]:
df.iloc[:, 1:3]
# 标量值:
# In[32]:
df.iloc[1,1]
# 当然,使用 `iat` 索引标量值更快:
# In[33]:
get_ipython().magic('timeit -n100 df.iloc[1,1]')
get_ipython().magic('timeit -n100 df.iat[1,1]')
df.iat[1,1]
# ### 布尔型索引
# 所有 `A` 列大于 0 的行:
# In[34]:
df[df.A > 0]
# 只留下所有大于 0 的数值:
# In[35]:
df[df > 0]
# 使用 `isin` 方法做 `filter` 过滤:
# In[36]:
df2 = df.copy()
df2['E'] = ['one', 'one','two','three','four','three']
df2
# In[37]:
df2[df2['E'].isin(['two','four'])]
# ### 设定数据的值
# In[38]:
s1 = pd.Series([1,2,3,4,5,6], index=pd.date_range('20130102', periods=6))
s1
# 像字典一样,直接指定 `F` 列的值为 `s1`,此时以 `df` 已有的 `index` 为标准将二者进行合并,`s1` 中没有的 `index` 项设为 `NaN`,多余的项舍去:
# In[39]:
df['F'] = s1
df
# 或者使用 `at` 或 `iat` 修改单个值:
# In[40]:
df.at[dates[0],'A'] = 0
df
# In[41]:
df.iat[0, 1] = 0
df
# 设定一整列:
# In[42]:
df.loc[:,'D'] = np.array([5] * len(df))
df
# 设定满足条件的数值:
# In[43]:
df2 = df.copy()
df2[df2 > 0] = -df2
df2
# ## 缺失数据
# In[44]:
df1 = df.reindex(index=dates[0:4], columns=list(df.columns) + ['E'])
df1.loc[dates[0]:dates[1],'E'] = 1
df1
# 丢弃所有缺失数据的行得到的新数据:
# In[45]:
df1.dropna(how='any')
# 填充缺失数据:
# In[46]:
df1.fillna(value=5)
# 检查缺失数据的位置:
# In[47]:
pd.isnull(df1)
# ## 计算操作
# ### 统计信息
# 每一列的均值:
# In[48]:
df.mean()
# 每一行的均值:
# In[49]:
df.mean(1)
# 多个对象之间的操作,如果维度不对,`pandas` 会自动调用 `broadcasting` 机制:
# In[50]:
s = pd.Series([1,3,5,np.nan,6,8], index=dates).shift(2)
s
# 相减 `df - s`:
# In[51]:
df.sub(s, axis='index')
# ### apply 操作
# 与 `R` 中的 `apply` 操作类似,接收一个函数,默认是对将函数作用到每一列上:
# In[52]:
df.apply(np.cumsum)
# 求每列最大最小值之差:
# In[53]:
df.apply(lambda x: x.max() - x.min())
# ### 直方图
# In[54]:
s = pd.Series(np.random.randint(0, 7, size=10))
s
# 直方图信息:
# In[55]:
s.value_counts()
# 绘制直方图信息:
# In[56]:
h = s.hist()
# ### 字符串方法
# 当 `Series` 或者 `DataFrame` 的某一列是字符串时,我们可以用 `.str` 对这个字符串数组进行字符串的基本操作:
# In[57]:
s = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca', np.nan, 'CABA', 'dog', 'cat'])
s.str.lower()
# ## 合并
# ### 连接
# In[58]:
df = pd.DataFrame(np.random.randn(10, 4))
df
# 可以使用 `pd.concat` 函数将多个 `pandas` 对象进行连接:
# In[59]:
pieces = [df[:2], df[4:5], df[7:]]
pieces
# In[60]:
pd.concat(pieces) # pieces是一个很奇怪的list
# ### 数据库中的 Join
# `merge` 可以实现数据库中的 `join` 操作:
# In[61]:
left = pd.DataFrame({'key': ['foo', 'foo'], 'lval': [1, 2]});left
# In[62]:
right = pd.DataFrame({'key': ['foo', 'foo'], 'rval': [4, 5]});right
# In[63]:
pd.merge(left, right, on='key')
# ### append
# 向 `DataFrame` 中添加行:
# In[64]:
df = pd.DataFrame(np.random.randn(8, 4), columns=['A','B','C','D'])
df
# 将第三行的值添加到最后:
# In[65]:
s = df.iloc[3]
df.append(s, ignore_index=True)
# ### Grouping
# In[66]:
df = pd.DataFrame({'A' : ['foo', 'bar', 'foo', 'bar',
'foo', 'bar', 'foo', 'foo'],
'B' : ['one', 'one', 'two', 'three',
'two', 'two', 'one', 'three'],
'C' : np.random.randn(8),
'D' : np.random.randn(8)})
df
# 按照 `A` 的值进行分类:
# In[67]:
df.groupby('A').sum()
# 按照 `A, B` 的值进行分类:
# In[68]:
df.groupby(['A', 'B']).sum()
# ## 改变形状
# ### Stack
# 产生一个多 `index` 的 `DataFrame`:
# In[69]:
tuples = list(zip(*[['bar', 'bar', 'baz', 'baz',
'foo', 'foo', 'qux', 'qux'],
['one', 'two', 'one', 'two',
'one', 'two', 'one', 'two']]))
index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second'])
df = pd.DataFrame(np.random.randn(8, 2), index=index, columns=['A', 'B'])
df
# `stack` 方法将 `columns` 变成一个新的 `index` 部分:
# In[70]:
df2 = df[:4]
stacked = df2.stack()
stacked
# 可以使用 `unstack()` 将最后一级 `index` 放回 `column`:
# In[71]:
stacked.unstack()
# 也可以指定其他的级别:
# In[72]:
stacked.unstack(1)
# ## 时间序列
# 金融分析中常用到时间序列数据:
# In[94]:
rng = pd.date_range('3/6/2017 00:00', periods=5, freq='D')
ts = pd.Series(np.random.randn(len(rng)), rng)
ts
# 标准时间表示:
# In[95]:
ts_utc = ts.tz_localize('UTC')
ts_utc
# 改变时区表示:
# In[96]:
ts_utc.tz_convert('US/Eastern')
# ## Categoricals
# In[97]:
df = pd.DataFrame({"id":[1,2,3,4,5,6], "raw_grade":['a', 'b', 'b', 'a', 'a', 'e']})
df
# 可以将 `grade` 变成类别:
# In[98]:
df["grade"] = df["raw_grade"].astype("category")
df["grade"]
# 将类别的表示转化为有意义的字符:
# In[99]:
df["grade"].cat.categories = ["very good", "good", "very bad"]
df["grade"]
# 添加缺失的类别:
# In[100]:
df["grade"] = df["grade"].cat.set_categories(["very bad", "bad", "medium", "good", "very good"])
df["grade"]
# 使用 `grade` 分组:
# In[101]:
df.groupby("grade").size()
# ## 绘图
# 使用 `ggplot` 风格:
# In[102]:
plt.style.use('ggplot')
# `Series` 绘图:
# In[103]:
ts = pd.Series(np.random.randn(1000), index=pd.date_range('1/1/2000', periods=1000))
p = ts.cumsum().plot()
# In[104]:
import pandas as pd
from bokeh.charts import TimeSeries
from bokeh.io import output_notebook, show
output_notebook()
# In[105]:
ts_pl = TimeSeries(ts.cumsum(),title="timeseries, bokeh",
legend='top_right',xlabel='Date', ylabel='Prices')
show(ts_pl) # 可以很方便的指定图例、xy周的标签,图面也漂亮了很多
# `DataFrame` 按照 `columns` 绘图:
# In[106]:
df = pd.DataFrame(np.random.randn(1000, 4), index=ts.index,
columns=['A', 'B', 'C', 'D'])
df.cumsum().plot()
p = plt.legend(loc="best")
# In[107]:
ts_pl = TimeSeries(df.cumsum(),title="timeseries, bokeh",
legend='top_left',xlabel='Date', ylabel='Prices')
show(ts_pl) # 可以很方便的指定图例、xy周的标签,图面也漂亮了很多
# ## 文件读写
# ### csv
# 写入文件:
# In[87]:
df.to_csv('foo.csv')
# 从文件中读取:
# In[88]:
pd.read_csv('foo.csv').head()
# ### hdf5
# 写入文件:
# In[89]:
df.to_hdf("foo.h5", "df")
# 读取文件:
# In[90]:
pd.read_hdf('foo.h5','df').head()
# ### excel
# 写入文件:
# In[91]:
df.to_excel('foo.xlsx', sheet_name='Sheet1')
# 读取文件:
# In[92]:
pd.read_excel('foo.xlsx', 'Sheet1', index_col=None, na_values=['NA']).head()
# 清理生成的临时文件:
# In[93]:
import glob
import os
for f in glob.glob("foo*"):
os.remove(f)
# ## 更多参考资料:
# ### http://pandas.pydata.org/pandas-docs/stable/dsintro.html