You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pandas为何变更DataFrame数据类型?如何保留原类型?

Pandas修改列值后int列变float的问题解析

问题背景

初始DataFrame数据类型:

id                             int64
symbol                         int64
period                         int64
start_at                       int64
open                         float64
high                         float64
low                          float64
close                        float64
volume                         int64
turnover                     float64
cross_seq                      int64
last_apply_1min_timestamp      int64
updated_at                    object
dtype: object

使用循环修改float类型列的值(GetOHIC返回均为float64):

for i in range(len(raw_sql_data_period_1)):
    temp_start_at_timestamp = raw_sql_data_period_1['start_at'].iloc[i]
    temp_data = raw_data[(raw_data['timestamp'] >= temp_start_at_timestamp*1e3) & (raw_data['timestamp'] <= (temp_start_at_timestamp+60)*1e3)]
    if len(temp_data) == 0 :
        continue
    open_price, high, low, close_price = GetOHIC(temp_data)
    raw_sql_data_period_1['open'].iloc[i] = open_price
    raw_sql_data_period_1['high'].iloc[i] = high
    raw_sql_data_period_1['low'].iloc[i] = low
    raw_sql_data_period_1['close'].iloc[i] = close_price

但循环结束后,所有int64列均变为float64:

id                           float64
symbol                       float64
period                       float64
start_at                     float64
open                         float64
high                         float64
low                          float64
close                        float64
volume                       float64
turnover                     float64
cross_seq                    float64
last_apply_1min_timestamp    float64
updated_at                    object
dtype: object

Pandas变更数据类型的场景及原因

  • 链式赋值触发隐式类型提升:你用的df['col'].iloc[i] = ...属于链式索引操作,Pandas无法保证这是在操作原DataFrame的视图还是临时副本。当这种操作触发数据重新分配时,为了避免数据丢失,Pandas会把所有数值列统一转换为更宽泛的类型(float能兼容int,所以int列被强制提升为float)。
  • 底层numpy数组的类型约束:Pandas的数值列基于numpy数组存储,结构化数组在修改时如果出现内存布局变化,会自动提升类型以容纳所有可能的数据——哪怕你只修改了float列,也可能牵连其他int列。
  • 视图/副本的模糊性:链式索引的写法会让Pandas的索引机制混乱,修改操作可能意外作用到临时副本上,导致原DataFrame的元数据(包括类型)被错误更新。

保留原有数据类型的解决方法

1. 用.loc替代链式赋值(最直接)

把循环里的赋值语句改成直接用.loc定位行和列,这是Pandas推荐的修改单值方式,不会创建临时对象,能稳定保留原类型:

raw_sql_data_period_1.loc[i, 'open'] = open_price
raw_sql_data_period_1.loc[i, 'high'] = high
raw_sql_data_period_1.loc[i, 'low'] = low
raw_sql_data_period_1.loc[i, 'close'] = close_price

2. 事后强制转换int列(补救方案)

如果已经出现类型变更,可以手动把int列转回去:

int_columns = ['id', 'symbol', 'period', 'start_at', 'volume', 'cross_seq', 'last_apply_1min_timestamp']
raw_sql_data_period_1[int_columns] = raw_sql_data_period_1[int_columns].astype('int64')

3. 用批量操作替代循环(更高效)

循环逐行修改性能极低,推荐用Pandas的矢量化分组操作来计算OHLC,再合并到原DataFrame,从根源避免类型问题:

# 将raw_data的timestamp转换为分钟级start_at(和原DataFrame对齐)
raw_data['start_at'] = (raw_data['timestamp'] // 1000).astype('int64')
# 分组计算每个时间窗口的OHLC
ohlc_result = raw_data.groupby('start_at').agg(
    open=('price', 'first'),
    high=('price', 'max'),
    low=('price', 'min'),
    close=('price', 'last')
).reset_index()
# 合并到原DataFrame,空值保留原列数据
raw_sql_data_period_1 = raw_sql_data_period_1.merge(ohlc_result, on='start_at', how='left', suffixes=('', '_new'))
raw_sql_data_period_1['open'] = raw_sql_data_period_1['open_new'].fillna(raw_sql_data_period_1['open'])
raw_sql_data_period_1['high'] = raw_sql_data_period_1['high_new'].fillna(raw_sql_data_period_1['high'])
raw_sql_data_period_1['low'] = raw_sql_data_period_1['low_new'].fillna(raw_sql_data_period_1['low'])
raw_sql_data_period_1['close'] = raw_sql_data_period_1['close_new'].fillna(raw_sql_data_period_1['close'])
# 清理临时列
raw_sql_data_period_1 = raw_sql_data_period_1.drop(['open_new', 'high_new', 'low_new', 'close_new'], axis=1)

内容的提问来源于stack exchange,提问作者Molin Liu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 05:50:37