pandas里面的用法相对非常灵活,经常会有一种需求可以采用多种方式实现的情况。为了方便查找与记忆,特此对pandas里面常见的一些用法
选择指定列是常见的需求,同样的实现方式也非常多。
常用的pd.read_csv方法,如果文件中包含有表头信息,可以直接读取指定列。
pd.read_csv("file", header=0, usecols=['c1', 'c2', 'c3'])
可以使用pd.DataFrame重新构建一个新的dataframe
c1 = ['a', 'b', 'c', 'd']
c2 = [1, 2, 3, 4]
c3 = ['0.1', '0.3', '0.5', '0.7']
data = pd.DataFrame({'c1': c1, 'c2': c2, 'c3': c3})
newdata = pd.DataFrame(data, columns=['c1', 'c2'])
print(newdata)
c1 c2
0 a 1
1 b 2
2 c 3
3 d 4
data = pd.DataFrame({'c1': c1, 'c2': c2, 'c3': c3})
newdata = data[['c1', 'c2']]
print(newdata)
data = pd.DataFrame({'c1': c1, 'c2': c2, 'c3': c3})
newdata = data.loc[:, ['c1', 'c2']]
print(newdata)
data = pd.DataFrame({'c1': c1, 'c2': c2, 'c3': c3})
newdata = data.iloc[:, [0, 1]]
print(newdata)
根据列中元素过滤数据,平时也使用非常多。下面我们看看如何根据列中元素来过滤数据。
pandas中[]是一个boolean表达式,[]里面被计算为true的行都会被选取,可以用来过滤数据。
c1 = ['a', 'a', 'c', 'd']
c2 = [1, 2, 3, 4]
c3 = ['0.1', '0.3', '0.5', '0.7']
data = pd.DataFrame({'c1': c1, 'c2': c2, 'c3': c3})
data1 = data[data.c1=='a']
print(data1)
print()
data2 = data[data.c2 > 2]
print(data2)
print()
data1用来选择c1列值为a的行
data2用来选择c2列值大于2的行。
最后的结果为
c1 c2 c3
0 a 1 0.1
1 a 2 0.3
c1 c2 c3
2 c 3 0.5
3 d 4 0.7
先选取前面三行,再根据c2列过滤
data_head = data.loc[0:2]
data3 = data_head[data_head.c2 < 3]
print(data3)
print()
c1 c2 c3
0 a 1 0.1
1 a 2 0.3
还可以使用apply方法,构造一个返回值为true的更复杂的过滤方法:
data4 = data[data.apply(lambda x: x.c2 < 10 * float(x.c3), axis=1)]
print(data4)
print()
c1 c2 c3
1 a 2 0.3
2 c 3 0.5
3 d 4 0.7
isin方法也可以对列进行过滤,方法名就说明了他是做啥的,不解释。
data5 = data[data.c1.isin(['a'])]
print(data5)
c1 c2 c3
0 a 1 0.1
1 a 2 0.3
删除数据可以使用drop方法。
最常见的为删除某一列,示例如下
c1 = ['a', 'a', 'c', 'd']
c2 = [1, 2, 3, 4]
c3 = ['0.1', '0.3', '0.5', '0.7']
data = pd.DataFrame({'c1': c1, 'c2': c2, 'c3': c3})
data.drop('c3', axis=1)
print(data)
print()
c1 c2 c3
0 a 1 0.1
1 a 2 0.3
2 c 3 0.5
3 d 4 0.7
如果想要在原数据上直接删除,可以将inplace参数设置为True。
data.drop('c3', axis=1, inplace=True)
print(data)
print()
c1 c2
0 a 1
1 a 2
2 c 3
3 d 4
axis=1指定为按列操作。如果想删除几行,将该参数去掉,默认就是axis=0,按行删除。
data.drop([0, 1], axis=0, inplace=True)
print(data)
print()
c1 c2
2 c 3
3 d 4
有的时候我们需要在现有数据中插入数据。下面我们按行与列的方式来分情况讨论。
import pandas as pd
c1 = ['a', 'a', 'c', 'd']
c2 = [1, 2, 3, 4]
c3 = ['0.1', '0.3', '0.5', '0.7']
data = pd.DataFrame({'c1': c1, 'c2': c2, 'c3': c3})
# 在最后插入一列
data.insert(data.shape[1], 'c4', [10, 20, 30, 40])
print(data)
print()
# 在最前面插入一列
data.insert(0, 'c0', ['a0', 'a1', 'a2', 'a3'])
print(data)
print()
# 将c3列插入到最前面
data.insert(0, 'c3', data.pop('c3'))
print(data)
insert方法可以方便用来插入行列数据,具体使用方式为insert(columnindex, columnname, data)。
data.insert(0, 'c3', data.pop('c3'))
是将c3列删除,然后插入到最前面。
pop方法与drop方法的不同在于,pop只能删除指定的列,并且会返回Series,所以我们才能使用insert方法继续插入被pop的Series。而drop可以删除指定的行或者列,默认删除行,并且方法无返回值,可以通过axis=1指定删除列。
代码运行的最后结果为
c1 c2 c3 c4
0 a 1 0.1 10
1 a 2 0.3 20
2 c 3 0.5 30
3 d 4 0.7 40
c0 c1 c2 c3 c4
0 a0 a 1 0.1 10
1 a1 a 2 0.3 20
2 a2 c 3 0.5 30
3 a3 d 4 0.7 40
c3 c0 c1 c2 c4
0 0.1 a0 a 1 10
1 0.3 a1 a 2 20
2 0.5 a2 c 3 30
3 0.7 a3 d 4 40
如果我们想交换两列的位置,比如将c1, c3列互换位置,可以按如下操作。
c1 = ['a', 'a', 'c', 'd']
c2 = [1, 2, 3, 4]
c3 = ['0.1', '0.3', '0.5', '0.7']
data = pd.DataFrame({'c1': c1, 'c2': c2, 'c3': c3})
print(data)
print()
data[['c1', 'c3']] = data[['c3', 'c1']]
print(data)
print()
data.rename(columns={'c1': 'c3', 'c3': 'c1'}, inplace=True)
print(data)
c1 c2 c3
0 a 1 0.1
1 a 2 0.3
2 c 3 0.5
3 d 4 0.7
c1 c2 c3
0 0.1 1 a
1 0.3 2 a
2 0.5 3 c
3 0.7 4 d
c3 c2 c1
0 0.1 1 a
1 0.3 2 a
2 0.5 3 c
3 0.7 4 d
上面的方法主要是两个步骤:
1.首先通过[]直接进行列数据的交换。
2.对columns进行重命名,恢复到原来的名称。
如果我们想在dataframe最后添加一行,如下两种方式都可以
c1 = ['a', 'a', 'c', 'd']
c2 = [1, 2, 3, 4]
c3 = ['0.1', '0.3', '0.5', '0.7']
data = pd.DataFrame({'c1': c1, 'c2': c2, 'c3': c3})
# 末尾添加一行
row = {'c1': 'e', 'c2': 5, 'c3': '0.9'}
data = data.append(row, ignore_index=True)
data.loc[data.shape[0]] = row
如果想在起始位置添加一行,可以使用如下方式
c1 = ['a', 'a', 'c', 'd']
c2 = [1, 2, 3, 4]
c3 = ['0.1', '0.3', '0.5', '0.7']
data = pd.DataFrame({'c1': c1, 'c2': c2, 'c3': c3})
row = {'c1': 'e', 'c2': 5, 'c3': '0.9'}
data.loc[-1] = row
data.index = data.index + 1
data = data.sort_index()
print(data)
输出结果为
c1 c2 c3
0 e 5 0.9
1 a 1 0.1
2 a 2 0.3
3 c 3 0.5
4 d 4 0.7
pandas中的排序可以使用sort_values方法,该方法简洁实用,谁用谁知道。
c1 = ['a', 'a', 'c', 'd']
c2 = [1, 2, 3, 4]
c3 = ['0.1', '0.3', '0.5', '0.7']
data = pd.DataFrame({'c1': c1, 'c2': c2, 'c3': c3})
data.sort_values(by=['c2'], ascending=False, inplace=True)
data.reset_index(drop=True, inplace=True)
print(data)
c1 c2 c3
0 d 4 0.7
1 c 3 0.5
2 a 2 0.3
3 a 1 0.1
其中by是指用来排序的列名,可以传入多个。排序完毕以后,为了后面方便使用,我们对index进行了重置。
如果我们想对多列进行排序
country = ['Chi', 'Chi', 'Chi', 'Jp', 'Jp', 'Aus']
city = ['bj', 'bj', 'sh', 'ty', 'ty', 'sy']
num = [200, 300, 100, 50, 60, 70]
data = pd.DataFrame({'country': country, 'city': city, 'num': num})
data.sort_values(by=['country', 'rate'], ascending=[True, False], inplace=True)
print(data)
上面的代码,即对data先按country降序排列,再按rate进行升序排列。
看个更复杂的例子
country = ['Chi', 'Chi', 'Chi', 'Jp', 'Jp', 'Aus']
city = ['1_bj', '5_bj', '4_sh', '3_ty', '6_ty', '2_sy']
data = pd.DataFrame({'country': country, 'city': city})
data.sort_values(by=['city'], inplace=True)
print(data)
data['newcity'] = data['city'].map(lambda x: x.split('_')[1])
data.sort_values(by=['newcity'], inplace=True)
data.drop('newcity', inplace=True, axis=1)
print(data)
上面的例子中,我们想对city列先按’_'进行分割,分割完毕后取第二个字段进行排序。我们可以先添加一列对整个dataframe进行排序,排序完毕以后再将该列删除。
很多时候我们拿到一个数据,想对其分布情况进行查看,做类似wordcount操作,pandas中的value_counts方法就可以方便进行上述操作。
c1 = ['a', 'a', 'c', 'd']
c2 = [1, 2, 3, 4]
c3 = ['0.1', '0.3', '0.5', '0.7']
data = pd.DataFrame({'c1': c1, 'c2': c2, 'c3': c3})
print(data.c1.value_counts())
print(type(data.c1.value_counts()))
输出结果为
a 2
d 1
c 1
Name: c1, dtype: int64
返回的数据类型为Series结构。
计算占比,是日常数据分析中的常见需求。下面我们通过一个实例来看一下如何计算占比。
import pandas as pd
country = ['Chi', 'Chi', 'Chi', 'Jp', 'Jp', 'Aus']
city = ['bj', 'bj', 'sh', 'ty', 'ty', 'sy']
num = [200, 300, 100, 50, 60, 70]
data = pd.DataFrame({'country': country, 'city': city, 'num': num})
data有三列:country,city,num。我们想计算,每个city在他所在country的num中占比。
涉及到占比,肯定离不开groupby分组操作,先稍微看一下groupby操作。
ret = data.groupby(['country', 'city']).count()
print(ret)
输出如下
num
country city
Aus sy 1
Chi bj 2
sh 1
Jp ty 2
很多时候,我们想要的输出为
country city num
Aus sy 1
Chi bj 2
Chi sh 1
Jp ty 2
为什么上面的结果不是我们想要的?
如果我们查看一下ret的index
print(ret.index)
发现结果如下
MultiIndex([('Aus', 'sy'),
('Chi', 'bj'),
('Chi', 'sh'),
( 'Jp', 'ty')],
names=['country', 'city'])
此时ret的index包含两列,分别为country与city。为了达到我们想要的结果,只需要重新reset_index即可
ret.reset_index(inplace=True)
print(ret)
下面我们实现一下最初计算占比的需求。
country = ['Chi', 'Chi', 'Chi', 'Jp', 'Jp', 'Aus']
city = ['bj', 'bj', 'sh', 'ty', 'ty', 'sy']
num = [200, 300, 100, 50, 60, 70]
data = pd.DataFrame({'country': country, 'city': city, 'num': num})
data['rate'] = data['num'] / data.groupby('country')['num'].transform('sum')
print(data)
上面的代码,按country分组,然后对num进行sum操作,注意sum操作是包含在transform中,这样能保证索引对齐最后按预期输出。
如果我们想根据现有列生成新的列,可以使用map方法来完成。
import pandas as pd
country = ['Chi', 'Chi', 'Chi', 'Jp', 'Jp', 'Aus']
city = ['bj', 'bj', 'sh', 'ty', 'ty', 'sy']
num = [200, 300, 100, 50, 60, 70]
data = pd.DataFrame({'country': country, 'city': city, 'num': num})
data['num2'] = data['num'].map(lambda x: x * 2 if x >= 100 else x + 1 )
print(data)
num2列根据num列生成。如果num列中的数值大于等于100,则乘以2;否则加1。
最后的输出结果为
country city num num2
0 Chi bj 200 400
1 Chi bj 300 600
2 Chi sh 100 200
3 Jp ty 50 51
4 Jp ty 60 61
5 Aus sy 70 71
分位数是统计学中的概念,一般用q表示比较多,q可以是0到1之间的任意数值,常用的四分位数比较出名。
四分位数,是指将数值从小到大排列分成四等份,处于三个分割点位置的数值就是四分位数。
计算分位数位置的方法有两种:
method1: position = (n + 1) * q
method2: pos = 1 + (n-1) * q
pandas中,使用的就是第二种方法。
import pandas as pd
import random
import numpy as np
n1 = [random.randint(1, 10) for _ in range(10)]
n2 = [random.randint(50, 60) for _ in range(10)]
data = pd.DataFrame({'n1': n1, 'n2': n2})
print(data)
print()
r1 = data['n1'].quantile(q = 0.25)
print(r1)
r2 = data['n2'].quantile(q = 0.4)
print(r2)
print()
a = np.array(data['n1'])
b = np.array(data['n2'])
print(np.percentile(a, 25))
print(np.percentile(b, 40))
上面的代码某次运行结果
n1 n2
0 2 53
1 2 55
2 3 52
3 9 58
4 5 53
5 1 55
6 3 57
7 7 51
8 4 51
9 3 50
2.25
52.6
2.25
52.6
可以看到,pandas中的quantile方法与numpy中的percentile方法计算结果是一致的。
稍微需要注意的是,quantile传的q值是0-1之间的浮点数,而percentile中的q值为0-100之间的浮点数。