文章目录
- 1. 生成dataframe
- 更改行索引的显示顺序:
- 更新列索引名:
- 2. 读写数据文件
- json:
- csv:
- txt:
- 3. 增加:
- 增加一列:
- 增加一行:
- 4. 删除:
- 5. 更新
- 排序
- 分组
- 聚合
- 行索引变成外层索引,列索引变成内层索引
- 更新某个值
- 行索引重置
- 6. 显示:
- 显示一列
- 显示多列
- 显示一行:
- 显示某个元素:
- 暴力法:
- 关于list与ndarray索引与切片的补充
- 查看某一行或者某一列有多少元素是1
- 条件筛选:
- 7. 数据缺失的处理:
- 8. 数据连接与合并:
- 连接
- 合并
- 9. 去重复
- 10.其它
- 提取数据,dataframe转list
- 提取行索引
- 提取列索引
这篇blog长期更新,总结一些python数据处理过程中常用的方法(不总结老是忘),我一般喜欢用dataframe做数据处理,所以一般会尽量转成pandas的dataframe格式。所有方法需要先导入库pandas和numpy。
import pandas as pd
import numpy as np
1. 生成dataframe
pd.DataFrame
# 输入二维向量,columns是列索引,index是行索引
df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns=['a', 'b', 'c'], index = [0,1,2])
print(df)
# 输出:
"""
a b c
0 1 2 3
1 4 5 6
2 7 8 9
"""
更改行索引的显示顺序:
df.reindex
df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns=['a', 'b', 'c'], index = [0,1,2])
df = df.reindex([2,1,0])
print(df)
# 输出
"""
a b c
2 7 8 9
1 4 5 6
0 1 2 3
"""
更新列索引名:
df.columns
df.rename
df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns=['a', 'b', 'c'], index = [0,1,2])
# 法一,暴力法
df.columns=['a', 'b', 'f']
# 法二,当列索引的数量很多,用第二种比较好,可以只改一部分
df.rename(columns={'b':'e'}, inplace = True)
print(df)
# 输出
"""
a e f
0 1 2 3
1 4 5 6
2 7 8 9
"""
2. 读写数据文件
json:
# 读取方法一,针对利用pd.to_json()存的json十分合适
pd.read_json('xxx')
# 读取方法二,有时候读取的json文件,不是由pd.to_json存的,利用pd.read_csv可能会有问题,要用这种方法
with open('xxx') as f:
for i in f.readlines():
data = json.load(i)
# 写方法
pd.to_json('xxx')
csv:
# 读方法,ignore_index用于确定是否保存行索引,ignore_index=False会保存行索引
pd.to_csv('xxx.csv', ignore_index=True)
# 写方法,nrows用于选择读取前多少行,usecols用于选择读取哪些列
pd.read_csv('xxx.csv', nrows = 10000, usecols = [0, 5, 82, 83])
txt:
# 读取
data=[]
f = open('xxx.txt', 'r')
for line in f:
info1, info2 = line.split(',') # 这里默认一行只有一个","来分割两个数据,可以视情况增加输出
data.append([info1, info2])
f.close
# 一般不建议保存成txt,可以直接保存成csv
3. 增加:
增加一列:
df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns=['a', 'b', 'c'], index = [0,1,2])
df['d']=[4,7,10]
print(df)
# 输出
"""
a b c d
0 1 2 3 4
1 4 5 6 7
2 7 8 9 10
"""
如果增加一列,这一列是用已有的列计算出来的,注意如果原来的df中有’d’这一列,则会把数据替换掉。
df.assign
df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns=['a', 'b', 'c'], index = [0,1,2])
df = df.assign(d = lambda x: x.a+x.b) # a索引列与b索引列相加
print(df)
# 输出
"""
a b c d
0 1 2 3 3
1 4 5 6 9
2 7 8 9 15
"""
df.assign是一个十分强大的函数,下面给出一个更复杂的情况,把df的’a’列的元素向下移动一列放到’d’列中。
df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns=['a', 'b', 'c'])
df.assign(d = lambda x: x.b.shift(1))
# 输出
"""
a b c d
0 1 2 3 NaN
1 4 5 6 2.0
2 7 8 9 5.0
"""
指定位置增加一列
df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns=['a', 'b', 'c'], index = [0,1,2])
df.insert(1,'B',[11,12,13]) #列索引的1位置插入一列
print(df)
# 输出
"""
a B b c
0 1 11 2 3
1 4 12 5 6
2 7 13 8 9
"""
增加一行:
df.append
df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns=['a', 'b', 'c'], index = [0,1,2])
df = df.append({'a':10, 'b':11, 'c':12}, ignore_index=True)
print(df)
# 输出
"""
a b c
0 1 2 3
1 4 5 6
2 7 8 9
3 10 11 12
"""
4. 删除:
df.drop
df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns=['a', 'b', 'c'], index = [0,1,2])
df.drop('a',axis=1, inplace=True) # axis=1删除列,inplace为True表示直接对原表修改且返回None,默认是False
df = df.drop(0,axis=0) # axis=0删除行
print(df)
# 输出
"""
b c
1 5 6
2 8 9
"""
5. 更新
排序
df.sort_values
df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns=['a', 'b', 'c'], index = [0,1,2])
df = df.sort_values('b', ascending=False) # ascending=False表示降序排列
print(df)
# 输出
"""
a b c
2 7 8 9
1 4 5 6
0 1 2 3
"""
也可以根据多个元素进行排序,写前面的优先考虑
df = pd.DataFrame([[1,2,3],[1,5,6],[2,5,9],[2,2,12]], columns=['a', 'b', 'c'], index = [0,1,2,3])
df = df.sort_values(['a', 'b'], ascending=False) # 先按照a列降序排,在a的基础上,考虑b列的降序排
print(df)
# 输出
"""
a b c
2 2 5 9
3 2 2 12
1 1 5 6
0 1 2 3
"""
值得一提的是,这个排序方式也可以排序时间格式类似’2018-10-01 08:00:00’的时间数据。
分组
df.groupby():分组,分组后输出的是一个类,需要用for循环读出。
df = pd.DataFrame([[1,2,3],[1,5,6],[7,8,9],[7,11,12]], columns=['a', 'b', 'c'])
for index, data in df.groupby(['a']):
print(index) # index是分组标签值
print(data) # data是该分组下的dataframe数据
# 输出
"""
1
a b c
0 1 2 3
1 1 5 6
7
a b c
2 7 8 9
3 7 11 12
"""
当然也可以进行多列分组,只需向groupby()传入一个含有多个元素的列表即可,同排序类似,写在前面的优先级高。
一般df.groupby()后,会接一个函数,例如count(),sum()等。
df = pd.DataFrame([[1,2,3],[1,5,6],[7,8,9],[7,11,12]], columns=['a', 'b', 'c'])
print(df.groupby(['a'], as_index=False).count())
# 输出
"""
a b c
0 1 2 2 # b,c列的元素,表示分到a的每一个分组中的记录个数
1 7 2 2
"""
df = pd.DataFrame([[1,2,3],[1,5,6],[7,8,9],[7,11,12]], columns=['a', 'b', 'c'])
print(df.groupby(['a'], as_index=False).sum())
# 输出
"""
a b c
a b c
0 1 7 9 # b,c列的元素,表示分到a的每一个分组中的记录,对应的b,c值的和
1 7 19 21
"""
聚合
df.agg()一般在分组groupby()后进行,可以把我们想要观察的指标,写入一个列表[‘min’, ‘mean’, ‘max’, n0],n0是自定义的,出入agg()。
def n0(x): return sum(x==8) # 计算等于8的个数
df = pd.DataFrame([[1,2,3],[1,5,6],[7,8,9],[7,11,12]], columns=['a', 'b', 'c'])
print(df.groupby(['a'], as_index=False).agg(['min', 'mean', 'max', n0]))
# 输出
"""
b c
min mean max n0 min mean max n0
a
1 2 3.5 5 0 3 4.5 6 0 # 在a=1的分组中,b,c的最小值、平均值、最大值、等于8的个数
7 8 9.5 11 1 9 10.5 12 0
"""
行索引变成外层索引,列索引变成内层索引
df.stack()
df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns=['a', 'b', 'c'], index = [0,1,2])
df.loc[1,'b'] = 'a'
df.stack()
# 输出
"""
0 a 1
b 2
c 3
1 a 4
b a
c 6
2 a 7
b 8
c 9
dtype: object
"""
更新某个值
df.loc
df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns=['a', 'b', 'c'], index = [0,1,2])
df.loc[1,'b'] = 'a'
print(df)
# 输出
"""
a b c
0 1 2 3
1 4 a 6
2 7 8 9
"""
行索引重置
df.reset_index(drop=True)
df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns=['a', 'b', 'c'], index=[1,2,3])
df = df.reset_index(drop=True)
print(df)
# 输出
"""
a b c
0 1 2 3
1 4 5 6
2 7 8 9
"""
6. 显示:
显示一列
df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns=['a', 'b', 'c'])
# 法一 输出series
print(df['a']) # series
# 输出
"""
0 1
1 4
2 7
Name: a, dtype: int64
"""
# 法二 输出dataframe
print(df[['a']])
"""
a
0 1
1 4
2 7
"""
# 法三
print(df.a)
# 输出
"""
0 1
1 4
2 7
Name: a, dtype: int64
"""
显示多列
df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns=['a', 'b', 'c'])
print(df[['a', 'b']])
# 输出
"""
a b
0 1 2
1 4 5
2 7 8
"""
显示一行:
df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns=['a', 'b', 'c'])
print(df.loc[0])
# 输出
"""
a 1
b 2
c 3
Name: 0, dtype: int64
"""
显示某个元素:
df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns=['a', 'b', 'c'])
print(df.loc[1, 'b'])
# 输出
"""
5
"""
暴力法:
利用df.iloc[],把dataframe完全当做二维ndarray进行索引,切片。
df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns=['a', 'b', 'c'])
print(df.iloc[1, :])
# 输出
"""
a 4
b 5
c 6
Name: 1, dtype: int64
"""
关于list与ndarray索引与切片的补充
注意二维list是不能进行二维切片,例如list[1, :]这样的切片,二维ndarray是可以的,因为list的一个[]中不能存在多维索引,ndarray可以 ,具体看下面的例子。
a = [[1,2,3],[4,5,6]]
np_a = np.asarray(a)
a[1][1] # 可以
np_a[1][1] # 可以
a[1,1] # 报错
np_a[1,1] # 可以,同np_a[1][1]
a[1][:] # 可以
np_a[1][:] # 可以
a[1, :] # 报错
np_a[1, :] # 可以,同np_a[1][:]
查看某一行或者某一列有多少元素是1
df = pd.DataFrame([[1,2,3],[1,5,6],[2,5,9],[2,2,12]], columns=['a', 'b', 'c'], index = [0,1,2,3])
def n0(x): return sum(x==1) # 计算等于1的个数
df.apply(n0, axis=0) # 对行或者列执行n0,axis=0是按列,有点像spark那样一个一个的计算
# 输出
"""
a 2
b 0
c 0
dtype: int64
"""
条件筛选:
df = pd.DataFrame([[1,2,3],[4,5,6],[7,5,6],[7,8,9]], columns=['a', 'b', 'c'], index = [0,1,2,3])
print(df[df['b']==5])
# 输出
"""
a b c
1 4 5 6
2 7 5 6
"""
如果要同时满足多个条件,要用&链接,同时加上(),不能用and链接 ,不然会报错:ValueError: The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
df = pd.DataFrame([[1,2,3],[4,5,6],[7,5,6],[7,8,9]], columns=['a', 'b', 'c'], index = [0,1,2,3])
print(df[(df['b']==5) & (df['a']==4)])
# 输出
"""
a b c
1 4 5 6
"""
找出某一列的最大值的行列索引
df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns=['a', 'b', 'c'])
print(df.loc[lambda x: x.a==max(x.a),'a'])
# 输出
"""
2 7
Name: a, dtype: int64
"""
可以把lambda中的x就理解为df自己,和spark中的用法不太一样,spark的lambda中的x一般理解为一行。
7. 数据缺失的处理:
注意,缺失值的表示是np.nan(或np.NaN),不是None。np.nan是没有可比性的,看下面的代码
print(np.nan == np.nan) # 输出False
想要单独判断np.nan,需要使用方法np.isnan()
np.isnan(np.NaN) # 输出True
但是None是有可比性的
print(None == None) # 输出True
如果利用pd.read_csv等读取数据,存在缺失值时,会使用np.nan填充的,我们可以利用下面的方法进行缺失值判断。
df = pd.DataFrame([[1,2,3],[np.NaN,5,6],[7,None,9]], columns=['a', 'b', 'c'])
print(df.isnull())
# 输出
"""
a b c
0 False False False
1 True False False
2 False True False
"""
可以看出来,其实 np.nan与None都会被当做缺失值处理的 ,但实际两者是不一样的。也可以单独对某一列处理。
df = pd.DataFrame([[1,2,3],[np.NaN,5,6],[7,None,9]], columns=['a', 'b', 'c'])
print(df['a'].isnull())
print()
print(pd.isnull(df['a'])) # 与第二行一样的效果
# 输出
"""
0 False
1 True
2 False
Name: a, dtype: bool
0 False
1 True
2 False
Name: a, dtype: bool
"""
我们可以用下面的方法对缺失值进行处理,仍然是同时处理np.nan与None。
# 删掉含有缺失值的记录
df = pd.DataFrame([[1,2,3],[np.NaN,5,6],[7,None,9]], columns=['a', 'b', 'c'])
print(df.dropna())
# 输出
"""
a b c
0 1.0 2.0 3
"""
# 填补0
df = pd.DataFrame([[1,2,3],[np.NaN,5,6],[7,None,9]], columns=['a', 'b', 'c'])
print(df.fillna(0))
# 输出
"""
a b c
0 1.0 2.0 3
1 0.0 5.0 6
2 7.0 0.0 9
"""
# 填补missing字样
df = pd.DataFrame([[1,2,3],[np.NaN,5,6],[7,None,9]], columns=['a', 'b', 'c'])
print(df.fillna('missing'))
# 输出
"""
a b c
0 1 2 3
1 missing 5 6
2 7 missing 9
"""
# 填补上一个数字
df = pd.DataFrame([[1,2,3],[np.NaN,5,6],[7,None,9]], columns=['a', 'b', 'c'])
print(df.fillna(method='pad'))
# 输出
"""
a b c
0 1.0 2.0 3
1 1.0 5.0 6
2 7.0 5.0 9
"""
更多的方法可以看官方文档:http://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.fillna.html
当然,对于不同的情况,我们也许会设计不同的方法进行填充,甚至是特别复杂的方法。
8. 数据连接与合并:
连接
pd.merge的功能同join差不多,可以实现内连接,左外链接,右外连接和全连接,对应的参数how={‘inner’, ‘left’, ‘right’, ‘outer’}。
df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns=['a', 'b', 'c'])
df2 = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns=['a', 'd', 'f'])
output = pd.merge(df, df2, on='a', how='left') # df是左,df2是右
print(output)
# 输出
"""
a b c d f
0 1 2 3 2 3
1 4 5 6 5 6
2 7 8 9 8 9
"""
如果df与df2的用于连接的字段名字不一样
df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns=['a', 'b', 'c'])
df2 = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns=['d', 'e', 'f'])
output = pd.merge(df, df2, left_on='a', right_on='d', how='left').drop('d', axis=1) # 需要手动删除重复的列
print(output)
# 输出
"""
a b c e f
0 1 2 3 2 3
1 4 5 6 5 6
2 7 8 9 8 9
"""
如果右边出现用于连接的字段值重复的情况,会多次链接,以左链接为例,如下
df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns=['a', 'b', 'c'])
df2 = pd.DataFrame([[1,2,3],[1,5,6],[7,8,9]], columns=['d', 'e', 'f'])
output = pd.merge(df, df2, left_on='a', right_on='d', how='left') # 这里没有删除d,所以下面会显示d列
print(output)
# 输出
"""
a b c d e f
0 1 2 3 1.0 2.0 3.0
1 1 2 3 1.0 5.0 6.0
2 4 5 6 NaN NaN NaN
3 7 8 9 7.0 8.0 9.0
"""
所以在进行连接前,要构思好逻辑,可以加去重。
合并
df2拼到df下面
df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns=['a', 'b', 'c'])
df2 = pd.DataFrame([[1,2,3],[1,5,6],[7,8,9]], columns=['a', 'b', 'c'])
output = pd.concat([df, df2], ignore_index=True, axis=0) # axis=0,df2拼到df下面,ignore_index=True即把index重排
print(output)
# 输出
"""
a b c
0 1 2 3
1 4 5 6
2 7 8 9
3 1 2 3
4 1 5 6
5 7 8 9
"""
df2拼到df右面
df = pd.DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns=['a', 'b', 'c'])
df2 = pd.DataFrame([[1,2,3],[1,5,6],[7,8,9]], columns=['a', 'b', 'c'])
output = pd.concat([df, df2], ignore_index=True, axis=1) # ;axis=1,df2拼到df右面
print(output)
# 输出
"""
0 1 2 3 4 5
0 1 2 3 1 2 3
1 4 5 6 1 5 6
2 7 8 9 7 8 9
"""
9. 去重复
df.drop_duplicates().reset_index(drop=True)
df = pd.DataFrame([[1,2,3],[1,2,3],[7,8,9]], columns=['a', 'b', 'c'])
df = df.drop_duplicates().reset_index(drop=True)
print(df)
# 输出
"""
a b c
0 1 2 3
1 7 8 9
"""
10.其它
提取数据,dataframe转list
df.values
df = pd.DataFrame([[1,2,3],[1,2,3],[7,8,9]], columns=['a', 'b', 'c'])
list_df = df.values
print(list_df)
# 输出
"""
[[1 2 3]
[1 2 3]
[7 8 9]]
"""
提取行索引
df.index
df = pd.DataFrame([[1,2,3],[1,2,3],[7,8,9]], columns=['a', 'b', 'c'])
for index in df.index:
print(index)
# 输出
"""
0
1
2
"""
提取列索引
df.columns
df = pd.DataFrame([[1,2,3],[1,2,3],[7,8,9]], columns=['a', 'b', 'c'])
for index in df.columns:
print(index)
# 输出
"""
a
b
c
"""