提升效率的10个pandas技巧

原文链接https://towardsdatascience.com/10-python-pandas-tricks-that-make-your-work-more-efficient-2e8e483808ba

Pandas是一个广泛用于处理结构化数据的Python包。网络上已经有很多很好的教程,但在这里我还是想介绍一些读者可能以前不知道的很酷的技巧,我相信它们很有用。

read_csv

每个人都知道这个命令。但是当你想要读取的数据很大时,那么在加载整个表之前,可以尝试添加这个参数:nrows = 5来读取表的一小部分。这样你就可以避免选择了错误分隔符这类问题(分隔符并非总是逗号形式)。

(或者,您可以在linux中使用’head’命令检查任何文本文件中的前5行(例如):head -c 5 data.txt

然后,您可以通过使用df.columns.tolist()提取所有列来提取列列表,然后添加usecols = ['c1','c2',...]参数来加载所需的列。此外,如果您知道几个特定列的数据类型,还可以通过添加参数dtype = {'c1':str,'c2':int,...},来加快加载速度。此参数的另一个优点是,如果您有一个包含字符串和数字的列,那么将其类型声明为字符串是一个好习惯,这样在尝试使用此列作为键合并表时就不会出错。

select_dtypes

如果数据预处理必须在Python中完成,那么这个命令可以节省你一些时间。读入表后,每列的默认数据类型可以是boolint64float64objectcategorytimedelta64或者datetime64。您可以通过下面的命令查看数据分布情况来了解dataframe中的数据类型

1
df.dtypes.value_counts()

然后执行

1
df.select_dtypes(include=[‘float64’, ‘int64’])

来选择数值类型的dataframe。

copy

如果您还没有听说过,那么这是一个重要的命令。执行以下语句:

1
2
3
4
5
import pandas as pd
df1 = pd.DataFrame({ 'a':[0,0,0], 'b': [1,1,1]})
df2 = df1
df2['a'] = df2['a'] + 1
df1.head()

你会发现df1已经改变了。这是因为df2 = df1没有复制df1并将其分配给df2,而是设置了指向df1的指针。因此,df2的任何变化都会导致df1发生变化。要解决这个问题,你可以采取下面的方法

1
df2 = df1.copy()

或者

1
2
from copy import deepcopy
df2 = deepcopy(df1)

map

这是一个进行数据转换的很酷的命令。首先定义一个字典,其中’keys’是旧值,’values’是新值。

1
2
level_map = {1'high'2'medium'3'low'} 
df ['c_level'] = df ['c'].map(level_map)

比如:True,False转换为1,0编码(用于建模); 定义分段水平; 用户自定义的字典编码。

apply

如果我们想创建一个包含其他几列作为输入的新列,那么apply函数将非常有用。

1
2
3
4
5
6
7
8
def rule(x, y):
if x == 'high' and y > 10:
return 1
else:
return 0
df = pd.DataFrame({ 'c1':[ 'high' ,'high', 'low', 'low'], 'c2': [0, 23, 17, 4]})
df['new'] = df.apply(lambda x: rule(x['c1'], x['c2']), axis = 1)
df.show()

在上面的代码中,我们定义了一个带有两个输入变量的函数,并使用apply函数将它应用于列'c1''c2'

apply的问题是它有时太慢了。比如你想计算两列'c1''c2'的最大值,你当然可以这样做

1
df['maximum'] = df.apply(lambda x: max(x['c1'], x['c2']), axis = 1)

但你会发现它比这个命令慢得多:

1
df['maximum'] = df[['c1','c2']].max(axis =1)

注意:如果您可以使用其他内置函数完成相同的工作(它们通常更快),请不要使用apply。例如,如果要将列'c'舍入为整数,请执行round(df ['c'],0)而不是使用apply函数。

value_counts

这是检查值数值分布的命令。如果您想检查c列中每个值的可能值和频率,您可以执行此操作

1
df['c'].value_counts()

这个命令还有一些有用的技巧和参数:
A.normalize = True:如果你要检查是频率,而不是计数。
B.dropna = False:如果你还想在统计数据中包含缺失值。
C.sort = False:显示按值而不是计数排序的统计数据。
D.df['c'].value_counts().reset_index()如果你想将统计表转换成pandas dataframe并进行操作。

缺失值

构建模型时,您可能希望排除具有太多缺失值的行/具有所有缺失值的行。您可以使用.isnull().sum()来计算指定列中缺失值的数量。

1
2
3
4
5
6
import pandas as pd
import numpy as np
df = pd.DataFrame({ 'id': [1,2,3], 'c1':[0,0,np.nan], 'c2': [np.nan,1,1]})
df = df[['id', 'c1', 'c2']]
df['num_nulls'] = df[['c1', 'c2']].isnull().sum(axis=1)
df.head()

选择具有特定ID的行

在SQL中,我们可以使用SELECT * FROM ... WHERE ID('A001','C022',...)来获取具有特定ID的记录。如果你想用pandas做同样的事情,你可以这样做

1
2
df_filter = df['ID'].isin(['A001','C022',...])
df[df_filter]

百分位组

您有一个数值列,并希望将该列中的值进行分组,例如组1中的前5%,组2中的5-20%,组3中的20%-50%,组4中的50%。当然,你可以用pandas.cut来做,但我想在这里提供另外一种选择:

1
2
3
4
5
6
import numpy as np
cut_points = [np.percentile(df['c'], i) for i in [50, 80, 95]]
df['group'] = 1
for i in range(3):
df['group'] = df['group'] + (df['c'] < cut_points[i])
# or <= cut_points[i]

能够快速运行(没有使用apply方法)。

to_csv

这也是每个人都会使用的命令。我想在这里指出两个技巧。第一个是

1
print(df[:5].to_csv())

您可以使用此命令打印出需要写入文件的前五行。
另一个技巧用来处理混合在一起的整数和缺失值。如果列包含缺失值和整数,则数据类型则是float而不是int。导出表时,可以添加float_format='%.0f'将所有浮点数舍入为整数。如果您只想要所有列的整数输出,请使用此技巧——您将摆脱令人烦恼的小数部分。

坚持原创技术分享,您的支持将鼓励我继续创作!