Pandas数据分析本文就够

一、常用操作

1、数据读取

df = pd.read_csv('data/train.csv', encoding='utf-8',header=None,names=['timestamp','value','label'])
df.to_csv('data/data.csv',header=None,index=None)
# 分块查询处理
# read_csv 和 read_table
table = pd.read_table(filename, sep='\t', chunksize=1000000)
df_list = []
for df in table:
    # 对每一个分块df处理
    df_list.apend(df)
df = pd.concat(df_list, ignore_index=True)

读取数据之后,要先对数据有个初步了解,有空值的先处理空值

df.shape # 获取总行数和列数
df.dtypes # 获取每列的数据类型
df.columns # 获取所有列
df.head(n) # 获取前n行数据
df.tail(n) # 获取后n行数据
df.info() # 获取更多数据类型,包含列名、行数、数据类型
df.describe()
df['A'].nunique() # 获取A列中唯一值的数目
df['label'].value_counts() # 统计各种标签的数量
df.isnull().any() # 筛选出有缺失值的列
df.isnull().T.any() # 筛选出有缺失值的行

获取某一列的统计值

df['A'].sum() # 求和
df['A'].max() # 求最大值
df['A'].min() # 求最小值
df['A'].mean() # 求均值
df['A'].std() # 求标准差
df['A'].median() # 求中位数

2、画图

查看两列数据是否存在关系,画两者的关系图

matplotlib

import matplotlib.pyplot as plt
plt.plot(df['x'],df['y'],'o') # 默认折线图,o为圆点图
# 多图画法
fig=plt.figure() # 创建画布
axes1=fig.add_subplot(2,2,1) # 子图2行2列,位置1
axes2=fig.add_subplot(2,2,2)
...
axes1.plot(df1['x'],df1['y'],'o') # 子图绘制图
axes2.plot(df2['x'],df2['y'],'o')
...
axes1.set_title("dataset1") # 子图添加小标题
axes2.set_title("dataset2")
...
fig.suptitle("Title Data") # 整幅图添加大标题
fig.tight_layout() # 使用紧凑布局

dataframe自带plot

# 直方图
fig,ax = plt.subplots()
ax = tips['total_bill'].plot.hist()
plot.show()
# 密度图
...
ax = tips['tip'].plot.kde()
...
# 散点图
...
ax = tips.plot.scatter(x='total_bill',y='tip',ax=ax)
...

3、处理NaN值

# 引入缺失值
from numpy import NaN,NAN,nan
# 
df[df["date"].isnull()] # 查看某一列含有NaN的数据
# 删除NaN值,how:'any'(只要含有NaN数据就丢弃),'all'(所有数据都为NaN时丢弃)
df.dropna(axis=1, how='all',inplace=True)
df.dropna(subset=['A'],inplace=True) # 删除某个字段为空的数据
df.fillna(value=0,inplace=True) # 全部填充
df.fillna({"A":0,"B":1}) # 对不同列填充不同的值
df.fillna(method='ffill') # method:ffill(用前面的数进行填充),bfill(用后面的值填充)
df.fillna(df["score"].mean(),inplace=True) # 用均值填充
df=df.fillna(df.interpolate()) #上下两个值的平均值进行填充
df["value"] = df.groupby("name").transform(lambda x: x.fillna(x.mean())) # 分组之后用均值填充

4、创建Dataframe

# 1、
df = pd.DataFrame([['a','b','c','d']],columns=['A','B','C','D'])
# 2、
df = pd.DataFrame()
data_dict = {'A':'a','B':'b','C':'c','D':'d'}
df.append(data_dict ,ignore_index=True)

5、包含值而非变量列处理

# id_vars:不变的列;
# var_name:融合后的新列名;
# value_name:融合后的新列名,是var_name的值
df = pd.melt(df,id_vars='religion',var_name='income',value_name='count')

6、某列分割为多列

df_A = df.A.str.split('_')
df['status'] = df_A.str.get(0)
df['country'] = df_A.str.get(1)

7、列名更换

df.rename(columns={"A": "姓名", "B": "年龄"},inplace=True)

8、删除列和行

df.drop(["A", "B"], axis=1, inplace=True) # 删除列
df.drop(index=del_indexs, axis=0, inplace=True) # 删除行数据

9、筛选数据

## 1、loc与iloc
df[2:3]
df['20180709':'20180710']
df[df.A > 3]
# 行名
df.loc['20180711']
df.loc[:,['B','C']]
df.loc[(df['A']>1) & (df['B']=='male'),:]
# 行号,索引号
df.iloc[-1]
df.iloc[1:3, 2:4]
df.iloc[[0, 2], 2:4]
# 获取某一行某一列的具体值
df1 = df[df["id"]=="2301"]
value = df1.iloc[0]["A"]

## 2、筛选包含指定字符的数据
df = df.loc[df["remarks"].str.contains('测试|安装')]

10、修改数据

df.loc[index, 'B'] = 1
df.loc[df.A>0, 'B'] = 1
df.iloc[2, 2] = 1
df.A[df.A > 3] = 1
df.A[df.C == "1"] = df.B[df.C== "1"]

11、保留小数和百分数处理

# 保留两位小数
df["A"] = round(df["A"], 2)
# 百分比显示,{0:.2}、{0:.2%}
# {0:05d}:第一个0索引值,第二个0填充的字符,5表示总共5个字符,d表示使用数字
df["ratio"] = df["ratio"].apply(lambda x: '%.2f%%' % (x * 100))
df["ratio"] = df["ratio"].apply(lambda x: '{0:.2%}'.format(x))

12、相关值替换

# 这种方法会将math列中非0元素变为NaN
df1["math"] = df1["math"].map({0:100}) 
df1.loc[df1["math"]==0,"math"] = 100
# 推荐这种方式,效率是上者的两倍以上
df.replace(to_replace=0, value=100) 

13、获得某列去重后的数据

df.drop_duplicates() # 删除完全重复的行
df.drop_duplicates(subset = 'A') # 删除字段A重复的数据,保留第一行
df.drop_duplicates(subset = 'A',keep='last') # 删除字段A重复的数据,保留最后一行

14、格式转换

# 1、df转列表字典,用于存储数据库
df_list = df.to_dict('records')
# 2、df列转换为列表形式
ids = np.array(df["id"]).tolist()
# 3、某列数据格式转换
df['value'] = df_train['value'].map(str)
df['value'] = df_train['value'].astype('int') # 效率比上者高70倍以上
df['sex'] = df_train['sex'].astype('category') # 转为分类数据

二、日期数据处理

1、加载日期列数据

df = pd.read_csv('data/train.csv',parse_dates=[0])
df['year'] = df['date'].dt.year
df.index = df['date'] # 设置日期列为索引列

2、格式转换

# 字符串转日期
df["date"] = pd.to_datetime(df["date"],format='%Y-%m-%d')
df['date'] = df['date'].apply(lambda x: datetime.strptime(x, '%Y-%m-%d'))
# 日期转字符串
df["date"] = df["date"].apply(lambda x: x.strftime("%Y-%m"))

3、处理缺失日期的数据

使用一个日期范围为数据集重建索引

head_range = df.date_range(start='2020-01-01',end='2020-12-31')
df.index = df['date']
df.reindex(head_range)

4、 按日、周、月统计

## "D":日,"W":周,"M":月
df_day = df.resample("2D", on="date", label="left").sum()
df_week = df.resample("W", on="date", label="left").sum()
# "MS"是每个月第一天为开始日期, "M"是每个月最后一天
df_month = df.resample("MS", label="left",closed="left").sum()

三、合并数据

1、concat

# join:'outer'(默认,取并集), 'inner'(取交集),以下为按列合并,数据行取交集
# ignore_index:是否重排行索引
df = pd.concat([df1, df2, df3], join='inner', axis=1, ignore_index=True)
# 按行合并
df = pd.concat([df1, df2], axis=0, ignore_index=True)

1、按列合并之后,如果连接方式为"inner",则最终数据条数由少的决定,长度长的数据下边就会丢失;如果连接方式为"outer",则最终数据条数由多的决定,长度短的数据下边由NaN进行填充。
2、按行合并之后,如果连接方式为"inner",则最终数据列数为两个表共同的列,不同的列就会丢失;如果连接方式为"outer",则最终列为两个表所有列并集,缺失的值由NaN进行填充。
3、只保留索引匹配的结果。

2、merge

# how:'inner', 'outer', 'left', 'right'
df = pd.merge(df3, df4, on=['key1', 'key2'], how='right')
df = pd.merge(df3, df4, left_on='key1', right_on='key2')

注意问题:
1、有时候merge会出错,主要由于数据中有重复数据,要先去掉重复数据再merge

df.drop_duplicates(subset='game_id', keep=False, inplace=True)

2、合并之后,最好先删除之前的索引,方便以后的计算

df.reset_index(drop=True, inplace=True)

四、排名与排序

1、排名,生成排序序号列。不改变数据顺序

df["rank"] = df["A"].rank(ascending=False, method='min')
# 分组排序
df['A_sort']=df['A'].groupby(df['B']).rank(ascending=False,method='min')

排名列数据格式为float64。

method有四种类型:“first”: 根据值在数组中出现的顺序进行排名 ,

“min”: 用整个分组的最小排名 ,“max”: 用整个分组的最大排名 ," average ":默认方式,平均排名

2、排序,改变数据顺序

df = df.sort_values(by=["B"],ascending=[False])

五、分组和切分

1、分组统计

df_group1 = df1.groupby(by=["class_id"], as_index=False).apply(max)
df_group2 = df1.groupby(by=["class_id"])[["math","english"]].apply(max).reset_index()

2、分组求和

df_sum = df.groupby(by=["A","B"], as_index=False)["math", "english", "chinese"].sum().reset_index()

3、分组计数

df_count = df.groupby(by=["A","B"], as_index=False)["id"].count().reset_index()

4、分组求累加值

df["cumsum"] = df["A"].groupby(by=["id"], as_index=False).cumsum().reset_index()

注:在分组统计时,如果某列含有空值(“”),会造成对该列分组统计出现问题。

解决方式:再分组统计之前先对空值进行替换。

df.replace("",0,inplace=True)

groupby分组默认会把分组依据列变成索引,可以用reset_index方法重置或者说取消索引,将它保留在列的位置,维持DataFrame格式,方便后续匹配。

5、切分

切分常用于一维数组的分类和打标

df["label"] = pd.cut(x = df['A'],bins = [0,60,80,90100],right = False,labels = ['不及格','及格','良','优'])

6、agg

df_mean = df.groupby(by=["A","B"], as_index=False)["math"].agg(np.mean)
def my_mean_diff(values,diff_value):
    n = len(values)
    sum = 0
    for value in values:
        sum+=value
        
    mean = sum/n
    return mean-diff_value

agg_mean_diff = df.groupby('year').lifeExp.agg(my_mean_diff,diff_value=df.lifeExp.mean())

df_dict = df.groupby('year').agg({
	'lifeExp':'mean',
	'pop':'median',
})

7、transform

def fill_na_mean(x):
    avg = x.mean()
    return x.fillna(avg)

df['fill_score'] = df.groupby('sex').score.transform(fill_na_mean)

8、过滤器filter

df_filter = df.groupby('size').filter(lambda x:x['size'].count()>=10)

六、应用

1、apply用法

def f(x):
    if x == 'male':
        return '男'
    elif x == 'female':
        return '女'
df["sex"] = df["sex"].apply(f)
# 还可以采用以下两种方式
df["sex"] = df["sex"].apply(lambda x: '男' if x == 'male' else '女')
df["sex"] = df["sex"].map({'male': '男'})

注:map比apply效率要高。简单的替换优先选用map,复杂操作需要使用apply配合编写的规则函数来实现。

2、apply传参

def circle_rate(df,arg1,arg2,arg3):
    x = df[arg1]
    y = df[arg2]
    z = df[arg3]
    return x - y if y==z else (x-y)/(y-z)
df["day_bef"] = df.apply(circle_rate, axis=1, arg1="anzhuang", arg2="anzhuang_bef", arg3="anzhuang_bef_bef")
df["day_bef"] = df.apply(circle_rate, axis=1, args=("anzhuang","anzhuang_bef","anzhuang_bef_bef"))

3、向量化函数

使用numpy

@np.vectorize
def divide(x, y):
    if y == 0:
        return np.NaN
    else:
        return x / y
df['C'] = divide(df['A'], df['B'])

使用numba

@numba.vectorize
def divide_numba(x, y):
    if int(y) == 0:
        return np.NaN
    else:
        return x / y
df['C'] = divide_numba(df['A'].values, df['B'].values)

七、其他操作

1、pivot_table和pivot

透视表函数

df_pivot = pd.pivot(df, index="cs", columns="rate").reset_index()
df_pivot_table = pd.pivot_table(df,index=["A","B"],columns="rate",aggfunc="count").reset_index()
#画Heatmap图
df_pivot = pd.pivot(df, index="cs", columns="rate")
plt.pcolor(df_pivot ,cmap='RdBu')
plt.colorbar()
plt.show()

pivot与pivot_table区别:
pivot要求行与列的交叉值的索引必须唯一,否则会报错。
pivot_table会将重复索引的值求均值。

2、并行计算

from pandarallel import pandarallel
pandarallel.initialize(nb_workers=2)  # 初始化该这个b...并行库
df["B"] = df["A"].parallel_apply(func)

注意pandarallel目前只能用在linux和maco,不能用在windows下

八、遇到的坑

1、merge操作时,如果left连接,merge之后有NAN值,该列整数类型会变为浮点类型。inner连接即可解决。或者填充之后,在转换该列数值类型。
2、df1=df与df1=df.copy()都是对df的引用。如果想要一个完全独立的dataframe,一定要用df1=df.copy(deep=True)

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值