Pandas入门
Pandas
此文稍长,但是包括了pandas的基础入门使用以及一些进阶部分:时间序列,数据清洗预处理等操作,当然要学习了解更多细节和操作去翻阅Pandas官方的操作手册也是必不可少的。
基础部分
- 导入pandas
import pandas as pd
- 查看版本信息
pd.__version__
Series数据类型
创建Series
-
从列表中创建Series:
S = pd.Series(data=['1','2','3','4'],index=['a','b','c','d'],name='CreatedSeries')
-
从字典中创建:
d = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} s2 = pd.Series(d)
-
从Ndarrray创建
import numpy as np n = np.random.randn(5) s3 = pd.Series(data=n)
Series基本操操作
- 修改索引:
S.index=[...]
,Series.reindex([...])
- 纵向拼接:
pd.concat([s1,s2])
- 按指定索引
- 删除:
S.drop('a')
- 修改:
S['d']=1
或S.loc['d']=1
- 查找 :
S.['d']
或S.loc['d']
- 切片操作
S[:]
参考列表切片操作
- 删除:
Series运算
按照索引进行计算,所以不同则为NaN
空值,下面以S与自身运算为例
-
四则运算如下:
S.add(S) S.sub(S) S.mul(S) S.div(S)
-
求中位数、求和、最值:
res6 = S.median() # 中位数 res7 = S.sum() # 求和 res8 = S.max() # 最大值 res9 = S.min() # 最小值
DataFrame数据类型
创建DataFrame
-
从Numpy数组创建:
dates = pd.date_range('today', periods=6) # 定义时间序列作为 index num_arr = np.random.randn(6, 4) # 传入 numpy 随机数组 column_name = ['A', 'B', 'C', 'D'] df1 = pd.DataFrame(data=num_arr,index=dates,columns=column_name)
-
通过数组字典创建:
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)
-
查看DataFrame数据类型:
df2.dtypes
DataFrame基本操作
-
了解陌生数据集结构(尤其是数据量大的数据)
# 查看前5行 df2.head() # 可以通过传递整数参数来指定显示行数 # 查看后3行 df2.tail(3) # 默认显示后5行
-
查看索引:
df1.index
-
查看列名:
df2.columns
-
查看数值:
df2.values
-
查看统计数据:
df2.describe(include='all') # 默认只统计数值列数据,查看所有列就需要参数 include='all'
-
转置操作:
df1.T
-
按列排序:
df1.sort_values(by='A',ascending=False) #以A列的值降序排列
-
切片操作:
df1[:6:2]
-
通过标签查询单列和多列
df1['A'] # 查询A列 df1.A # 查询A列等价写法 df1[['A','B']] # 查询A列和B列
-
多条件查询
df1[(df1['A']>0) & (df1['B']<0)]
-
按位置查询
.loc[]
方法用于根据标签名称索引,行和列对应的名称
.iloc[]
方法用于根据整数位置索引,行和列都是从0开始编号row = df1.iloc[1] # 按行位置查询 col = df1.iloc[:,2] # 按列位置查询 arr = df1.iloc[:5,:3] # 前五行前三列
-
副本拷贝:
df3= df2.copy # 从df2生成DataFrame副本df3
-
判断元素是否为空:
df2.isnull() # 判断整个df2元素是否为空值 df2['age'].isnull() # 判断df2中的age列元素是否为空值
-
添加列数据:
num = pd.Series([0,1,2,3,4,5,6,7,8,9],index=df3.index) # 需要插入的列 df3['No.']=num # num插入到df3中命名为’No.‘
-
数据修改:
- 根据下标值:
df2.iloc[2,1]=1 # 修改了第三行第二列的数据df2.iat[2,1]=1 # 等价与前一种
- 根据标签:
df2.loc['a','age']=3 # 修改了名为'a’行,‘age'列的数据
- 根据下标值:
-
求和、求平均值操作等
df2.median() df2['age'].sum()
-
字符串操作
-
大小写转换:
string = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca',np.nan, 'CABA', 'dog', 'cat']) print(string) string.str.lower() # 字符串转换为小写 string.str.upper() # 将字符串换为大写
-
分割字符串:
import pandas as pd # 创建一个包含字符串的Series data = pd.Series(['apple,banana,cherry', 'date,fig']) print(data) # 使用.str.split()方法按逗号分割字符串 split_data = data.str.split(',') print(split_data)
-
-
缺失值操作:
-
检测缺失值:
isna()
和notna()
:这两个方法用于检测缺失值。isna()
返回一个布尔值Series,指示每个元素是否为缺失值。notna()
返回一个布尔值Series,指示每个元素是否不是缺失值data = pd.Series([1, 2, np.nan, None]) print(data.isna()) print(data.notna())
-
删除缺失值:
dropna()
:该方法用于删除包含缺失值的行或列。默认情况下,它会删除包含任何缺失值的行。可以使用axis
参数指定删除的轴,axis=0
表示删除行,axis=1
表示删除列data = pd.DataFrame({'A': [1, 2, np.nan], 'B': [4, np.nan, 6], 'C': [np.nan, 8, 9]}) print(data) cleaned_data = data.dropna() print(cleaned_data) cleaned_data_col = data.dropna(axis=1) print(cleaned_data_col)
-
-
指定列对齐:
# 创建两个示例DataFrame df1 = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]}) df2 = pd.DataFrame({'C': [7, 8, 9], 'D': [10, 11, 12]}) # 按'A'列对齐两个DataFrame df1_aligned, df2_aligned = df1.align(df2, join='inner', axis=0, level=None, copy=False) print(df1_aligned) print(df2_aligned)
-
列名的重命名:
import pandas as pd # 创建示例数据帧 df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]}) # 定义新的列名列表 new_column_names = ['X', 'Y'] # 使用rename()函数重命名列 df = df.rename(columns=dict(zip(df.columns, new_column_names))) print(df)
文件读取和写入操作
- 读取:
pd.read_csv()
、pd.read_excel()
等方法对不同文件读取 - 写入:
df.to_excel()
、df.to_json()
等方法进行写入,此处的df是一个DataFrame对象
进阶部分:
时间序列索引
- 建立一个以 2018 年每一天为索引,值为随机数的 Series:
import pandas as pd
import numpy as np
dti = pd.date_range(start='2018-01-01', end='2018-12-31', freq='D')
s = pd.Series(np.random.rand(len(dti)), index=dti)
-
统计每一个周三对应值的和:
# 周一从 0 开始 s[s.index.weekday == 2].sum()
-
统计每个月的平均值:
s.resample('M').mean()
pandas中的
resample()
函数对时间序列数据进行重采样 -
时间转换:
s = pd.date_range('today', periods=100, freq='S') ts = pd.Series(np.random.randint(0, 500, len(s)), index=s) sum1 = ts.resample('Min').sum() sum2 = ts.resample('H').sum() ''' 注意使用sum()重采样聚合后 sum1与sum2值相等 '''
-
时间标准转换:
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.tz_convert('Asia/Shanghai') # 转换为上海时间
-
不同时间表示方式转换:
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 多重索引
-
创建多重索引:
letters = ['A', 'B', 'C'] numbers = list(range(10)) mi = pd.MultiIndex.from_product([letters, numbers]) # 设置多重索引 s = pd.Series(np.random.rand(30), index=mi) # 随机数
-
根据多重索引查询:
# 查询索引为 1,3,6 的值 s.loc[:, [1, 3, 6]]
-
多重索引切片:
s.loc[pd.IndexSlice[:'B', 5:]]
DataFrame多重索引
-
创建带有多重索引的DataFrame:
frame = pd.DataFrame(np.arange(12).reshape(6, 2), index=[list('AAABBB'), list('123123')], columns=['hello', 'shiyanlou'])
-
多重索引设置列名称:
frame.index.names = ['first', 'second']
-
多重索引分组求和:
frame.groupby('firsr').sum
-
行列名称转换:
print(frame) frame.stack()
-
索引转换:
frame.unstack()
-
条件查找:
# 示例数据 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) # 单个条件查询 df[df['age']>3] # 多个条件查询 df[(df['animal'] == 'cat') & (df['age'] < 3)]
-
按关键字查询:
df[df['animal'].isin(['cat','dog'])]
-
按标签及列名查询:
df.loc[df.index[[3,4,8]],['animal','age']]
-
多条件排序:
```python
# 字段`age`降序,`visits`升序来进行排序
df.sort_values(by=['age','visits'], ascending=[False,True])
```
-
多值替换:对某一列数据使用
map
函数进行替换df['priority'].map({'yes':True, 'no':False})
-
分组求和:
df.groupby('animal').sum() df.groupby(['animal','age']).sum()
-
拼接多个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) # 等价于 pd.concat([temp_df1, temp_df2, temp_df3])
-
找出和最小的列:
df = pd.DataFrame(np.random.random(size=(5, 10)), columns=list('abcdefghij')) # idxmax(),idmin() 返回最大最小值的索引值 df.sum().idxmin()
-
每个元素减去每一行的平均值:
df = pd.DataFrame(np.random.random(size=(5, 3))) # 相当于复合运算 df.sub(df.mean(axis=1), axis=0)
-
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)
-
DataFrame 分组,并得到每一组中最大三个数之和:
df = pd.DataFrame({'A': list('aaabbcaabcccbbc'), 'B': [12, 345, 3, 1, 45, 14, 4, 52, 54, 23, 235, 21, 57, 3, 87]}) df.groupby('A')['B'].nlargest(3).sum(level=0) df.nlargest(3,'B') # 获取df中B列值最大的前三行
透视表
当分析庞大的数据时,为了更好的发掘数据特征之间的关系,且不破坏原数据,就可以利用透视表 pivot_table
进行操作
-
透视表的创建:
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)}) pd.pivot_table(df, index=['A', 'B', 'C'])
-
按照指定列进行聚合:
# 将以D列聚合,按照A,B列为索引进行聚合,聚合的方式为默认求平均值 pd.pivot_table(df, values=['D'], index=['A', 'B'])
-
透视表聚合方式定义:
# 当 aggfunc 是一个函数列表时,将同时应用多个聚合函数,并返回一个具有多级列索引的数据框 pd.pivot_table(df, values=['D'], index=['A', 'B'], aggfunc=[np.sum, len]) # aggfunc=[np.sum, len] 表示要对值进行两个聚合操作,即求和和计数。np.sum 是一个函数,表示要计算每个组合
-
透视表利用额外列进行辅助分割:
#`D` 列按照 `A,B` 列进行聚合时,若关心 `C` 列对 `D` 列的影响,可以加入 `columns` 值进行分析 pd.pivot_table(df, values=['D'], index=['A', 'B'], columns=['C'], aggfunc=np.sum)
-
透视表中对缺省值处理:
# 在透视表中由于不同的聚合方式,相应缺少的组合将为缺省值,可以加入 `fill_value` 对缺省值处理 pd.pivot_table(df, values=['D'], index=['A', 'B'], columns=['C'], aggfunc=np.sum, fill_value=0)
绝对类型
在数据的形式上主要包括数量型和性质型,数量型表示着数据可数范围可变,而性质型表示范围已经确定不可改变,绝对型数据就是性质型数据的一种
-
绝对型数据定义:
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["grade"].cat.categories = ["very good", "good", "very bad"]
-
绝对型数据其他操作:
# 排序 df.sort_values(by="grade") # 分组 df.groupby("grade").size()
数据清洗&预处理
经常得到的数据不符合最终处理的数据要求,包括了缺省值以及坏的数据,需要我们对数据进行清洗
-
缺失值拟合
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(!)', '<Air France> (12)', '(British Airways. )', '12. Air France', '"Swiss Air"']}) # 对FlightNumber中缺失的数据进行线性填充,并让数据为int类型 df['FlightNumber'] = df['FlightNumber'].interpolate().astype(int)
-
数据列拆分
# 将上一步生成的df中的From_To列通过split进行拆分为独立两列为新表 temp = df.From_To.str.split('_', expand=True) temp.columns = ['From', 'To']
-
字符标准化
# 对地名姓名进行标准化处理 temp['From'] = temp['From'].str.capitalize() temp['To'] = temp['To'].str.capitalize()
-
删除坏数据加入整理好的数据
# 将原来的From_to列删除,加入整理好的From和to列 df = df.drop('From_To', axis=1) df = df.join(temp) print(df)
-
去除多余字符
df['Airline'] = df['Airline'].str.extract( '([a-zA-Z\s]+)', expand=False).str.strip()
-
格式规范:
上面df中的RencentDelays
中记录的方式为列表类型,但是列表的长度不一,后期处理分析会比较麻烦,此时将其拆开,去除列表中相同位置元素作为一列,若为空值用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)
-
信息区间划分:
# 将grades按照是否大于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 = pd.DataFrame({'A': [1, 2, 2, 3, 4, 5, 5, 5, 6, 7, 7]}) # 将A列中连续重复的数据清除 df.loc[df['A'].shift() != df['A']]