0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

pandas的内存使用以及选择合适的数据类型

阿铭linux 来源:机器之心 作者:Josh Devlin 2021-08-17 09:27 次阅读

选自DATAQUEST

作者:Josh Devlin

机器之心编译

当使用 pandas 操作小规模数据(低于 100 MB)时,性能一般不是问题。而当面对更大规模的数据(100 MB 到数 GB)时,性能问题会让运行时间变得更漫长,而且会因为内存不足导致运行完全失败。

尽管 Spark 这样的工具可以处理大型数据集(100 GB 到数 TB),但要完全利用它们的能力,往往需要更加昂贵的硬件。而且和 pandas 不同,它们缺少丰富的用于高质量数据清理、探索和分析的功能集。对于中等规模的数据,我们最好能更充分地利用 pandas,而不是换成另一种工具。

在这篇文章中,我们将了解 pandas 的内存使用,以及如何只需通过为列选择合适的数据类型就能将 dataframe 的内存占用减少近 90%。

处理棒球比赛日志

我们将处理 130 年之久的美国职业棒球大联盟(MLB)比赛数据,这些数据来自 Retrosheet:http://www.retrosheet.org/gamelogs/index.html。

这些数据原来分成了 127 个不同的 CSV 文件,但我们已经使用 csvkit 合并了这些数据,并在第一行增加了列名称。如果你想下载本文所用的这个数据版本,请访问:https://data.world/dataquest/mlb-game-logs。

让我们首先导入数据,并看看其中的前五行:

import pandas as pd

gl = pd.read_csv(‘game_logs.csv’)

gl.head()

下面我们总结了一些重要的列,但如果你想了解所有的列,我们也为整个数据集创建了一个数据词典:https://data.world/dataquest/mlb-game-logs/workspace/data-dictionary。

date - 比赛时间

v_name - 客队名

v_league - 客队联盟

h_name - 主队名

h_league - 主队联盟

v_score - 客队得分

h_score - 主队得分

v_line_score - 客队每局得分排列,例如:010000(10)00.

h_line_score - 主队每局得分排列,例如:010000(10)0X.

park_id - 比赛举办的球场名

attendance- 比赛观众

我们可以使用 DataFrame.info() 方法为我们提供关于 dataframe 的高层面信息,包括它的大小、数据类型的信息和内存使用情况。

默认情况下,pandas 会近似 dataframe 的内存用量以节省时间。因为我们也关心准确度,所以我们将 memory_usage 参数设置为 ‘deep’,以便得到准确的数字。

gl.info(memory_usage=‘deep’)

《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

我们可以看到,我们有 171,907 行和 161 列。pandas 会自动为我们检测数据类型,发现其中有 83 列数据是数值,78 列是 object。object 是指有字符串或包含混合数据类型的情况。

为了更好地理解如何减少内存用量,让我们看看 pandas 是如何将数据存储在内存中的。

dataframe 的内部表示

在 pandas 内部,同样数据类型的列会组织成同一个值块(blocks of values)。这里给出了一个示例,说明了 pandas 对我们的 dataframe 的前 12 列的存储方式。

你可以看到这些块并没有保留原有的列名称。这是因为这些块为存储 dataframe 中的实际值进行了优化。pandas 的 BlockManager 类则负责保留行列索引与实际块之间的映射关系。它可以作为一个 API 使用,提供了对底层数据的访问。不管我们何时选择、编辑或删除这些值,dataframe 类和 BlockManager 类的接口都会将我们的请求翻译成函数和方法的调用。

在 pandas.core.internals 模块中,每一种类型都有一个专门的类。pandas 使用 ObjectBlock 类来表示包含字符串列的块,用 FloatBlock 类表示包含浮点数列的块。对于表示整型数和浮点数这些数值的块,pandas 会将这些列组合起来,存储成 NumPy ndarray。NumPy ndarray 是围绕 C 语言的数组构建的,其中的值存储在内存的连续块中。这种存储方案使得对值的访问速度非常快。

因为每种数据类型都是分开存储的,所以我们将检查不同数据类型的内存使用情况。首先,我们先来看看各个数据类型的平均内存用量。

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))

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

可以看出,78 个 object 列所使用的内存量最大。我们后面再具体谈这个问题。首先我们看看能否改进数值列的内存用量。

理解子类型(subtype)

正如我们前面简单提到的那样,pandas 内部将数值表示为 NumPy ndarrays,并将它们存储在内存的连续块中。这种存储模式占用的空间更少,而且也让我们可以快速访问这些值。因为 pandas 表示同一类型的每个值时都使用同样的字节数,而 NumPy ndarray 可以存储值的数量,所以 pandas 可以快速准确地返回一个数值列所消耗的字节数。

pandas 中的许多类型都有多个子类型,这些子类型可以使用更少的字节来表示每个值。比如说 float 类型就包含 float16、float32 和 float64 子类型。类型名称中的数字就代表该类型表示值的位(bit)数。比如说,我们刚刚列出的子类型就分别使用了 2、4、8、16 个字节。下面的表格给出了 pandas 中最常用类型的子类型:

19b949d8-fe7e-11eb-9bcf-12bb97331649.png

一个 int8 类型的值使用 1 个字节的存储空间,可以表示 256(2^8)个二进制数。这意味着我们可以使用这个子类型来表示从 -128 到 127(包括 0)的所有整数值。

我们可以使用 numpy.iinfo 类来验证每个整型数子类型的最大值和最小值。举个例子:

import numpy as np

int_types = [“uint8”, “int8”, “int16”]

for it in int_types:

print(np.iinfo(it))

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(有符号整型)之间的差异。这两种类型都有一样的存储能力,但其中一个只保存 0 和正数。无符号整型让我们可以更有效地处理只有正数值的列。

使用子类型优化数值列

我们可以使用函数 pd.to_numeric() 来对我们的数值类型进行 downcast(向下转型)操作。我们会使用 DataFrame.select_dtypes 来选择整型列,然后我们会对其数据类型进行优化,并比较内存用量。

# We‘re going to be calculating memory usage a lot,

# so we’ll create a function to save us some time!

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)

7.87 MB

1.48 MB

19c5962a-fe7e-11eb-9bcf-12bb97331649.png

我们可以看到内存用量从 7.9 MB 下降到了 1.5 MB,降低了 80% 以上。但这对我们原有 dataframe 的影响并不大,因为其中的整型列非常少。

让我们对其中的浮点型列进行一样的操作。

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)

100.99 MB

50.49 MB

19da575e-fe7e-11eb-9bcf-12bb97331649.png

我们可以看到浮点型列的数据类型从 float64 变成了 float32,让内存用量降低了 50%。

让我们为原始 dataframe 创建一个副本,并用这些优化后的列替换原来的列,然后看看我们现在的整体内存用量。

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))

861.57 MB

804.69 MB

尽管我们极大地减少了数值列的内存用量,但整体的内存用量仅减少了 7%。我们的大部分收获都将来自对 object 类型的优化。

在我们开始行动之前,先看看 pandas 中字符串的存储方式与数值类型的存储方式的比较。

数值存储与字符串存储的比较

object 类型表示使用 Python 字符串对象的值,部分原因是 NumPy 不支持缺失(missing)字符串类型。因为 Python 是一种高级的解释性语言,它对内存中存储的值没有细粒度的控制能力。

这一限制导致字符串的存储方式很碎片化,从而会消耗更多内存,而且访问速度也更慢。object 列中的每个元素实际上都是一个指针,包含了实际值在内存中的位置的「地址」。

下面这幅图给出了以 NumPy 数据类型存储数值数据和使用 Python 内置类型存储字符串数据的方式。

19e9da1c-fe7e-11eb-9bcf-12bb97331649.jpg

图片来源:https://jakevdp.github.io/blog/2014/05/09/why-python-is-slow/

在前面的表格中,你可能已经注意到 object 类型的内存使用是可变的。尽管每个指针仅占用 1 字节的内存,但如果每个字符串在 Python 中都是单独存储的,那就会占用实际字符串那么大的空间。我们可以使用 sys.getsizeof() 函数来证明这一点,首先查看单个的字符串,然后查看 pandas series 中的项。

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))

60

65

74

74

obj_series = pd.Series([’working out‘,

’memory usage for‘,

’strings in python is fun!‘,

’strings in python is fun!‘])

obj_series.apply(getsizeof)

0 60

1 65

2 74

3 74

dtype: int64

你可以看到,当存储在 pandas series 时,字符串的大小与用 Python 单独存储的字符串的大小是一样的。

使用 Categoricals 优化 object 类型

pandas 在 0.15 版引入了 Categorials。category 类型在底层使用了整型值来表示一个列中的值,而不是使用原始值。pandas 使用一个单独的映射词典将这些整型值映射到原始值。只要当一个列包含有限的值的集合时,这种方法就很有用。当我们将一列转换成 category dtype 时,pandas 就使用最节省空间的 int 子类型来表示该列中的所有不同值。

19ff414a-fe7e-11eb-9bcf-12bb97331649.png

为了了解为什么我们可以使用这种类型来减少内存用量,让我们看看我们的 object 类型中每种类型的不同值的数量。

gl_obj = gl.select_dtypes(include=[’object‘]).copy()

gl_obj.describe()

1a0b0354-fe7e-11eb-9bcf-12bb97331649.png

上图完整图像详见原文

大概看看就能发现,对于我们整个数据集的 172,000 场比赛,其中不同(unique)值的数量可以说非常少。

为了了解当我们将其转换成 categorical 类型时究竟发生了什么,我们拿出一个 object 列来看看。我们将使用数据集的第二列 day_of_week.

看看上表,可以看到其仅包含 7 个不同的值。我们将使用 .astype() 方法将其转换成 categorical 类型。

dow = gl_obj.day_of_week

print(dow.head())

dow_cat = dow.astype(’category‘)

print(dow_cat.head())

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 类型用来表示每个值的整型值。

dow_cat.head().cat.codes

0 4

1 0

2 2

3 1

4 5

dtype: int8

你可以看到每个不同值都被分配了一个整型值,而该列现在的基本数据类型是 int8。这一列没有任何缺失值,但就算有,category 子类型也能处理,只需将其设置为 -1 即可。

最后,让我们看看在将这一列转换为 category 类型前后的内存用量对比。

print(mem_usage(dow))

print(mem_usage(dow_cat))

9.84 MB

0.16 MB

9.8 MB 的内存用量减少到了 0.16 MB,减少了 98%!注意,这个特定列可能代表了我们最好的情况之一——即大约 172,000 项却只有 7 个不同的值。

尽管将所有列都转换成这种类型听起来很吸引人,但了解其中的取舍也很重要。最大的坏处是无法执行数值计算。如果没有首先将其转换成数值 dtype,那么我们就无法对 category 列进行算术运算,也就是说无法使用 Series.min() 和 Series.max() 等方法。

我们应该坚持主要将 category 类型用于不同值的数量少于值的总数量的 50% 的 object 列。如果一列中的所有值都是不同的,那么 category 类型所使用的内存将会更多。因为这一列不仅要存储所有的原始字符串值,还要额外存储它们的整型值代码。你可以在 pandas 文档中了解 category 类型的局限性:http://pandas.pydata.org/pandas-docs/stable/categorical.html。

我们将编写一个循环函数来迭代式地检查每一 object 列中不同值的数量是否少于 50%;如果是,就将其转换成 category 类型。

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]

和之前一样进行比较:

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)

752.72 MB

51.67 MB

1a1611ea-fe7e-11eb-9bcf-12bb97331649.png

在这个案例中,所有的 object 列都被转换成了 category 类型,但并非所有数据集都是如此,所以你应该使用上面的流程进行检查。

object 列的内存用量从 752MB 减少到了 52MB,减少了 93%。让我们将其与我们 dataframe 的其它部分结合起来,看看从最初 861MB 的基础上实现了多少进步。

optimized_gl[converted_obj.columns] = converted_obj

mem_usage(optimized_gl)

’103.64 MB‘

Wow,进展真是不错!我们还可以执行另一项优化——如果你记得前面给出的数据类型表,你知道还有一个 datetime 类型。这个数据集的第一列就可以使用这个类型。

date = optimized_gl.date

print(mem_usage(date))

date.head()

0.66 MB

0 18710504

1 18710505

2 18710506

3 18710508

4 18710509

Name: date, dtype: uint32

你可能记得这一列开始是一个整型,现在已经优化成了 unint32 类型。因此,将其转换成 datetime 类型实际上会让内存用量翻倍,因为 datetime 类型是 64 位的。将其转换成 datetime 类型是有价值的,因为这让我们可以更好地进行时间序列分析。

pandas.to_datetime() 函数可以帮我们完成这种转换,使用其 format 参数将我们的日期数据存储成 YYYY-MM-DD 形式。

optimized_gl[’date‘] = pd.to_datetime(date,format=’%Y%m%d‘)

print(mem_usage(optimized_gl))

optimized_gl.date.head()

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,然后在这个过程中迭代以减少内存占用,我们了解了每种优化方法可以带来的内存减省量。但是正如我们前面提到的一样,我们往往没有足够的内存来表示数据集中的所有值。如果我们一开始甚至无法创建 dataframe,我们又可以怎样应用节省内存的技术呢?

幸运的是,我们可以在读入数据的同时指定最优的列类型。pandas.read_csv() 函数有几个不同的参数让我们可以做到这一点。dtype 参数接受具有(字符串)列名称作为键值(key)以及 NumPy 类型 object 作为值的词典。

首先,我们可将每一列的最终类型存储在一个词典中,其中键值表示列名称,首先移除日期列,因为日期列需要不同的处理方式。

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))

# rather than print all 161 items, we’ll

# sample 10 key/value pairs from the dict

# and print it nicely using prettyprint

preview = first2pairs = {key:value for key,value in list(column_types.items())[:10]}

import pprint

pp = pp = pprint.PrettyPrinter(indent=4)

pp.pprint(preview)

{ ‘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’}

现在我们可以使用这个词典了,另外还有几个参数可用于按正确的类型读入日期,而且仅需几行代码:

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()

104.28 MB

1a21aba4-fe7e-11eb-9bcf-12bb97331649.png

上图完整图像详见原文

通过优化这些列,我们成功将 pandas 的内存占用从 861.6MB 减少到了 104.28MB——减少了惊人的 88%!

分析棒球比赛

现在我们已经优化好了我们的数据,我们可以执行一些分析了。让我们先从了解这些比赛的日期分布开始。

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 年代以前,星期日的棒球比赛很少,但在上个世纪后半叶就变得越来越多了。

我们也可以清楚地看到过去 50 年来,比赛的日期分布基本上没什么大变化了。

让我们再看看比赛时长的变化情况:

game_lengths = optimized_gl.pivot_table(index=‘year’, values=‘length_minutes’)

game_lengths.reset_index().plot.scatter(‘year’,‘length_minutes’)

plt.show()

从 1940 年代以来,棒球比赛的持续时间越来越长。

总结和下一步

我们已经了解了 pandas 使用不同数据类型的方法,然后我们使用这种知识将一个 pandas dataframe 的内存用量减少了近 90%,而且也仅使用了一些简单的技术:

将数值列向下转换成更高效的类型

将字符串列转换成 categorical 类型

责任编辑:haq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 数据
    +关注

    关注

    8

    文章

    7064

    浏览量

    89105
  • 内存
    +关注

    关注

    8

    文章

    3028

    浏览量

    74096

原文标题:简单实用的pandas技巧:如何将内存占用降低90%

文章出处:【微信号:aming_linux,微信公众号:阿铭linux】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    杰和课堂|如何快速选择一款合适的云终端

    选择合适的云终端,应遵循以下原则: 1、场景匹配:根据实际使用场景选择适合的云终端类型,如VDI、IDV或VOI。 2、性能需求:评估所需的处理能力、
    的头像 发表于 12-11 14:19 108次阅读
    杰和课堂|如何快速<b class='flag-5'>选择</b>一款<b class='flag-5'>合适</b>的云终端

    选择数据采集器时需要考虑的因素

    选择数据采集器时,需要考虑以下关键因素,以确保所选设备能够满足特定应用需求并具有良好的性能和可靠性: 采集需求 : 数据类型和数量 :确定需要采集的数据类型(如温度、湿度、压力、位移
    的头像 发表于 11-28 16:02 368次阅读

    如何选择合适的DSP平台

    进行深入分析。这包括: 处理能力 :确定所需的处理速度和精度。 内存需求 :考虑所需的数据存储和缓存大小。 I/O接口 :识别所需的输入/输出接口类型和数量。 功耗 :评估系统的功耗限制。 尺寸和重量 :对于便携式或空间受限的应
    的头像 发表于 11-04 14:28 327次阅读

    如何选择合适的UWB模块

    的非正弦波窄脉冲传输数据,所占的频谱范围很大,数据传输速率高。 应用场景 :UWB模块适用于高精度定位、测距以及需要高速数据传输的场合。 二、确定模块性能指标 测距精度 : 根据应用场
    的头像 发表于 10-31 11:18 437次阅读

    如何选择合适的adc芯片

    开始选择ADC芯片之前,首先要明确你的应用需求。这包括了解信号的特性、系统的工作环境以及性能要求。 信号特性 :包括信号的类型(如音频、视频、温度等),信号的频率范围,以及信号的幅度。
    的头像 发表于 10-31 10:33 368次阅读

    如何选择合适数据光端机型号?

    在现代通信网络中,数据光端机作为一种高速、稳定的数据传输设备,扮演着至关重要的角色。选择合适数据光端机型号,不仅能够确保网络的高效运行,还
    的头像 发表于 10-28 10:27 261次阅读

    AIC23采集到的数据是应该用什么数据类型来接收?int还是unsigned int?

    AIC23采集到的数据是应该用什么数据类型来接收,int还是unsigned int? 这个采集到的数字是什么含义呢?代表的是声音信号的幅值? while(!MCBSP_rrdy(hMcbsp
    发表于 10-18 06:56

    如何选择合适的过载保护器

    选择合适的过载保护器是确保电气系统安全稳定运行的关键步骤。以下将详细阐述如何选择合适的过载保护器,包括考虑的因素、选择步骤
    的头像 发表于 09-06 11:53 938次阅读

    如何选择反射内存

    选择反射内存卡时,需要考虑以下几个关键因素:传输速度和延迟:根据您的应用对数据实时性的要求,选择具有合适传输速度和低延迟的反射
    的头像 发表于 09-05 09:37 255次阅读
    如何<b class='flag-5'>选择</b>反射<b class='flag-5'>内存</b>卡

    labview数据类型的取值范围是多少

    LabVIEW的数据类型丰富多样,涵盖了整数、小数(浮点数)、复数等多种类型,每种类型都有其特定的取值范围。以下是对LabVIEW中常见数据类型取值范围的说明: 整数
    的头像 发表于 09-04 17:33 1125次阅读

    常见的遥感数据类型有哪些

    遥感技术是一种通过遥感器在远离目标的位置获取目标地物的电磁波信息,并进行分析的技术。遥感数据类型繁多,涵盖了从可见光到红外、微波等多个波段,以及不同的数据格式和分辨率。 光学遥感数据
    的头像 发表于 09-04 14:30 1712次阅读

    技术干货驿站 ▏深入理解C语言:基本数据类型和变量

    在C语言中,数据类型和变量是编程的基础,也是理解更复杂概念的关键。数据类型决定了变量的内存分配、存储范围和操作方式,而变量则是存储数据的容器。本篇文章将从基本
    的头像 发表于 07-26 17:53 2165次阅读
    技术干货驿站 ▏深入理解C语言:基本<b class='flag-5'>数据类型</b>和变量

    ESP32-S3是否支持修改控制端点数据类型

    ESP32-S3是否支持修改控制端点数据类型(如标准类型,自定义类型); 我需要在控制传输数据阶段的DATA0包改为我的USB设备规定的8个字节的
    发表于 06-07 06:00

    C语言数据类型有哪些

    在 C 语言中,数据类型指的是用于声明不同类型的变量或函数的一个广泛的系统。变量的类型决定了变量存储占用的空间,以及如何解释存储的位模式。
    发表于 03-20 10:56 486次阅读
    C语言<b class='flag-5'>数据类型</b>有哪些

    arcgis值类型与字段类型不兼容

    数据类型,用于定义字段可以存储的数据范围和格式。常见的字段类型包括整数(int),浮点数(float),日期(date),文本(string)等。当我们在创建数据表或图层时,需要
    的头像 发表于 02-25 11:14 1718次阅读