无法设置从 Numpy 数组读取的适当 dtype
Posted
技术标签:
【中文标题】无法设置从 Numpy 数组读取的适当 dtype【英文标题】:Can't set appropriate dtypes reading from a Numpy array 【发布时间】:2015-11-02 22:28:58 【问题描述】:我想保存数据框的一些属性并给定底层 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())])
【问题讨论】:
您是否尝试将raw_slice
保存到磁盘?
请注意,在这种情况下,没有“底层 numpy 数组”。有两个,因为 numpy 数组是同质的。因此,有一个底层 int64 数组和一个对象/字符串数组。当您执行值时,您实际上是将它们连接到一个数组中,并且它必须是对象,因为其中一个组件数组是对象。
我不知道。很好的资料!
【参考方案1】:
如果您尝试将 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 数组(对象 dtype!)重建子数据帧
和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 数组读取的适当 dtype的主要内容,如果未能解决你的问题,请参考以下文章
无法将 pandas.Series 转换为 dtype=np.float64 的 numpy.array