Python - Pandas 内存中的数据帧连接气球
Python - Pandas dataframe concatenation Balloons in memory
我的原始数据集是一个很大的 JSON 对象列表,用于对药物产生不良反应。在每个 JSON 对象中,我们可以有几种药物以 rxcui ids 的形式产生不良反应。
我已经获取了 JSON 对象的列表并提取了我们需要的重要数据,例如该人是否死亡,以及 rxcui 并将它们展平为最大为 2 的 JSON 对象层次深。我们会有这样的东西:
{
"serious": 1,
"drug": [
"DrugA",
"DrugB",
"DrugC"
],
"rxcui": [
100,
200,
300
]
}
尽我们所能,我必须弄清楚如何将其放入一个数组中,然后我可以将其提供给 ML 算法。所以我的想法是使用one-hot编码。
这就是我使用 countVectorizer 的原因,这样我就可以矢量化所有这些子列表
我正在尝试连接几个 pandas 数据帧(有些是稀疏数据帧,有些是常规数据帧),它们是某些数据的单热编码。我已经检查了所有文件(我还将它们腌制到硬盘上)并且 none 大于 81MB。但是一旦我开始连接它们,它们就会膨胀到超过 29 GB。这怎么可能?
我所有的df都是这样的:
Label0 Label1 Label2 Label3... Label999
1 1 0 0 ... 0
1 1 0 1 ... 1
.
.
.
我 运行 像这样连接:
x = pandas.concat([x, drugcharacterization, occurcountry, reactionmeddrapt, reactionmeddraversionpt, reactionoutcome, rxcui],axis=1, copy=False)
我还可以将我尝试轻松连接的所有子数据帧放入内存中。为什么一旦我这样做它就爆炸了?
编辑:
这是我获取数据框的方式。正如我们所看到的,我无法创建其中之一的稀疏矩阵,它给了我一个错误:
raise ValueError("empty vocabulary; perhaps the documents only contain stop words")
import pandas
from sklearn.feature_extraction.text import CountVectorizer
rr = pandas.DataFrame()
for col in categorical_labels:
print col
try:
vect = CountVectorizer()
X = vect.fit_transform(z[col].astype(str).map(lambda x: ' '.join(x) if isinstance(x, list) else x))
r = pandas.SparseDataFrame(X, columns=vect.get_feature_names(), index=z.index, default_fill_value=0).add_prefix(col + ' = ')
r.to_pickle(col + '_subarr.pkl')
except:
r = z[col].astype(str).str.strip('[]').str.get_dummies(', ').add_prefix(col + ' = ')
r.to_pickle(col + '_subarr.pkl')
rr = pandas.concat([rr,r], axis=1)
这是他们的不雅之处:
drugcharacterization.index
Out[13]: RangeIndex(start=0, stop=234372, step=1)
occurcountry.index
Out[14]: RangeIndex(start=0, stop=234372, step=1)
reactionmeddrapt.index
Out[15]: RangeIndex(start=0, stop=234372, step=1)
reactionmeddraversionpt.index
Out[16]: RangeIndex(start=0, stop=234372, step=1)
reactionoutcome.index
Out[17]: RangeIndex(start=0, stop=234372, step=1)
rxcui.index
Out[18]: RangeIndex(start=0, stop=234372, step=1)
AFAIK pd.concat([...])
生成一个新的 常规 (非稀疏)DataFrame。
考虑以下示例(我使用了 Pandas 0.20.1):
源 DF:
In [118]: df
Out[118]:
text
0 With free-text, each letter is actually an ind...
1 As far as the computer is concerned
2 no individual letter or number has any relatio...
In [119]: another
Out[119]:
a b c
0 10 23 87
1 12 45 32
2 14 76 89
让我们对文本进行一次性编码:
from sklearn.feature_extraction.text import CountVectorizer
vect = CountVectorizer(stop_words='english')
# one-hot-encoded
# for Pandas version < 0.20.1 use: vect.fit_transform(df.text).A
ohe = pd.SparseDataFrame(vect.fit_transform(df.text),
columns=vect.get_feature_names(),
index=df.index,
default_fill_value=0)
结果-SparseDataFrame(注意内存占用):
In [127]: ohe
Out[127]:
actually computer concerned far free independent individual letter number object relationship text
0 1 0 0 0 1 1 0 1 0 1 0 1
1 0 1 1 1 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 1 2 2 0 1 0
In [128]: ohe.memory_usage()
Out[128]:
Index 80
actually 8
computer 8
concerned 8
far 8
free 8
independent 8
individual 8
letter 16
number 8
object 8
relationship 8
text 8
dtype: int64
让我们将此 SparseDataFrame 与源 DF(常规 DF)连接起来:
In [129]: r = pd.concat([another, df, ohe], axis=1)
In [130]: r
Out[130]:
a b c text actually computer concerned far free independent individual \
0 10 23 87 With free-text, each letter is actually an ind... 1 0 0 0 1 1 0
1 12 45 32 As far as the computer is concerned 0 1 1 1 0 0 0
2 14 76 89 no individual letter or number has any relatio... 0 0 0 0 0 0 1
letter number object relationship text
0 1 0 1 0 1
1 0 0 0 0 0
2 2 2 0 1 0
In [131]: r.memory_usage()
Out[131]:
Index 80
a 24
b 24
c 24
text 24
actually 24
computer 24
concerned 24
far 24
free 24
independent 24
individual 24
letter 24
number 24
object 24
relationship 24
text 24
dtype: int64
注意: pd.concat()
创建了一个新的常规 DataFrame,因此所有 "sparsed" 列都被压缩了...
对于纯数字 SparseDataFrames 或 SparseArrays 我们可以使用 scipy.sparse.hstack([...]):
In [149]: from scipy import sparse
In [150]: r = pd.SparseDataFrame(sparse.hstack([ohe, another]),
columns=ohe.columns.append(another.columns))
In [151]: r.memory_usage()
Out[151]:
Index 80
actually 8
computer 8
concerned 8
far 8
free 8
independent 8
individual 8
letter 16
number 8
object 8
relationship 8
text 8
a 24
b 24
c 24
dtype: int64
我怀疑您的数据框不共享索引,因此您构建的数据框比您预期的要大得多。
例如,考虑以下内容:
df1 = pd.DataFrame({'x': [1, 2, 3]}, index=[0, 1, 2])
df2 = pd.DataFrame({'y': [2, 4, 6]}, index=[3, 4, 5])
print(pd.concat([df1, df2], axis=1))
x y
0 1.0 NaN
1 2.0 NaN
2 3.0 NaN
3 NaN 2.0
4 NaN 4.0
5 NaN 6.0
这里我们连接两个数据帧,结果是输入的 4 倍,因为索引不共享。对于您的 7 个数据帧,如果索引的 none 是共享的,则连接结果可能比输入的大小大 ~50 倍。
在没有更多信息的情况下,我无法确定您的情况是否如此,但这就是我开始调查的地方。
我的原始数据集是一个很大的 JSON 对象列表,用于对药物产生不良反应。在每个 JSON 对象中,我们可以有几种药物以 rxcui ids 的形式产生不良反应。
我已经获取了 JSON 对象的列表并提取了我们需要的重要数据,例如该人是否死亡,以及 rxcui 并将它们展平为最大为 2 的 JSON 对象层次深。我们会有这样的东西:
{
"serious": 1,
"drug": [
"DrugA",
"DrugB",
"DrugC"
],
"rxcui": [
100,
200,
300
]
}
尽我们所能,我必须弄清楚如何将其放入一个数组中,然后我可以将其提供给 ML 算法。所以我的想法是使用one-hot编码。
这就是我使用 countVectorizer 的原因,这样我就可以矢量化所有这些子列表
我正在尝试连接几个 pandas 数据帧(有些是稀疏数据帧,有些是常规数据帧),它们是某些数据的单热编码。我已经检查了所有文件(我还将它们腌制到硬盘上)并且 none 大于 81MB。但是一旦我开始连接它们,它们就会膨胀到超过 29 GB。这怎么可能?
我所有的df都是这样的:
Label0 Label1 Label2 Label3... Label999
1 1 0 0 ... 0
1 1 0 1 ... 1
.
.
.
我 运行 像这样连接:
x = pandas.concat([x, drugcharacterization, occurcountry, reactionmeddrapt, reactionmeddraversionpt, reactionoutcome, rxcui],axis=1, copy=False)
我还可以将我尝试轻松连接的所有子数据帧放入内存中。为什么一旦我这样做它就爆炸了?
编辑: 这是我获取数据框的方式。正如我们所看到的,我无法创建其中之一的稀疏矩阵,它给了我一个错误:
raise ValueError("empty vocabulary; perhaps the documents only contain stop words")
import pandas
from sklearn.feature_extraction.text import CountVectorizer
rr = pandas.DataFrame()
for col in categorical_labels:
print col
try:
vect = CountVectorizer()
X = vect.fit_transform(z[col].astype(str).map(lambda x: ' '.join(x) if isinstance(x, list) else x))
r = pandas.SparseDataFrame(X, columns=vect.get_feature_names(), index=z.index, default_fill_value=0).add_prefix(col + ' = ')
r.to_pickle(col + '_subarr.pkl')
except:
r = z[col].astype(str).str.strip('[]').str.get_dummies(', ').add_prefix(col + ' = ')
r.to_pickle(col + '_subarr.pkl')
rr = pandas.concat([rr,r], axis=1)
这是他们的不雅之处:
drugcharacterization.index
Out[13]: RangeIndex(start=0, stop=234372, step=1)
occurcountry.index
Out[14]: RangeIndex(start=0, stop=234372, step=1)
reactionmeddrapt.index
Out[15]: RangeIndex(start=0, stop=234372, step=1)
reactionmeddraversionpt.index
Out[16]: RangeIndex(start=0, stop=234372, step=1)
reactionoutcome.index
Out[17]: RangeIndex(start=0, stop=234372, step=1)
rxcui.index
Out[18]: RangeIndex(start=0, stop=234372, step=1)
AFAIK pd.concat([...])
生成一个新的 常规 (非稀疏)DataFrame。
考虑以下示例(我使用了 Pandas 0.20.1):
源 DF:
In [118]: df
Out[118]:
text
0 With free-text, each letter is actually an ind...
1 As far as the computer is concerned
2 no individual letter or number has any relatio...
In [119]: another
Out[119]:
a b c
0 10 23 87
1 12 45 32
2 14 76 89
让我们对文本进行一次性编码:
from sklearn.feature_extraction.text import CountVectorizer
vect = CountVectorizer(stop_words='english')
# one-hot-encoded
# for Pandas version < 0.20.1 use: vect.fit_transform(df.text).A
ohe = pd.SparseDataFrame(vect.fit_transform(df.text),
columns=vect.get_feature_names(),
index=df.index,
default_fill_value=0)
结果-SparseDataFrame(注意内存占用):
In [127]: ohe
Out[127]:
actually computer concerned far free independent individual letter number object relationship text
0 1 0 0 0 1 1 0 1 0 1 0 1
1 0 1 1 1 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 1 2 2 0 1 0
In [128]: ohe.memory_usage()
Out[128]:
Index 80
actually 8
computer 8
concerned 8
far 8
free 8
independent 8
individual 8
letter 16
number 8
object 8
relationship 8
text 8
dtype: int64
让我们将此 SparseDataFrame 与源 DF(常规 DF)连接起来:
In [129]: r = pd.concat([another, df, ohe], axis=1)
In [130]: r
Out[130]:
a b c text actually computer concerned far free independent individual \
0 10 23 87 With free-text, each letter is actually an ind... 1 0 0 0 1 1 0
1 12 45 32 As far as the computer is concerned 0 1 1 1 0 0 0
2 14 76 89 no individual letter or number has any relatio... 0 0 0 0 0 0 1
letter number object relationship text
0 1 0 1 0 1
1 0 0 0 0 0
2 2 2 0 1 0
In [131]: r.memory_usage()
Out[131]:
Index 80
a 24
b 24
c 24
text 24
actually 24
computer 24
concerned 24
far 24
free 24
independent 24
individual 24
letter 24
number 24
object 24
relationship 24
text 24
dtype: int64
注意: pd.concat()
创建了一个新的常规 DataFrame,因此所有 "sparsed" 列都被压缩了...
对于纯数字 SparseDataFrames 或 SparseArrays 我们可以使用 scipy.sparse.hstack([...]):
In [149]: from scipy import sparse
In [150]: r = pd.SparseDataFrame(sparse.hstack([ohe, another]),
columns=ohe.columns.append(another.columns))
In [151]: r.memory_usage()
Out[151]:
Index 80
actually 8
computer 8
concerned 8
far 8
free 8
independent 8
individual 8
letter 16
number 8
object 8
relationship 8
text 8
a 24
b 24
c 24
dtype: int64
我怀疑您的数据框不共享索引,因此您构建的数据框比您预期的要大得多。
例如,考虑以下内容:
df1 = pd.DataFrame({'x': [1, 2, 3]}, index=[0, 1, 2])
df2 = pd.DataFrame({'y': [2, 4, 6]}, index=[3, 4, 5])
print(pd.concat([df1, df2], axis=1))
x y
0 1.0 NaN
1 2.0 NaN
2 3.0 NaN
3 NaN 2.0
4 NaN 4.0
5 NaN 6.0
这里我们连接两个数据帧,结果是输入的 4 倍,因为索引不共享。对于您的 7 个数据帧,如果索引的 none 是共享的,则连接结果可能比输入的大小大 ~50 倍。
在没有更多信息的情况下,我无法确定您的情况是否如此,但这就是我开始调查的地方。