从Python调用R的SMOTE函数时,DataFrame出现NA_character_的解决方法
问题:Python调用R的SMOTE算法后生成的少数类样本标签变为NA_character_
我在Python中通过rpy2调用R的SMOTE函数处理不平衡数据集(多数类0占90%,少数类1占10%),直接在R中运行函数能得到正确输出,但Python调用时,新生成的少数类样本对应的y值变成了NA_character_,数量恰好是SMOTE应生成的少数类样本数。
原代码
R函数(r_test.r)
# file r_test.r library(performanceEstimation) rtest <- function(r_df, over_val, under_val) { set.seed(0) new_df <- smote(y ~ ., r_df, perc.over = over_val, perc.under = under_val, k = 5) table(new_df$y) return(new_df) }
Python调用代码
import os import numpy as np import pandas as pd import rpy2.robjects as ro from rpy2.robjects.packages import importr from rpy2.robjects import pandas2ri from rpy2.robjects.conversion import localconverter from sklearn.datasets import make_classification def function2(r_df, over_val, under_val): r=ro.r r.source(path) p=r.rtest(r_df, over_val, under_val) return p path=os.path.join(os.getcwd(), "r_test.r") X, y = make_classification(n_classes=2, class_sep=2, weights=[0.90, 0.10], n_informative=4, n_redundant=1, flip_y=0, n_features=5, n_clusters_per_class=1, n_samples=100, random_state=10) df = pd.DataFrame(X, columns = ["x1", "x2", "x3", "x4", "x5"]) df['y'] = y print(df['y'].value_counts())
输出:
0 90 1 10 Name: y, dtype: int64
base = importr('base') with localconverter(ro.default_converter + pandas2ri.converter): r_from_pd_df = ro.conversion.py2rpy(df) with localconverter(ro.default_converter + pandas2ri.converter): pd_from_r_df = ro.conversion.rpy2py(function2(r_from_pd_df, 5, 2)) print(pd_from_r_df['y'].value_counts())
输出:
0 100 NA_character_ 50 1 10 Name: y, dtype: int64
问题原因
核心是数据类型不兼容:
- R的
smote函数要求响应变量是因子(factor)类型,当输入的y是整数时,函数会自动将其转换为因子。 - 生成新样本后,返回的
y列是因子类型,但rpy2在将R的data.frame转换回pandas的DataFrame时,无法正确将新生成的因子水平映射为原整数类型,导致新样本的标签变成NA_character_。
解决方案
修改R函数,统一输出类型
修改R函数,显式将输入的y转为因子(符合smote要求),生成样本后再将因子转回整数,确保输出的y列是数值类型:
# file r_test.r library(performanceEstimation) rtest <- function(r_df, over_val, under_val) { set.seed(0) # 将输入的y转为因子,满足smote函数要求 r_df$y <- as.factor(r_df$y) new_df <- smote(y ~ ., r_df, perc.over = over_val, perc.under = under_val, k = 5) # 将因子转回整数,避免类型转换问题 new_df$y <- as.integer(as.character(new_df$y)) return(new_df) }
验证结果
重新运行Python代码后,pd_from_r_df['y'].value_counts()的输出应为:
0 100 1 60 Name: y, dtype: int64
其中60个1包含原有的10个样本和SMOTE生成的50个新样本,符合预期。
内容的提问来源于stack exchange,提问作者user22
相关产品推荐
相关产品推荐

