无法设置从 Numpy 数组读取的适当数据类型
Can't set appropriate dtypes reading from a Numpy array
我想保存数据帧的一些属性并给定底层 numpy 数组的一部分,我想重建数据帧,就好像我已经获取了数据帧的一部分一样。如果一个对象列有一个可以强制转换为浮点数的值,我想不出任何可行的方法。在真实数据集中,我有数百万个观察值和数百个列。
实际用例涉及自定义代码,其中 pandas 与 scikit-learn 交互。我知道最新版本的 scikit-learn 与内置 pandas 兼容,但我无法使用此版本,因为 RandomizedSearchCV 对象无法处理大参数网格(这将在未来版本中修复)。
data = [[2, 4, "Focus"],
[3, 4, "Fiesta",],
[1, 4, "300"],
[7, 3, "Pinto"]]
# This dataframe is exactly as intended
df = pd.DataFrame(data=data)
# Slice a subset of the underlying numpy array
raw_slice = df.values[1:,:]
# Try using the dtype option to force dtypes
df_dtype = pd.DataFrame(data=raw_slice, dtype=df.dtypes)
print "\n Dtype arg doesn't use passed dtypes \n", df_dtype.dtypes
# Try converting objects to numeric after reading into dataframe
df_convert = pd.DataFrame(data=raw_slice).convert_objects(convert_numeric=True)
print "\n Convert objects drops object values that are not numeric \n", df_convert
[Out]
Converted data does not use passed dtypes
0 object
1 object
2 object
dtype: object
Converted data drops object values that are not numeric
0 1 2
0 3 4 NaN
1 1 4 300
2 7 3 NaN
编辑:
谢谢@unutbu 的回答,它准确地回答了我的问题。在 0.16.0 之前的 scikit-learn 版本中,gridsearch 对象从 pandas 数据帧中剥离了底层的 numpy 数组。这意味着单个对象列使整个数组成为一个对象,并且 pandas 方法无法包装在自定义转换器中。
使用@unutbu 的答案的解决方案是使管道的第一步成为自定义 "DataFrameTransformer" 对象。
class DataFrameTransformer(BaseEstimator, TransformerMixin):
def __init__(self, X):
self.columns = list(X.columns)
self.dtypes = X.dtypes
def fit(self, X, y=None):
return self
def transform(self, X, y=None):
X = pd.DataFrame(X, columns=self.columns)
for col, dtype in zip(X, self.dtypes):
X[col] = X[col].astype(dtype)
return X
在管道中,只需将原始 df 包含在构造函数中:
pipeline = Pipeline([("df_converter", DataFrameTransformer(X)),
...,
("rf", RandomForestClassifier())])
如果您尝试将 DataFrame 的一部分保存到磁盘,那么功能强大且
方便的方法是使用 pd.HDFStore
。请注意,这需要
将安装 PyTables。
# To save the slice `df.iloc[1:, :]` to disk:
filename = '/tmp/test.h5'
with pd.HDFStore(filename) as store:
store['mydata'] = df.iloc[1:, :]
# To load the DataFrame from disk:
with pd.get_store(filename) as store:
newdf2 = store['mydata']
print(newdf2.dtypes)
print(newdf2)
产量
0 int64
1 int64
2 object
dtype: object
0 1 2
0 3 4 Fiesta
1 1 4 300
2 7 3 Pinto
从 NumPy 数组(对象数据类型!)重建子数据帧
和 df.dtypes
,你可以使用
import pandas as pd
data = [[2, 4, "Focus"],
[3, 4, "Fiesta",],
[1, 4, "300"],
[7, 3, "Pinto"]]
# This dataframe is exactly as intended
df = pd.DataFrame(data=data)
# Slice a subset of the `values` numpy object array
raw_slice = df.values[1:,:]
newdf = pd.DataFrame(data=raw_slice)
for col, dtype in zip(newdf, df.dtypes):
newdf[col] = newdf[col].astype(dtype)
print(newdf.dtypes)
print(newdf)
产生与上述相同的结果。但是,如果您不保存
raw_slice
到磁盘,那么你可以简单地保留一个
引用 df.iloc[1:, :]
而不是将数据转换为 NumPy 数组
object dtype——一个相对低效的数据结构(在内存和
性能)。
我想保存数据帧的一些属性并给定底层 numpy 数组的一部分,我想重建数据帧,就好像我已经获取了数据帧的一部分一样。如果一个对象列有一个可以强制转换为浮点数的值,我想不出任何可行的方法。在真实数据集中,我有数百万个观察值和数百个列。
实际用例涉及自定义代码,其中 pandas 与 scikit-learn 交互。我知道最新版本的 scikit-learn 与内置 pandas 兼容,但我无法使用此版本,因为 RandomizedSearchCV 对象无法处理大参数网格(这将在未来版本中修复)。
data = [[2, 4, "Focus"],
[3, 4, "Fiesta",],
[1, 4, "300"],
[7, 3, "Pinto"]]
# This dataframe is exactly as intended
df = pd.DataFrame(data=data)
# Slice a subset of the underlying numpy array
raw_slice = df.values[1:,:]
# Try using the dtype option to force dtypes
df_dtype = pd.DataFrame(data=raw_slice, dtype=df.dtypes)
print "\n Dtype arg doesn't use passed dtypes \n", df_dtype.dtypes
# Try converting objects to numeric after reading into dataframe
df_convert = pd.DataFrame(data=raw_slice).convert_objects(convert_numeric=True)
print "\n Convert objects drops object values that are not numeric \n", df_convert
[Out]
Converted data does not use passed dtypes
0 object
1 object
2 object
dtype: object
Converted data drops object values that are not numeric
0 1 2
0 3 4 NaN
1 1 4 300
2 7 3 NaN
编辑: 谢谢@unutbu 的回答,它准确地回答了我的问题。在 0.16.0 之前的 scikit-learn 版本中,gridsearch 对象从 pandas 数据帧中剥离了底层的 numpy 数组。这意味着单个对象列使整个数组成为一个对象,并且 pandas 方法无法包装在自定义转换器中。
使用@unutbu 的答案的解决方案是使管道的第一步成为自定义 "DataFrameTransformer" 对象。
class DataFrameTransformer(BaseEstimator, TransformerMixin):
def __init__(self, X):
self.columns = list(X.columns)
self.dtypes = X.dtypes
def fit(self, X, y=None):
return self
def transform(self, X, y=None):
X = pd.DataFrame(X, columns=self.columns)
for col, dtype in zip(X, self.dtypes):
X[col] = X[col].astype(dtype)
return X
在管道中,只需将原始 df 包含在构造函数中:
pipeline = Pipeline([("df_converter", DataFrameTransformer(X)),
...,
("rf", RandomForestClassifier())])
如果您尝试将 DataFrame 的一部分保存到磁盘,那么功能强大且
方便的方法是使用 pd.HDFStore
。请注意,这需要
将安装 PyTables。
# To save the slice `df.iloc[1:, :]` to disk:
filename = '/tmp/test.h5'
with pd.HDFStore(filename) as store:
store['mydata'] = df.iloc[1:, :]
# To load the DataFrame from disk:
with pd.get_store(filename) as store:
newdf2 = store['mydata']
print(newdf2.dtypes)
print(newdf2)
产量
0 int64
1 int64
2 object
dtype: object
0 1 2
0 3 4 Fiesta
1 1 4 300
2 7 3 Pinto
从 NumPy 数组(对象数据类型!)重建子数据帧
和 df.dtypes
,你可以使用
import pandas as pd
data = [[2, 4, "Focus"],
[3, 4, "Fiesta",],
[1, 4, "300"],
[7, 3, "Pinto"]]
# This dataframe is exactly as intended
df = pd.DataFrame(data=data)
# Slice a subset of the `values` numpy object array
raw_slice = df.values[1:,:]
newdf = pd.DataFrame(data=raw_slice)
for col, dtype in zip(newdf, df.dtypes):
newdf[col] = newdf[col].astype(dtype)
print(newdf.dtypes)
print(newdf)
产生与上述相同的结果。但是,如果您不保存
raw_slice
到磁盘,那么你可以简单地保留一个
引用 df.iloc[1:, :]
而不是将数据转换为 NumPy 数组
object dtype——一个相对低效的数据结构(在内存和
性能)。