前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >pandas 处理大数据——如何节省超90%内存

pandas 处理大数据——如何节省超90%内存

作者头像
bugsuse
发布2020-04-21 17:23:06
5.8K0
发布2020-04-21 17:23:06
举报
文章被收录于专栏:气象杂货铺气象杂货铺

使用 pandas 处理小数据集不会遇到性能问题,但是当处理大数据集时(GB级)会遇到性能问题,甚至会因为内存不足而无法处理。

当然使用 spark等工具可以处理大数据集,但是一般的硬件设备使用这些工具也是捉襟见肘,而且 pandas 具有强大的数据清洗方法。当处理的数据量级无需使用spark等工具,使用pandas同样能解决时,该如何提高效率呢?

下面展示如何有效降低 pandas 的内存使用率,甚至降低90%的内存使用。

处理棒球比赛数据

开始之前,我们已经将 130 年的联盟棒球比赛数据进行了处理,并合并为一个文件而且添加了表头信息。

下面我们开始处理数据并查看部分数据信息:

代码语言:javascript
复制
import pandas as pd

gl = pd.read_csv('game_logs.csv')
gl.head
代码语言:javascript
复制
        date   number_of_game   day_of_week   v_name   v_league   ...
0   18710504               0           Thu       CL1       na     ...
1   18710505               0           Fri       BS1       na     ...
2   18710506               0           Sat       CL1       na     ...
3   18710508               0           Mon       CL1       na     ...
4   18710509               0           Tue       BS1       na     ...

下面是数据集中的一些主要列,查看数据集可以获取所有列信息:

  • date - 比赛日期
  • v_name - 客队名
  • v_league - 客队联赛
  • h_name - 主队名
  • h_league - 主队联赛
  • v_score - 客队分数
  • h_score - 主队分数
  • v_line_score - 客队比分
  • h_line_score- 主队比分
  • park_id - 比赛场地ID
  • attendance- 观众数

使用 DataFrame.info 可以获得一些深度信息,比如数据大小,数据类型和使用内存等信息:

默认 pandas 为了节省时间会返回内存使用量的粗略值,为了获取精确值,传递 memory_usage = ’deep‘:

代码语言:javascript
复制
gl.info(memory_usage='deep')
代码语言:javascript
复制
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 171907 entries, 0 to 171906
Columns: 161 entries, date to acquisition_info
dtypes: float64(77), int64(6), object(78)
memory usage: 861.6 MB

数据集中共有 171907 行,161列。pandas 自动获取数据类型:77个浮点数,6个整数,78个对象。内存使用量为 861.8 MB。

因此我们能更好的理解减少内存的使用,下面看看pandas 是如何在内存中存储数据的。

DataFrame的内部呈现

在内部机制中,pandas 会将相同类型的数据分为一组。下面是pandas 如何存储DataFrame中的前12个变量:

因为存储在DataFrame中的真实值经过了优化,因此数据块没有引用列名。BlockManager类保证了行列和真实数据块的映射,相当于获取低层数据的API。我们调用函数和方法选择,编辑,删除DataFrame中的数据时,其实是 BlockManager在’捣鬼‘。

pandas.core.internals 中每种数据类型都有一个特定类。ObjectBlock 类呈现字符串;FloatBlock 类呈现浮点数;。对于数值数据块,pandas 会将其转换为 numpy 数组。Numpy数组构建在C数组基础上,而且连续存储在内存中。基于这种存储机制,访问会非常快。

因为每种数据类型单独存储,因此我们通过数据类型分析内存使用。先看看每种数据类型的平均内存使用量:

代码语言:javascript
复制
for dtype in ['float','int','object']:
    selected_dtype = gl.select_dtypes(include=[dtype])
    mean_usage_b = selected_dtype.memory_usage(deep=True).mean()
    mean_usage_mb = mean_usage_b / 1024 ** 2
    print("Average memory usage for {} columns: {:03.2f} MB".format(dtype,mean_usage_mb))
代码语言:javascript
复制
Average memory usage for float columns: 1.29 MB
Average memory usage for int columns: 1.12 MB
Average memory usage for object columns: 9.53 MB

可以发现 object 占用了大部分内存。抛开这个,我们先看看如何提高数值的内存使用。

理解 Subtypes

之前提及到,pandas 会将数值存储为 Numpy 数组,并且连续存储在内存中。这种存储机制节省了很多空间而且能够提高获取速度。pandas 每种数值类型以相同的字节存储,Numpy数组存储数值,pandas 能够准确快速的返回数值列的字节数。

许多数据类型在pandas中都有一些子类型(subtypes),可以以更少的字节存储每一个值。例如:float 有 float16,float32,float64子类型,类型后的数字表示存储数据的字节数。下面是 pandas 中常见数据类型的子类型:

memory usage

float

int

uint

datetime

bool

object

1 bytes

int8

uint8

bool

2 bytes

float16

int16

uint16

4 bytes

float32

int32

uint32

8 bytes

float64

int64

uint64

datetime64

variable

object

int8 使用了1个字节(8位)存储数据,可以存储256 (2^8)个二进制数据。我们可以使用此类型表示 -128 到 127之间的数据。

使用 numpy.iinfo 表示每一种数据类型所能表示的最大值和最小值:

代码语言:javascript
复制
import numpy as np
int_types = ["uint8", "int8", "int16"]
for it in int_types:
    print(np.iinfo(it))
代码语言:javascript
复制
Machine parameters for uint8
---------------------------------------------------------------
min = 0
max = 255
---------------------------------------------------------------

Machine parameters for int8
---------------------------------------------------------------
min = -128
max = 127
---------------------------------------------------------------

Machine parameters for int16
---------------------------------------------------------------
min = -32768
max = 32767
---------------------------------------------------------------

注意 uint 和 int 的差异:虽然存储能力相同,但是前者表示非负数,而后者表示正负数范围。当仅存储正数的时候,使用 uint 效率更高。

数值优化

使用 pandas.to_numeric 可以对数值类型进行“降维打击”。使用 DataFrame.select_dtypes 只选择整型列,然后优化数据类型并对比内存使用量:

代码语言:javascript
复制
# 计算内存使用量

def mem_usage(pandas_obj):
    if isinstance(pandas_obj,pd.DataFrame):
        usage_b = pandas_obj.memory_usage(deep=True).sum()
    else: # we assume if not a df it's a series
        usage_b = pandas_obj.memory_usage(deep=True)
    usage_mb = usage_b / 1024 ** 2 # convert bytes to megabytes
    return "{:03.2f} MB".format(usage_mb)

gl_int = gl.select_dtypes(include=['int'])
converted_int = gl_int.apply(pd.to_numeric,downcast='unsigned')

print(mem_usage(gl_int))
print(mem_usage(converted_int))

compare_ints = pd.concat([gl_int.dtypes,converted_int.dtypes],axis=1)
compare_ints.columns = ['before','after']
compare_ints.apply(pd.Series.value_counts)
代码语言:javascript
复制
7.87 MB
1.48 MB

       before   after
uint8    NaN     5.0
uint32   NaN     1.0
int64    6.0     NaN

可以看出内存使用量从7.87MB降为1.48MB,节省了80%左右。因为原来的 DataFrame仅包含了很少的整型数据,因此内存节省有限。

让我们来看一下浮点列:

代码语言:javascript
复制
gl_float = gl.select_dtypes(include=['float'])
converted_float = gl_float.apply(pd.to_numeric,downcast='float')

print(mem_usage(gl_float))
print(mem_usage(converted_float))

compare_floats = pd.concat([gl_float.dtypes,converted_float.dtypes],axis=1)
compare_floats.columns = ['before','after']
compare_floats.apply(pd.Series.value_counts)
代码语言:javascript
复制
100.99 MB
50.49 MB

        before   after
float32   NaN    77.0
float64   77.0    NaN

浮点类型从 float64转换位 float32,节省了50%左右的内存使用。

让我们创建一个原DataFrame的副本,将优化后的数值列赋值给原数据,看看节省了多少内存。

代码语言:javascript
复制
optimized_gl = gl.copy()

optimized_gl[converted_int.columns] = converted_int
optimized_gl[converted_float.columns] = converted_float

print(mem_usage(gl))
print(mem_usage(optimized_gl))
代码语言:javascript
复制
861.57 MB

804.69 MB

虽然对数值列的数据类型进行了“降维”,但是总体只降了 7%左右的内存。看来只能优化对象类型了。

开始之前,先对比字符串和数值在 pandas 中的存储。

对比字符串和数值存储

pandas 中使用 Numpy 字符串对象表示 object,有部分是因为 Numpy 中缺乏多缺省字符串值的支持。因为python是高级的脚本语言,并没有对如何在内存中存储数据进行精细的控制。

此限制导致字符串以碎片化的形式存储,消耗了更多内存,导致获取慢。实际上,object列的元素是存储在内存中真实值的指针。

下图展示了数值类型如何以Numpy数据存储以及如何以python内置类型存储字符串:

你可能注意到了,object 使用的是可变大小内存。每一个指针使用1字节,每一个字符串使用的字节数和存储在python中单独存储字符串使用的字节数相同。让我们使用 sys.getsizeof 说明:首先看一下单独的字符串,然后看 pandas Series 中的项:

代码语言:javascript
复制
from sys import getsizeof

s1 = 'working out'
s2 = 'memory usage for'
s3 = 'strings in python is fun!'
s4 = 'strings in python is fun!'
          
for s in [s1, s2, s3, s4]:
    print(getsizeof(s))
代码语言:javascript
复制
60
65
74
74
代码语言:javascript
复制
obj_series = pd.Series(['working out',
                          'memory usage for',
                          'strings in python is fun!',
                          'strings in python is fun!'])
obj_series.apply(getsizeof)
代码语言:javascript
复制
0    60
1    65
2    74
3    74
dtype: int64

可以看出,存储在 pandas 中的字符串的字节数和存储在 python中的字符串字节数相同。

“对象”优化

v0.15开始,pandas 引入了 Categoricals。在低层,category 类型使用整型表示列中的值,而不是原始值。pandas 使用单独的字典来映射原始值和这些整数。当每一列包含有限的数据时,这非常有用。当pandas转换一列为 category 类型时,pandas 会使用最节省空间的 int 子类型表示每一列的唯一值。

为了直观的表示使用此类型可以节省内存,我们来看看每个 object 类型的唯一值数目:

代码语言:javascript
复制
gl_obj = gl.select_dtypes(include=['object']).copy()
gl_obj.describe()
代码语言:javascript
复制
        day_of_week   v_name   v_league   h_name   h_league   ...
count       171907    171907   171907     171907   171907     ...
unique           7       148       7         148       7      ...
top            Sat       CHN       NL        CHN       NL     ...
freq         28891      8870    88866       9024    88867     ...

从上述数据中可以看到,一些列的数据只包含很少的唯一值,也就是说大多数值都是重复的。

先选择一列,看看将其转换为类别类型之后会如何。使用 day_of_week 列数据,只包含了7个唯一值。使用 astype 方法将其转换为 category 类型:

代码语言:javascript
复制
dow = gl_obj.day_of_week
print(dow.head())

dow_cat = dow.astype('category')
print(dow_cat.head())
代码语言:javascript
复制
0    Thu
1    Fri
2    Sat
3    Mon
4    Tue
Name: day_of_week, dtype: object
0    Thu
1    Fri
2    Sat
3    Mon
4    Tue
Name: day_of_week, dtype: category
Categories (7, object): [Fri, Mon, Sat, Sun, Thu, Tue, Wed]

数据类型发生了变化,但是看起来没什么区别。让我们看看低层发生了什么。

下面使用 Series.cat.codes 属性返回 category 类型表示的整型值:

代码语言:javascript
复制
dow_cat.head().cat.codes
代码语言:javascript
复制
0    4
1    0
2    2
3    1
4    5
dtype: int8

每个唯一值都是整型值,数据类型为 int8。上述数据中没有缺省值,如果存在缺省值的话,category会将其转换为 -1。

让我们看看转换为 category 类型前后的内存使用情况:

代码语言:javascript
复制
print(mem_usage(dow))
print(mem_usage(dow_cat))
代码语言:javascript
复制
9.84 MB
0.16 MB

内存使用从 9.84 MB降到 0.16 MB,内存使用减少了98%左右!!

如果转换所有列为 category 类型,那么内存使用量将极大的降低。首要问题是数值计算能力。转换为 category 类型之后,无法对其进行计算,也无法使用 Series.max 和 Sseries.min 等方法。

当唯一值数量少于50%时,应该使用 category 类。如果一列全是唯一值,转换为 category 类会极大的降低内存使用。关于 category 的更多限制见官方文档 [注1]

注意:

如果 category 类型的数目接近数据的数,那么 Categorical 会使用和 object 类型差不多甚至更多的内存。

比如:

代码语言:javascript
复制
>> s = pd.Series(['foo%04d' % i for i in range(2000)])

# object dtype
>> s.nbytes
 16000

# category dtype
>> s.astype('category').nbytes
 20000

使用 Categorical 创建 Series 时,会得到视图而不是副本,就是说对 Series 所做的修改会反馈到 Categorical 。比如 (copy 参数可以控制返回副本):

代码语言:javascript
复制
In [237]: cat = pd.Categorical([1,2,3,10], categories=[1,2,3,4,10])

In [238]: s = pd.Series(cat, name="cat")

In [239]: cat
Out[239]: 
[1, 2, 3, 10]
Categories (5, int64): [1, 2, 3, 4, 10]

In [240]: s.iloc[0:2] = 10

In [241]: cat
Out[241]: 
[10, 10, 3, 10]
Categories (5, int64): [1, 2, 3, 4, 10]

In [242]: df = pd.DataFrame(s)

In [243]: df["cat"].cat.categories = [1,2,3,4,5]

In [244]: cat
Out[244]: 
[5, 5, 3, 5]
Categories (5, int64): [1, 2, 3, 4, 5]

可以通过迭代检查的方式查看唯一值数量是否少于50%,如果是则将其转换为 category 类型:

代码语言:javascript
复制
converted_obj = pd.DataFrame()

for col in gl_obj.columns:
    num_unique_values = len(gl_obj[col].unique())
    num_total_values = len(gl_obj[col])
    if num_unique_values / num_total_values < 0.5:
        converted_obj.loc[:,col] = gl_obj[col].astype('category')
    else:
        converted_obj.loc[:,col] = gl_obj[col]
代码语言:javascript
复制
print(mem_usage(gl_obj))
print(mem_usage(converted_obj))

compare_obj = pd.concat([gl_obj.dtypes,converted_obj.dtypes],axis=1)
compare_obj.columns = ['before','after']
compare_obj.apply(pd.Series.value_counts)
代码语言:javascript
复制
752.72 MB
51.67 MB

          before   after
object       78.0   NaN
category      NaN   78.0

此例中,所有的 object 列都转换为 category 类型。但是在其他情况下可能不会这样,所以要执行上述检查操作。

内存使用量从 752.72 MB 降到 52.67 MB,降低了 93%左右。将其和剩下的 DataFrame 合并,看看一开始的 861 MB内存会节省多少:

代码语言:javascript
复制
optimized_gl[converted_obj.columns] = converted_obj

mem_usage(optimized_gl)
代码语言:javascript
复制
'103.64 MB'

确实有改善!还有一种优化方式,数据列表中的第一列可以用 datetime 来表示:

代码语言:javascript
复制
date = optimized_gl.date
print(mem_usage(date))
date.head()
代码语言:javascript
复制
0.66 MB

0    18710504
1    18710505
2    18710506
3    18710508
4    18710509
Name: date, dtype: uint32

作为整型读入,并且优化为 uint32类型,而datetime 是 64位类型,内存使用将是2倍。但是这样做更方便进行时间序列分析。

使用 pandas.to_datetime 函数进行转换:

代码语言:javascript
复制
optimized_gl['date'] = pd.to_datetime(date,format='%Y%m%d')

print(mem_usage(optimized_gl))
optimized_gl.date.head()
代码语言:javascript
复制
104.29 MB

0   1871-05-04
1   1871-05-05
2   1871-05-06
3   1871-05-08
4   1871-05-09
Name: date, dtype: datetime64[ns]

读入数据时设置数据类型

目前为止,我们探索了一些节省 dataframe 内存占用的方法。先读入,然后优化。之前提到,我们可能没有那么多内存表示数据集中的全部值。如果不能一次读入 DataFrame,那么该如何节省内存呢?

幸运的是,在读入数据集时,我们可以指定最优化数据类型。pandas.read_csv 函数有一些参数可以这样做,dtypes 参数接受一个字典:键为字符串,键值表示 numpy 数据类型。

首先,存储每一列的数据类型到字典中 (先移除日期数据,因为要单独处理):

代码语言:javascript
复制
dtypes = optimized_gl.drop('date',axis=1).dtypes

dtypes_col = dtypes.index
dtypes_type = [i.name for i in dtypes.values]

column_types = dict(zip(dtypes_col, dtypes_type))

# 不需要打印所有项,只需要字典中的10个键值对

preview = first2pairs = {key:value for key,value in list(column_types.items())[:10]}
import pprint
pp = pp = pprint.PrettyPrinter(indent=4)
pp.pprint(preview)
代码语言:javascript
复制
{   'acquisition_info': 'category',
    'h_caught_stealing': 'float32',
    'h_player_1_name': 'category',
    'h_player_9_name': 'category',
    'v_assists': 'float32',
    'v_first_catcher_interference': 'float32',
    'v_grounded_into_double': 'float32',
    'v_player_1_id': 'category',
    'v_player_3_id': 'category',
    'v_player_5_id': 'category'}

现在我们使用字典,然后传入一些参数来处理日期数据从而准确读取日期:

代码语言:javascript
复制
read_and_optimized = pd.read_csv('game_logs.csv',dtype=column_types,parse_dates=['date'],infer_datetime_format=True)

print(mem_usage(read_and_optimized))
read_and_optimized.head()
代码语言:javascript
复制
104.28 MB

   date   number_of_game   day_of_week   v_name   v_league   v_game_number   h_name   h_league   h_game_number   v_score   h_score   length_outs   day_night   completion   forefeit   protest   park_id   attendance   length_minutes   v_line_score   h_line_score   v_at_bats   v_hits   v_doubles   v_triples   v_homeruns   v_rbi   v_sacrifice_hits   v_sacrifice_flies   v_hit_by_pitch   v_walks   v_intentional walks   v_strikeouts   v_stolen_bases   v_caught_stealing   v_grounded_into_double   v_first_catcher_interference   v_left_on_base   v_pitchers_used   v_individual_earned_runs   v_team_earned_runs   v_wild_pitches   v_balks   v_putouts   v_assists   v_errors   v_passed_balls   v_double_plays   v_triple_plays   h_at_bats   h_hits   h_doubles   h_triples   h_homeruns   h_rbi   h_sacrifice_hits   h_sacrifice_flies   h_hit_by_pitch   h_walks   h_intentional walks   h_strikeouts   h_stolen_bases   h_caught_stealing   h_grounded_into_double   h_first_catcher_interference   h_left_on_base   h_pitchers_used   h_individual_earned_runs   h_team_earned_runs   h_wild_pitches   h_balks   h_putouts   h_assists   h_errors   h_passed_balls   h_double_plays   h_triple_plays   hp_umpire_id   hp_umpire_name   1b_umpire_id   1b_umpire_name   2b_umpire_id   2b_umpire_name   3b_umpire_id   3b_umpire_name   lf_umpire_id   lf_umpire_name   rf_umpire_id   rf_umpire_name   v_manager_id   v_manager_name   h_manager_id   h_manager_name   winning_pitcher_id   winning_pitcher_name   losing_pitcher_id   losing_pitcher_name   saving_pitcher_id   saving_pitcher_name   winning_rbi_batter_id   winning_rbi_batter_id_name   v_starting_pitcher_id   v_starting_pitcher_name   h_starting_pitcher_id   h_starting_pitcher_name   v_player_1_id   v_player_1_name   v_player_1_def_pos   v_player_2_id   v_player_2_name   v_player_2_def_pos   v_player_3_id   v_player_3_name   v_player_3_def_pos   v_player_4_id   v_player_4_name   v_player_4_def_pos   v_player_5_id   v_player_5_name   v_player_5_def_pos   v_player_6_id   v_player_6_name   v_player_6_def_pos   v_player_7_id   v_player_7_name   v_player_7_def_pos   v_player_8_id   v_player_8_name   v_player_8_def_pos   v_player_9_id   v_player_9_name   v_player_9_def_pos   h_player_1_id   h_player_1_name   h_player_1_def_pos   h_player_2_id   h_player_2_name   h_player_2_def_pos   h_player_3_id   h_player_3_name   h_player_3_def_pos   h_player_4_id   h_player_4_name   h_player_4_def_pos   h_player_5_id   h_player_5_name   h_player_5_def_pos   h_player_6_id   h_player_6_name   h_player_6_def_pos   h_player_7_id   h_player_7_name   h_player_7_def_pos   h_player_8_id   h_player_8_name   h_player_8_def_pos   h_player_9_id   h_player_9_name   h_player_9_def_pos   additional_info   acquisition_info
0   1871-05-04   0   Thu   CL1   na   1   FW1   na   1   0   2   54.0   D   NaN   NaN   NaN   FOR01   200.0   120.0   000000000   010010000   30.0   4.0   1.0   0.0   0.0   0.0   0.0   0.0   0.0   1.0   -1.0   6.0   1.0   -1.0   -1.0   -1.0   4.0   1.0   1.0   1.0   0.0   0.0   27.0   9.0   0.0   3.0   0.0   0.0   31.0   4.0   1.0   0.0   0.0   2.0   0.0   0.0   0.0   1.0   -1.0   0.0   0.0   -1.0   -1.0   -1.0   3.0   1.0   0.0   0.0   0.0   0.0   27.0   3.0   3.0   1.0   1.0   0.0   boakj901   John Boake   NaN   (none)   NaN   (none)   NaN   (none)   NaN   (none)   NaN   (none)   paboc101   Charlie Pabor   lennb101   Bill Lennon   mathb101   Bobby Mathews   prata101   Al Pratt   NaN   (none)   NaN   (none)   prata101   Al Pratt   mathb101   Bobby Mathews   whitd102   Deacon White   2.0   kimbg101   Gene Kimball   4.0   paboc101   Charlie Pabor   7.0   allia101   Art Allison   8.0   white104   Elmer White   9.0   prata101   Al Pratt   1.0   sutte101   Ezra Sutton   5.0   carlj102   Jim Carleton   3.0   bassj101   John Bass   6.0   selmf101   Frank Sellman   5.0   mathb101   Bobby Mathews   1.0   foraj101   Jim Foran   3.0   goldw101   Wally Goldsmith   6.0   lennb101   Bill Lennon   2.0   caret101   Tom Carey   4.0   mince101   Ed Mincher   7.0   mcdej101   James McDermott   8.0   kellb105   Bill Kelly   9.0   NaN   Y
1   1871-05-05   0   Fri   BS1   na   1   WS3   na   1   20   18   54.0   D   NaN   NaN   NaN   WAS01   5000.0   145.0   107000435   640113030   41.0   13.0   1.0   2.0   0.0   13.0   0.0   0.0   0.0   18.0   -1.0   5.0   3.0   -1.0   -1.0   -1.0   12.0   1.0   6.0   6.0   1.0   0.0   27.0   13.0   10.0   1.0   2.0   0.0   49.0   14.0   2.0   0.0   0.0   11.0   0.0   0.0   0.0   10.0   -1.0   2.0   1.0   -1.0   -1.0   -1.0   14.0   1.0   7.0   7.0   0.0   0.0   27.0   20.0   10.0   2.0   3.0   0.0   dobsh901   Henry Dobson   NaN   (none)   NaN   (none)   NaN   (none)   NaN   (none)   NaN   (none)   wrigh101   Harry Wright   younn801   Nick Young   spala101   Al Spalding   braia102   Asa Brainard   NaN   (none)   NaN   (none)   spala101   Al Spalding   braia102   Asa Brainard   wrigg101   George Wright   6.0   barnr102   Ross Barnes   4.0   birdd102   Dave Birdsall   9.0   mcvec101   Cal McVey   2.0   wrigh101   Harry Wright   8.0   goulc101   Charlie Gould   3.0   schah101   Harry Schafer   5.0   conef101   Fred Cone   7.0   spala101   Al Spalding   1.0   watef102   Fred Waterman   5.0   forcd101   Davy Force   6.0   mille105   Everett Mills   3.0   allid101   Doug Allison   2.0   hallg101   George Hall   7.0   leona101   Andy Leonard   4.0   braia102   Asa Brainard   1.0   burrh101   Henry Burroughs   9.0   berth101   Henry Berthrong   8.0   HTBF   Y
2   1871-05-06   0   Sat   CL1   na   2   RC1   na   1   12   4   54.0   D   NaN   NaN   NaN   RCK01   1000.0   140.0   610020003   010020100   49.0   11.0   1.0   1.0   0.0   8.0   0.0   0.0   0.0   0.0   -1.0   1.0   0.0   -1.0   -1.0   -1.0   10.0   1.0   0.0   0.0   2.0   0.0   27.0   12.0   8.0   5.0   0.0   0.0   36.0   7.0   2.0   1.0   0.0   2.0   0.0   0.0   0.0   0.0   -1.0   3.0   5.0   -1.0   -1.0   -1.0   5.0   1.0   3.0   3.0   1.0   0.0   27.0   12.0   13.0   3.0   0.0   0.0   mawnj901   J.H. Manny   NaN   (none)   NaN   (none)   NaN   (none)   NaN   (none)   NaN   (none)   paboc101   Charlie Pabor   hasts101   Scott Hastings   prata101   Al Pratt   fishc102   Cherokee Fisher   NaN   (none)   NaN   (none)   prata101   Al Pratt   fishc102   Cherokee Fisher   whitd102   Deacon White   2.0   kimbg101   Gene Kimball   4.0   paboc101   Charlie Pabor   7.0   allia101   Art Allison   8.0   white104   Elmer White   9.0   prata101   Al Pratt   1.0   sutte101   Ezra Sutton   5.0   carlj102   Jim Carleton   3.0   bassj101   John Bass   6.0   mackd101   Denny Mack   3.0   addyb101   Bob Addy   4.0   fishc102   Cherokee Fisher   1.0   hasts101   Scott Hastings   8.0   ham-r101   Ralph Ham   5.0   ansoc101   Cap Anson   2.0   sagep101   Pony Sager   6.0   birdg101   George Bird   7.0   stirg101   Gat Stires   9.0   NaN   Y
3   1871-05-08   0   Mon   CL1   na   3   CH1   na   1   12   14   54.0   D   NaN   NaN   NaN   CHI01   5000.0   150.0   101403111   077000000   46.0   15.0   2.0   1.0   2.0   10.0   0.0   0.0   0.0   0.0   -1.0   1.0   0.0   -1.0   -1.0   -1.0   7.0   1.0   6.0   6.0   0.0   0.0   27.0   15.0   11.0   6.0   0.0   0.0   43.0   11.0   2.0   0.0   0.0   8.0   0.0   0.0   0.0   4.0   -1.0   2.0   1.0   -1.0   -1.0   -1.0   6.0   1.0   4.0   4.0   0.0   0.0   27.0   14.0   7.0   2.0   0.0   0.0   willg901   Gardner Willard   NaN   (none)   NaN   (none)   NaN   (none)   NaN   (none)   NaN   (none)   paboc101   Charlie Pabor   woodj106   Jimmy Wood   zettg101   George Zettlein   prata101   Al Pratt   NaN   (none)   NaN   (none)   prata101   Al Pratt   zettg101   George Zettlein   whitd102   Deacon White   2.0   kimbg101   Gene Kimball   4.0   paboc101   Charlie Pabor   7.0   allia101   Art Allison   8.0   white104   Elmer White   9.0   prata101   Al Pratt   1.0   sutte101   Ezra Sutton   5.0   carlj102   Jim Carleton   3.0   bassj101   John Bass   6.0   mcatb101   Bub McAtee   3.0   kingm101   Marshall King   8.0   hodec101   Charlie Hodes   2.0   woodj106   Jimmy Wood   4.0   simmj101   Joe Simmons   9.0   folet101   Tom Foley   7.0   duffe101   Ed Duffy   6.0   pinke101   Ed Pinkham   5.0   zettg101   George Zettlein   1.0   NaN   Y
4   1871-05-09   0   Tue   BS1   na   2   TRO   na   1   9   5   54.0   D   NaN   NaN   NaN   TRO01   3250.0   145.0   000002232   101003000   46.0   17.0   4.0   1.0   0.0   6.0   0.0   0.0   0.0   2.0   -1.0   0.0   1.0   -1.0   -1.0   -1.0   12.0   1.0   2.0   2.0   0.0   0.0   27.0   12.0   5.0   0.0   1.0   0.0   36.0   9.0   0.0   0.0   0.0   2.0   0.0   0.0   0.0   3.0   -1.0   0.0   2.0   -1.0   -1.0   -1.0   7.0   1.0   3.0   3.0   1.0   0.0   27.0   11.0   7.0   3.0   0.0   0.0   leroi901   Isaac Leroy   NaN   (none)   NaN   (none)   NaN   (none)   NaN   (none)   NaN   (none)   wrigh101   Harry Wright   pikel101   Lip Pike   spala101   Al Spalding   mcmuj101   John McMullin   NaN   (none)   NaN   (none)   spala101   Al Spalding   mcmuj101   John McMullin   wrigg101   George Wright   6.0   barnr102   Ross Barnes   4.0   birdd102   Dave Birdsall   9.0   mcvec101   Cal McVey   2.0   wrigh101   Harry Wright   8.0   goulc101   Charlie Gould   3.0   schah101   Harry Schafer   5.0   conef101   Fred Cone   7.0   spala101   Al Spalding   1.0   flync101   Clipper Flynn   9.0   mcgem101   Mike McGeary   2.0   yorkt101   Tom York   8.0   mcmuj101   John McMullin   1.0   kings101   Steve King   7.0   beave101   Edward Beavens   4.0   bells101   Steve Bellan   5.0   pikel101   Lip Pike   3.0   cravb101   Bill Craver   6.0   HTBF   Y

优化之后,内存使用量从 861.6 MB 减少到 104.28 MB,降低了约 88%!!

分析棒球比赛

优化之后,开始进行一些分析。先看看比赛日期的分布:

代码语言:javascript
复制
optimized_gl['year'] = optimized_gl.date.dt.year
games_per_day = optimized_gl.pivot_table(index='year',columns='day_of_week',values='date',aggfunc=len)
games_per_day = games_per_day.divide(games_per_day.sum(axis=1),axis=0)

ax = games_per_day.plot(kind='area',stacked='true')
ax.legend(loc='upper right')
ax.set_ylim(0,1)
plt.show()

1920年以前,棒球比赛很少在周日,随后的半个世纪才开始增多。

来看看比赛时长的变化:

代码语言:javascript
复制
game_lengths = optimized_gl.pivot_table(index='year', values='length_minutes')
game_lengths.reset_index().plot.scatter('year','length_minutes')
plt.show()

1940年之后棒球比赛时长开始增加,从1950年前后开始增速较快。

总结

我们了解到 pandas 使用不同的数据类型存储数据。也是用了技巧有效的降低了内存占用量,而且降低了90%左右!!主要通过以下方式:

  • 数据类型“降维”
  • 转换字符串列为 category 类型

注1:https://pandas.pydata.org/pandas-docs/stable/categorical.html#gotchas

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-08-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 气象杂货铺 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档