(本文大部分内容源自实验楼“Pandas百题大冲关”)
- 实验环境为Jupyter Notebook
- 最好自己动手敲一遍代码
大多是基础知识,有些小技巧还是挺有用的,不熟悉的话一定要自己敲一遍代码熟悉一下。
涉及的主要知识点有:
- 创建 Series
- Series 基本操作
- 创建 DataFrame
- DataFrame 基本操作
- DataFrame 文件操作
- Series,DataFrame 和多索引
- 透视表
- 数据清洗
- 数据预处理
- 可视化
基础部分
1. 导入Pandas
import pandas as pd
2. 查看Pandas版本信息
print(pd.__version__)
创建Series数据类型
3. 从列表创建Series
arr = [0, 1, 2, 3, 4]
s1 = pd.Series(arr) # 如果不指定索引,则默认从 0 开始
s1
# 可以直接pd.Series([0,1,2,3,4])
4. 从ndarray创建Series
import numpy as np
n = np.random.randn(5) # 创建一个随机 Ndarray 数组
index = ['a', 'b', 'c', 'd', 'e']
s2 = pd.Series(n, index=index)
s2
# 也可s2 = pd.Series(np.random.randn(5),index=list('abcde'))
5. 从字典创建Series
d = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
s3 = pd.Series(d)
s3
Series基本操作
6. 修改Series索引
print(s1) # 以 s1 为例
s1.index = ['A', 'B', 'C', 'D', 'E'] # 修改后的索引
s1
7. Series纵向拼接
s4 = s3.append(s1) # 将 s1 拼接到 s3
s4
8. Series按指定索引删除元素
print(s4)
s4 = s4.drop('e') # 删除索引为 e 的值
s4
9. Series修改指定索引元素
s4['A'] = 6 # 修改索引为 A 的值 = 6
s4
10. Seires按指定索引查找元素
s4['B']
11. Series切片操作
# 例如对s4的前3个元素访问
s4[:3]
Series运算
12 - 15. Series加法、减法、乘法、除法运算
Series 的加减乘除运算是按照索引计算,如果索引不同则填充为 NaN
(空值)。
# 加法
s4.add(s3)
# 减法
s4.sub(s3)
# 乘法
s4.mul(s3)
# 除法
s4.div(s3)
16 -19. Series求中位数、求和、求最小值、求最大值
# 求中位数
s4.median()
# 求和
s4.sum()
# 求最小值
s4.min()
# 求最大值
s4.max()
创建DataFrame数据类型
20. 通过numpy数组创建DataFrame
dates = pd.date_range('today', periods=6) # 定义时间序列作为 index
num_arr = np.random.randn(6, 4) # 传入 numpy 随机数组
columns = ['A', 'B', 'C', 'D'] # 将列表作为列名
df1 = pd.DataFrame(num_arr, index=dates, columns=columns)
df1
21. 通过字典数组创建DataFrame
data = {'animal': ['cat', 'cat', 'snake', 'dog', 'dog', 'cat', 'snake', 'cat', 'dog', 'dog'],
'age': [2.5, 3, 0.5, np.nan, 5, 2, 4.5, np.nan, 7, 3],
'visits': [1, 3, 2, 3, 2, 3, 1, 1, 2, 1],
'priority': ['yes', 'yes', 'no', 'yes', 'no', 'no', 'no', 'yes', 'no', 'no']}
labels = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
df2 = pd.DataFrame(data, index=labels)
df2
使用字典创建DataFrame时,字典的键作为DataFrame的列名。
22. 查看DataFrame的数据类型
df2.dtypes
DataFrame的基本操作
23. 预览DataFrame的前五行
df2.head()
24. 查看DataFrame的后三行数据
df2.tail(3)
25 - 27. 查看DataFrame的索引、列名、数值
# 查看索引
df2.index
# 查看列名
df.columns
# 查看数值
df.values
28. 查看DataFrame的统计数据
df2.describe()
29. DataFrame的转置操作
df2.T
30. 对DataFrame进行按列排序
# 根据 age 进行升序排列
df2.sort_values(by='age')
31. 对DataFrame数据切片
df2[1:3]
32. 对DataFrame通过标签查询(单列)
df2['age']
# 或
df2.age
33. 对 DataFrame 通过标签查询(多列)
df2[['age', 'animal']] # 传入一个列名组成的列表
34. 对DataFrame通过位置查询
df2.iloc[1:3] # 查询 2,3 行
35. DataFrame副本拷贝
# 生成 DataFrame 副本,方便数据集被多个不同流程使用
df3 = df2.copy()
df3
36. 判断DataFrame元素是否为空
df3.isnull() # 如果为空则返回为 True
37. 添加列数据
num = pd.Series([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], index=df3.index)
df3['No.'] = num # 添加以 'No.' 为列名的新数据列
df3
38. 根据DataFrame的下标值进行修改
# 修改第 2 行与第 2 列对应的值 3.0 → 2.0
df3.iat[1, 1] = 2 # 索引序号从 0 开始,这里为 1, 1
df3
39. 根据DataFrame的标签对数据进行修改
df3.loc['f', 'age'] = 1.5
df3
40. DataFrame求平均值操作
df3.mean()
41. 对DataFrame中任意列做求和操作
df3['visits'].sum()
字符串操作
42. 将字符串转化为小写字母
string = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca',
np.nan, 'CABA', 'dog', 'cat'])
print(string)
string.str.lower()
43. 将字符串转化为大写字母
string.str.upper()
DataFrame缺失值操作
44. 对缺失值进行填充
df4 = df3.copy()
print(df4)
df4.fillna(value=3)
45. 删除存在缺失值的行
df5 = df3.copy()
print(df5)
df5.dropna(how='any') # 任何存在 NaN 的行都将被删除
46. DataFrame按指定列对齐
left = pd.DataFrame({'key': ['foo1', 'foo2'], 'one': [1, 2]})
right = pd.DataFrame({'key': ['foo2', 'foo3'], 'two': [4, 5]})
print(left)
print(right)
# 按照 key 列对齐连接,只存在 foo2 相同,所以最后变成一行
pd.merge(left, right, on='key')
DataFrame文件操作
47. CSV文件写入
df3.to_csv('animal.csv')
print("写入成功.")
48. CSV文件读取
df_animal = pd.read_csv('animal.csv')
df_animal
49. Excel写入操作
df3.to_excel('animal.xlsx', sheet_name='Sheet1')
print("写入成功.")
50. Excel读取操作
pd.read_excel('animal.xlsx', 'Sheet1', index_col=None, na_values=['NA'])
进阶部分
时间序列索引
51. 建立一个以 2018 年每一天为索引,值为随机数的 Series
dti = pd.date_range(start='2018-01-01', end='2018-12-31', freq='D')
s = pd.Series(np.random.rand(len(dti)), index=dti)
s
52. 统计s
中每一个周三对应值的和
# 周一从 0 开始
s[s.index.weekday == 2].sum()
53. 统计s
中每个月值的平均值
s.resample('M').mean()
54. 将 Series 中的时间进行转换(秒转分钟)
s = pd.date_range('today', periods=100, freq='S')
ts = pd.Series(np.random.randint(0, 500, len(s)), index=s)
ts.resample('Min').sum()
55. UTC 世界时间标准
s = pd.date_range('today', periods=1, freq='D') # 获取当前时间
ts = pd.Series(np.random.randn(len(s)), s) # 随机数值
ts_utc = ts.tz_localize('UTC') # 转换为 UTC 时间
ts_utc
56. 转换为上海所在时区
ts_utc.tz_convert('Asia/Shanghai')
57.不同时间表示方式的转换
rng = pd.date_range('1/1/2018', periods=5, freq='M')
ts = pd.Series(np.random.randn(len(rng)), index=rng)
print(ts)
ps = ts.to_period()
print(ps)
ps.to_timestamp()
Series多重索引
58. 创建多重索引 Series
构建一个 letters = ['A', 'B', 'C']
和 numbers = list(range(10))
为索引,值为随机数的多重索引 Series。
letters = ['A', 'B', 'C']
numbers = list(range(10))
mi = pd.MultiIndex.from_product([letters, numbers]) # 设置多重索引
s = pd.Series(np.random.rand(30), index=mi) # 随机数
s
59. 多重索引 Series 查询
# 查询索引为 1,3,6 的值
s.loc[:, [1, 3, 6]]
60. 多重索引 Series 切片
s.loc[pd.IndexSlice[:'B', 5:]]
DataFrame多重索引
61. 根据多重索引创建 DataFrame
创建一个以 letters = ['A', 'B']
和 numbers = list(range(6))
为索引,值为随机数据的多重索引 DataFrame。
frame = pd.DataFrame(np.arange(12).reshape(6, 2),
index=[list('AAABBB'), list('123123')],
columns=['hello', 'shiyanlou'])
frame
62. 多重索引设置列名称
frame.index.names = ['first', 'second']
frame
63. DataFrame 多重索引分组求和
frame.groupby('first').sum()
64. DataFrame 行列名称转换
print(frame)
frame.stack()
65. DataFrame 索引转换
print(frame)
frame.unstack()
66. DataFrame 条件查找
# 示例数据
data = {'animal': ['cat', 'cat', 'snake', 'dog', 'dog', 'cat', 'snake', 'cat', 'dog', 'dog'],
'age': [2.5, 3, 0.5, np.nan, 5, 2, 4.5, np.nan, 7, 3],
'visits': [1, 3, 2, 3, 2, 3, 1, 1, 2, 1],
'priority': ['yes', 'yes', 'no', 'yes', 'no', 'no', 'no', 'yes', 'no', 'no']}
labels = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
df = pd.DataFrame(data, index=labels)
查找 age
大于 3
的全部信息
df[df['age'] > 3]
67. 根据行列索引切片
df.iloc[2:4, 1:3]
68. DataFrame 多重条件查询
查找 age<3
且为 cat
的全部数据。
df = pd.DataFrame(data, index=labels)
df[(df['animal'] == 'cat') & (df['age'] < 3)]
69. DataFrame 按关键字查询
df3[df3['animal'].isin(['cat', 'dog'])]
70. DataFrame 按标签及列名查询。
df.loc[df2.index[[3, 4, 8]], ['animal', 'age']]
71. DataFrame 多条件排序
按照 age
降序,visits
升序排列
df.sort_values(by=['age', 'visits'], ascending=[False, True])
72.DataFrame 多值替换
将 priority
列的 yes
值替换为 True
,no
值替换为 False
。
df['priority'].map({'yes': True, 'no': False})
73. DataFrame 分组求和
df4.groupby('animal').sum()
74. 使用列表拼接多个 DataFrame
temp_df1 = pd.DataFrame(np.random.randn(5, 4)) # 生成由随机数组成的 DataFrame 1
temp_df2 = pd.DataFrame(np.random.randn(5, 4)) # 生成由随机数组成的 DataFrame 2
temp_df3 = pd.DataFrame(np.random.randn(5, 4)) # 生成由随机数组成的 DataFrame 3
print(temp_df1)
print(temp_df2)
print(temp_df3)
pieces = [temp_df1, temp_df2, temp_df3]
pd.concat(pieces)
75. 找出 DataFrame 表中和最小的列
df = pd.DataFrame(np.random.random(size=(5, 10)), columns=list('abcdefghij'))
print(df)
df.sum().idxmin() # idxmax(), idxmin() 为 Series 函数返回最大最小值的索引值
76. DataFrame 中每个元素减去每一行的平均值
df = pd.DataFrame(np.random.random(size=(5, 3)))
print(df)
df.sub(df.mean(axis=1), axis=0)
77. DataFrame 分组,并得到每一组中最大三个数之和
df = pd.DataFrame({'A': list('aaabbcaabcccbbc'),
'B': [12, 345, 3, 1, 45, 14, 4, 52, 54, 23, 235, 21, 57, 3, 87]})
print(df)
df.groupby('A')['B'].nlargest(3).sum(level=0)
透视表
当分析庞大的数据时,为了更好的发掘数据特征之间的关系,且不破坏原数据,就可以利用透视表 pivot_table
进行操作。
78. 透视表的创建
新建表将 A, B, C
列作为索引进行聚合。
df = pd.DataFrame({'A': ['one', 'one', 'two', 'three'] * 3,
'B': ['A', 'B', 'C'] * 4,
'C': ['foo', 'foo', 'foo', 'bar', 'bar', 'bar'] * 2,
'D': np.random.randn(12),
'E': np.random.randn(12)})
print(df)
pd.pivot_table(df, index=['A', 'B'])
79. 透视表按指定行进行聚合
将该 DataFrame 的 D
列聚合,按照 A,B
列为索引进行聚合,聚合的方式为默认求均值。
pd.pivot_table(df, values=['D'], index=['A', 'B'])
80. 透视表聚合方式定义
上一题中 D
列聚合时,采用默认求均值的方法,若想使用更多的方式可以在 aggfunc
中实现。
pd.pivot_table(df, values=['D'], index=['A', 'B'], aggfunc=[np.sum, len])
81. 透视表利用额外列进行辅助分割
D
列按照 A,B
列进行聚合时,若关心 C
列对 D
列的影响,可以加入 columns
值进行分析。
pd.pivot_table(df, values=['D'], index=['A', 'B'],
columns=['C'], aggfunc=np.sum)
82. 透视表的缺省值处理
在透视表中由于不同的聚合方式,相应缺少的组合将为缺省值,可以加入 fill_value
对缺省值处理。
pd.pivot_table(df, values=['D'], index=['A', 'B'],
columns=['C'], aggfunc=np.sum, fill_value=0)
绝对类型
在数据的形式上主要包括数量型和性质型,数量型表示着数据可数范围可变,而性质型表示范围已经确定不可改变,绝对型数据就是性质型数据的一种。
83. 绝对型数据定义
df = pd.DataFrame({"id": [1, 2, 3, 4, 5, 6], "raw_grade": [
'a', 'b', 'b', 'a', 'a', 'e']})
df["grade"] = df["raw_grade"].astype("category")
df
84. 对绝对型数据重命名
df["grade"].cat.categories = ["very good", "good", "very bad"]
df
85. 重新排列绝对型数据并补充相应的缺省值
df["grade"] = df["grade"].cat.set_categories(
["very bad", "bad", "medium", "good", "very good"])
df
86. 对绝对型数据进行排序
df.sort_values(by="grade")
87. 对绝对型数据进行分组
df.groupby("grade").size()
数据清洗
常常我们得到的数据是不符合我们最终处理的数据要求,包括许多缺省值以及坏的数据,需要我们对数据进行清洗。
88. 缺失值拟合
在FilghtNumber
中有数值缺失,其中数值为按 10 增长,补充相应的缺省值使得数据完整,并让数据为 int
类型。
df = pd.DataFrame({'From_To': ['LoNDon_paris', 'MAdrid_miLAN', 'londON_StockhOlm',
'Budapest_PaRis', 'Brussels_londOn'],
'FlightNumber': [10045, np.nan, 10065, np.nan, 10085],
'RecentDelays': [[23, 47], [], [24, 43, 87], [13], [67, 32]],
'Airline': ['KLM(!)', ' (12)', '(British Airways. )',
'12. Air France', '"Swiss Air"']})
df['FlightNumber'] = df['FlightNumber'].interpolate().astype(int)
df
89. 数据列拆分
其中From_to
应该为两独立的两列From
和To
,将From_to
依照_
拆分为独立两列建立为一个新表。
temp = df.From_To.str.split('_', expand=True)
temp.columns = ['From', 'To']
temp
90. 字符标准化
其中注意到地点的名字都不规范(如:londON
应该为London
)需要对数据进行标准化处理。
temp['From'] = temp['From'].str.capitalize()
temp['To'] = temp['To'].str.capitalize()
91. 删除坏数据加入整理好的数据
将最开始的 From_to
列删除,加入整理好的 From
和 to
列。
df = df.drop('From_To', axis=1)
df = df.join(temp)
print(df)
91. 删除坏数据加入整理好的数据
将最开始的 From_to
列删除,加入整理好的 From
和 to
列。
df = df.drop('From_To', axis=1)
df = df.join(temp)
print(df)
93. 格式规范
在 RecentDelays
中记录的方式为列表类型,由于其长度不一,这会为后期数据分析造成很大麻烦。这里将 RecentDelays
的列表拆开,取出列表中的相同位置元素作为一列,若为空值即用 NaN
代替。
delays = df['RecentDelays'].apply(pd.Series)
delays.columns = ['delay_{}'.format(n) for n in range(1, len(delays.columns)+1)]
df = df.drop('RecentDelays', axis=1).join(delays)
df
数据预处理
94. 信息区间划分
班级一部分同学的数学成绩表,如下图所示
df=pd.DataFrame({'name':['Alice','Bob','Candy','Dany','Ella','Frank','Grace','Jenny'],'grades':[58,83,79,65,93,45,61,88]})
但我们更加关心的是该同学是否及格,将该数学成绩按照是否>60
来进行划分。
df = pd.DataFrame({'name': ['Alice', 'Bob', 'Candy', 'Dany', 'Ella',
'Frank', 'Grace', 'Jenny'], 'grades': [58, 83, 79, 65, 93, 45, 61, 88]})
def choice(x):
if x > 60:
return 1
else:
return 0
df.grades = pd.Series(map(lambda x: choice(x), df.grades))
df
95. 数据去重
一个列为A
的 DataFrame 数据,如下图所示
df = pd.DataFrame({'A': [1, 2, 2, 3, 4, 5, 5, 5, 6, 7, 7]})
尝试将 A 列中连续重复的数据清除。
df = pd.DataFrame({'A': [1, 2, 2, 3, 4, 5, 5, 5, 6, 7, 7]})
df.loc[df['A'].shift() != df['A']]
96. 数据归一化
有时候,DataFrame 中不同列之间的数据差距太大,需要对其进行归一化处理。
其中,Max-Min 归一化是简单而常见的一种方式.
def normalization(df):
numerator = df.sub(df.min())
denominator = (df.max()).sub(df.min())
Y = numerator.div(denominator)
return Y
df = pd.DataFrame(np.random.random(size=(5, 3)))
print(df)
normalization(df)
Pandas绘图操作
为了更好的了解数据包含的信息,最直观的方法就是将其绘制成图。
97. Series 可视化
%matplotlib inline
ts = pd.Series(np.random.randn(100), index=pd.date_range('today', periods=100))
ts = ts.cumsum()
ts.plot()
98. DataFrame 折线图
df = pd.DataFrame(np.random.randn(100, 4), index=ts.index,
columns=['A', 'B', 'C', 'D'])
df = df.cumsum()
df.plot()
99. DataFrame 散点图
df = pd.DataFrame({"xs": [1, 5, 2, 8, 1], "ys": [4, 2, 1, 9, 6]})
df = df.cumsum()
df.plot.scatter("xs", "ys", color='red', marker="*")
100. DataFrame 柱形图
df = pd.DataFrame({"revenue": [57, 68, 63, 71, 72, 90, 80, 62, 59, 51, 47, 52],
"advertising": [2.1, 1.9, 2.7, 3.0, 3.6, 3.2, 2.7, 2.4, 1.8, 1.6, 1.3, 1.9],
"month": range(12)
})
ax = df.plot.bar("month", "revenue", color="yellow")
df.plot("month", "advertising", secondary_y=True, ax=ax)