在没有真实索引的情况下重塑 pandas 数据框
Reshaping a pandas dataframe without a true index
过去几周我一直在尝试构建回归输出的数据框,并且我已经完成了大部分工作。我现在正尝试围绕一个列中的某些关键字重塑它,据我所知这是不可调用的。
我的数据框的简化版本如下所示:
? coef pval se rsq
Intercept 1 0 .1 .1
Cash 2 0.2 .05 .1
Food 2 0.05 .2 .1
Intercept 3 0 .1 .2
Cash 1 0.01 .2 .2
Food 2 0.3 .1 .2
Zone 1 0.4 .3 .2
我想要实现的是:
(1) (2)
Intercept coef 1 3
Intercept pval 0 0
Intercept se 0.1 0.1
Cash coef 2 1
Cash pval 0.2 0.01
Cash se 0.05 0.2
Food coef 2 2
Food pval 0.05 0.3
Food se 0.2 0.1
Zone coef NaN 1
Zone pval NaN 0.4
Zone se NaN 0.3
rsq 0.1 0.2
到目前为止,我已经尝试了几种方法,有希望使用 r 平方 (rsq) 作为索引进行重塑 -> RegTable = RegTable.pivot(index='rsq', columns=['pval', 'coef', 'robust_se'])
然而,这 returns 错误 ValueError: all arrays must be same length
。一些研究让我认为这是因为截至目前,zone = NaN
由简单地没有区域行的回归表示,但我不确定如何修复它。此外,我一直无法弄清楚如何调用我标识为“?”的列。使用 PANDAS - 它未在 CSV 输出中标记。此外,这种方法似乎有问题,因为如果两个回归具有相同的 r 平方,它最终将抛出一个新的错误或对每个值进行平均,这两种情况都不是完全可取的。
此解决方案背后的直觉是将数据帧分成大致相等的两个部分。这里的假设是您只有两组数据点,因此这变得易于管理。
print(df)
coef pval se rsq
Intercept 1 0.00 0.10 0.1
Cash 2 0.20 0.05 0.1
Food 2 0.05 0.20 0.1
Intercept 3 0.00 0.10 0.2
Cash 1 0.01 0.20 0.2
Food 2 0.30 0.10 0.2
Zone 1 0.40 0.30 0.2
df_ = df.reset_index().iloc[:, :-1]
df2 = df_.iloc[df_['index'].drop_duplicates(keep='first').to_frame().index]
df1 = df_.iloc[df_['index'].drop_duplicates(keep='last')\
.to_frame().index.difference(df2.index)]
完成此操作后,必须堆叠每个部分,然后沿第一个轴连接起来。
out = pd.concat([df1.set_index('index').stack(),\
df2.set_index('index').stack()], 1)
out.append(pd.DataFrame([df.rsq.unique()], index=[('rsq', '')]))
out.columns = ['1', '2']
print(out)
1 2
index
Cash coef 1.00 2.00
pval 0.01 0.20
se 0.20 0.05
Food coef 2.00 2.00
pval 0.30 0.05
se 0.10 0.20
Intercept coef 3.00 1.00
pval 0.00 0.00
se 0.10 0.10
Zone coef NaN 1.00
pval NaN 0.40
se NaN 0.30
rsq 0.10 0.20
让我们试试这个:
df.set_index(['rsq','?']).stack().unstack([0]).T\
.reset_index().T.rename_axis([None,None])\
.rename(columns={0:'(1)',1:'(2)'})\
.sort_index()
哪里 df:
? coef pval se rsq
0 Intercept 1 0.00 0.10 0.1
1 Cash 2 0.20 0.05 0.1
2 Food 2 0.05 0.20 0.1
3 Intercept 3 0.00 0.10 0.2
4 Cash 1 0.01 0.20 0.2
5 Food 2 0.30 0.10 0.2
6 Zone 1 0.40 0.30 0.2
输出:
(1) (2)
Cash coef 2.00 1.00
pval 0.20 0.01
se 0.05 0.20
Food coef 2.00 2.00
pval 0.05 0.30
se 0.20 0.10
Intercept coef 1.00 3.00
pval 0.00 0.00
se 0.10 0.10
Zone coef NaN 1.00
pval NaN 0.40
se NaN 0.30
rsq 0.10 0.20
这里有一种稍微古怪的方法,可以在不拆分成两个数据帧的情况下执行此操作。
此解决方案重命名索引以跟踪它们所属的回归,在缺少字段时添加 NaN
(如 Zone
的情况)。
然后 groupby
、stack
,并将列表列拆分为 (1)
和 (2)
列(尽管它被概括为处理数据中发生的尽可能多的回归)。
与df
为:
coef pval se rsq
Intercept 1 0 .1 .1
Cash 2 0.2 .05 .1
Food 2 0.05 .2 .1
Intercept 3 0 .1 .2
Cash 1 0.01 .2 .2
Food 2 0.3 .1 .2
Zone 1 0.4 .3 .2
将索引值重命名为 Intercept0
、Intercept1
等:
measures = df.index.unique()
found = {m:0 for m in measures}
for i, name in enumerate(df.index):
if np.max(list(found.values())) > found[name]+1:
df.loc["{}{}".format(name, found[name])] = np.nan
found[name] += 1
df.index.values[i] = "{}{}".format(name, found[name])
found[name] += 1
df
coef pval se rsq
Intercept0 1.0 0.00 0.10 0.1
Cash0 2.0 0.20 0.05 0.1
Food0 2.0 0.05 0.20 0.1
Intercept1 3.0 0.00 0.10 0.2
Cash1 1.0 0.01 0.20 0.2
Food1 2.0 0.30 0.10 0.2
Zone1 1.0 0.40 0.30 0.2
Zone0 NaN NaN NaN NaN
现在排列行,以便将每个回归的元素组合在一起。 (这主要是为了在正确的位置获得 NaN
行。)
order_by_reg = sorted(df.index, key=lambda x: ''.join(reversed(x)))
df = df.loc[order_by_reg]
df
coef pval se rsq
Food0 2.0 0.05 0.20 0.1
Zone0 NaN NaN NaN NaN
Cash0 2.0 0.20 0.05 0.1
Intercept0 1.0 0.00 0.10 0.1
Food1 2.0 0.30 0.10 0.2
Zone1 1.0 0.40 0.30 0.2
Cash1 1.0 0.01 0.20 0.2
Intercept1 3.0 0.00 0.10 0.2
最后,groupby
、stack
,并将列表的结果列拆分为 apply(pd.Series)
:
gb = (df.groupby(lambda x: x[:-1])
.agg(lambda x: list(x))
.stack()
.apply(lambda pair: pd.Series({"({})".format(i):el for i, el in enumerate(pair)})))
gb
(0) (1)
Cash coef 2.00 1.00
pval 0.20 0.01
se 0.05 0.20
rsq 0.10 0.20
Food coef 2.00 2.00
pval 0.05 0.30
se 0.20 0.10
rsq 0.10 0.20
Intercept coef 1.00 3.00
pval 0.00 0.00
se 0.10 0.10
rsq 0.10 0.20
Zone coef NaN 1.00
pval NaN 0.40
se NaN 0.30
rsq NaN 0.20
过去几周我一直在尝试构建回归输出的数据框,并且我已经完成了大部分工作。我现在正尝试围绕一个列中的某些关键字重塑它,据我所知这是不可调用的。
我的数据框的简化版本如下所示:
? coef pval se rsq
Intercept 1 0 .1 .1
Cash 2 0.2 .05 .1
Food 2 0.05 .2 .1
Intercept 3 0 .1 .2
Cash 1 0.01 .2 .2
Food 2 0.3 .1 .2
Zone 1 0.4 .3 .2
我想要实现的是:
(1) (2)
Intercept coef 1 3
Intercept pval 0 0
Intercept se 0.1 0.1
Cash coef 2 1
Cash pval 0.2 0.01
Cash se 0.05 0.2
Food coef 2 2
Food pval 0.05 0.3
Food se 0.2 0.1
Zone coef NaN 1
Zone pval NaN 0.4
Zone se NaN 0.3
rsq 0.1 0.2
到目前为止,我已经尝试了几种方法,有希望使用 r 平方 (rsq) 作为索引进行重塑 -> RegTable = RegTable.pivot(index='rsq', columns=['pval', 'coef', 'robust_se'])
然而,这 returns 错误 ValueError: all arrays must be same length
。一些研究让我认为这是因为截至目前,zone = NaN
由简单地没有区域行的回归表示,但我不确定如何修复它。此外,我一直无法弄清楚如何调用我标识为“?”的列。使用 PANDAS - 它未在 CSV 输出中标记。此外,这种方法似乎有问题,因为如果两个回归具有相同的 r 平方,它最终将抛出一个新的错误或对每个值进行平均,这两种情况都不是完全可取的。
此解决方案背后的直觉是将数据帧分成大致相等的两个部分。这里的假设是您只有两组数据点,因此这变得易于管理。
print(df)
coef pval se rsq
Intercept 1 0.00 0.10 0.1
Cash 2 0.20 0.05 0.1
Food 2 0.05 0.20 0.1
Intercept 3 0.00 0.10 0.2
Cash 1 0.01 0.20 0.2
Food 2 0.30 0.10 0.2
Zone 1 0.40 0.30 0.2
df_ = df.reset_index().iloc[:, :-1]
df2 = df_.iloc[df_['index'].drop_duplicates(keep='first').to_frame().index]
df1 = df_.iloc[df_['index'].drop_duplicates(keep='last')\
.to_frame().index.difference(df2.index)]
完成此操作后,必须堆叠每个部分,然后沿第一个轴连接起来。
out = pd.concat([df1.set_index('index').stack(),\
df2.set_index('index').stack()], 1)
out.append(pd.DataFrame([df.rsq.unique()], index=[('rsq', '')]))
out.columns = ['1', '2']
print(out)
1 2
index
Cash coef 1.00 2.00
pval 0.01 0.20
se 0.20 0.05
Food coef 2.00 2.00
pval 0.30 0.05
se 0.10 0.20
Intercept coef 3.00 1.00
pval 0.00 0.00
se 0.10 0.10
Zone coef NaN 1.00
pval NaN 0.40
se NaN 0.30
rsq 0.10 0.20
让我们试试这个:
df.set_index(['rsq','?']).stack().unstack([0]).T\
.reset_index().T.rename_axis([None,None])\
.rename(columns={0:'(1)',1:'(2)'})\
.sort_index()
哪里 df:
? coef pval se rsq
0 Intercept 1 0.00 0.10 0.1
1 Cash 2 0.20 0.05 0.1
2 Food 2 0.05 0.20 0.1
3 Intercept 3 0.00 0.10 0.2
4 Cash 1 0.01 0.20 0.2
5 Food 2 0.30 0.10 0.2
6 Zone 1 0.40 0.30 0.2
输出:
(1) (2)
Cash coef 2.00 1.00
pval 0.20 0.01
se 0.05 0.20
Food coef 2.00 2.00
pval 0.05 0.30
se 0.20 0.10
Intercept coef 1.00 3.00
pval 0.00 0.00
se 0.10 0.10
Zone coef NaN 1.00
pval NaN 0.40
se NaN 0.30
rsq 0.10 0.20
这里有一种稍微古怪的方法,可以在不拆分成两个数据帧的情况下执行此操作。
此解决方案重命名索引以跟踪它们所属的回归,在缺少字段时添加 NaN
(如 Zone
的情况)。
然后 groupby
、stack
,并将列表列拆分为 (1)
和 (2)
列(尽管它被概括为处理数据中发生的尽可能多的回归)。
与df
为:
coef pval se rsq
Intercept 1 0 .1 .1
Cash 2 0.2 .05 .1
Food 2 0.05 .2 .1
Intercept 3 0 .1 .2
Cash 1 0.01 .2 .2
Food 2 0.3 .1 .2
Zone 1 0.4 .3 .2
将索引值重命名为 Intercept0
、Intercept1
等:
measures = df.index.unique()
found = {m:0 for m in measures}
for i, name in enumerate(df.index):
if np.max(list(found.values())) > found[name]+1:
df.loc["{}{}".format(name, found[name])] = np.nan
found[name] += 1
df.index.values[i] = "{}{}".format(name, found[name])
found[name] += 1
df
coef pval se rsq
Intercept0 1.0 0.00 0.10 0.1
Cash0 2.0 0.20 0.05 0.1
Food0 2.0 0.05 0.20 0.1
Intercept1 3.0 0.00 0.10 0.2
Cash1 1.0 0.01 0.20 0.2
Food1 2.0 0.30 0.10 0.2
Zone1 1.0 0.40 0.30 0.2
Zone0 NaN NaN NaN NaN
现在排列行,以便将每个回归的元素组合在一起。 (这主要是为了在正确的位置获得 NaN
行。)
order_by_reg = sorted(df.index, key=lambda x: ''.join(reversed(x)))
df = df.loc[order_by_reg]
df
coef pval se rsq
Food0 2.0 0.05 0.20 0.1
Zone0 NaN NaN NaN NaN
Cash0 2.0 0.20 0.05 0.1
Intercept0 1.0 0.00 0.10 0.1
Food1 2.0 0.30 0.10 0.2
Zone1 1.0 0.40 0.30 0.2
Cash1 1.0 0.01 0.20 0.2
Intercept1 3.0 0.00 0.10 0.2
最后,groupby
、stack
,并将列表的结果列拆分为 apply(pd.Series)
:
gb = (df.groupby(lambda x: x[:-1])
.agg(lambda x: list(x))
.stack()
.apply(lambda pair: pd.Series({"({})".format(i):el for i, el in enumerate(pair)})))
gb
(0) (1)
Cash coef 2.00 1.00
pval 0.20 0.01
se 0.05 0.20
rsq 0.10 0.20
Food coef 2.00 2.00
pval 0.05 0.30
se 0.20 0.10
rsq 0.10 0.20
Intercept coef 1.00 3.00
pval 0.00 0.00
se 0.10 0.10
rsq 0.10 0.20
Zone coef NaN 1.00
pval NaN 0.40
se NaN 0.30
rsq NaN 0.20