在Python中将一个df中的每一列划分为另一个df中的每一列

时间:2018-10-04 17:45:30

标签: python pandas

美好的一天,

问题:我有两个数据框-每个公司的绩效又称为每个公司的输出和输入:

`firms = ['1', '2', '3']
df = pd.DataFrame(firms)
output = { 'firms': ['1', '2', '3'],
'Sales': [150, 200, 50],
'Profit':[200, 210, 90]}
df1 = pd.DataFrame.from_dict(output)
inputs = { 'firms': ['1', '2', '3'],
'Salary': [10000, 20000, 500],
'employees':[2, 4, 5]}
df2 = pd.DataFrame.from_dict(inputs)`

我需要的是将输出表中的每一列划分为输入表中的每一列。到目前为止,我正在以非常丑陋的方式进行操作-将整个输出tbl除以输入表中的每个单独列,然后将结果合并在一起。当我有两列时,这一切都很好,但是我想知道是否有更好的方法,因为我可能在一个表中有100列,而在另一个表中有50列。嗯,大小可能有所不同也很重要,例如输入表中输入为50列,输出表中输入为100列。

frst = df1.iloc[:,0:2].divide(df2.Salary, axis = 0)
frst.columns = ['y1-x1', 'y2-x1']
sec = df1.iloc[:,0:2].divide(df2.employees, axis = 0)
sec.columns = ['y1-x2', 'y2-x2']
complete = pd.DataFrame(df).join(frst).join(sec)

输出:

|公司y1-x1 | y2-x1 | y1-x2 | y2-x2 |

| 1 | 0.0200 | 0.015 | 100.0 | 75.0 |

| 2 | 0.0105 | 0.010 | 52.5 | 50.0 |

| 3 | 0.1800 | 0.100 | 18.0 | 10.0 |

我也尝试过使用循环,但是如果我没有记错的话,因为在我的实际示例中,我有不同大小的表,因此无法解决。我将非常感谢您的建议!

2 个答案:

答案 0 :(得分:0)

因此,我认为问题在于,您实际上将数据视为三维的,具有维度(公司,成本成分,收入成分),并且您想要三个外部产品的每个比率尺寸。

肯定有一些方法可以完成您想要在DataFrame中完成的工作,但是它们很混乱。

Pandas确实有一个称为Panel的3-D对象,但是this is being deprecated支持一种更完整的解决方案,用于建立索引较高的数据结构xarray。将其视为NDArrays的熊猫。

我们可以通过标记和堆叠索引来将您的数据转换为xarray DataArray:

In [2]: income = df1.set_index('firms').rename_axis(['income'], axis=1).stack('income').to_xarray()

In [3]: income
Out[3]:
<xarray.DataArray (firms: 3, income: 2)>
array([[150, 200],
       [200, 210],
       [ 50,  90]])
Coordinates:
  * firms    (firms) object '1' '2' '3'
  * income   (income) object 'Sales' 'Profit'

In [4]: costs = df2.set_index('firms').rename_axis(['costs'], axis=1).stack('costs').to_xarray()

In [5]: costs
Out[5]:
<xarray.DataArray (firms: 3, costs: 2)>
array([[10000,     2],
       [20000,     4],
       [  500,     5]])
Coordinates:
  * firms    (firms) object '1' '2' '3'
  * costs    (costs) object 'Salary' 'employees'

您现在有两个DataArray,每个DataArray都有两个维度,但是维度不匹配。两者均以firms索引,但收入以income索引,成本以costs索引。

对它们两个执行操作时,它们自动broadcast against each other

In [6]: income / costs
Out[6]:
<xarray.DataArray (firms: 3, income: 2, costs: 2)>
array([[[1.50e-02, 7.50e+01],
        [2.00e-02, 1.00e+02]],

       [[1.00e-02, 5.00e+01],
        [1.05e-02, 5.25e+01]],

       [[1.00e-01, 1.00e+01],
        [1.80e-01, 1.80e+01]]])
Coordinates:
  * firms    (firms) object '1' '2' '3'
  * income   (income) object 'Sales' 'Profit'
  * costs    (costs) object 'Salary' 'employees'

此数据现在具有您要实现的结构,并且该划分是使用优化的cython操作而不是循环来完成的。

您可以使用内置的DataArray.to_series方法将数据转换回数据框:

In [7]: (income / costs).to_series().to_frame(name='income to cost ratio')
Out[7]:
                        income to cost ratio
firms income costs
1     Sales  Salary                   0.0150
             employees               75.0000
      Profit Salary                   0.0200
             employees              100.0000
2     Sales  Salary                   0.0100
             employees               50.0000
      Profit Salary                   0.0105
             employees               52.5000
3     Sales  Salary                   0.1000
             employees               10.0000
      Profit Salary                   0.1800
             employees               18.0000

答案 1 :(得分:0)

我不明白为什么不能只使用一个简单的循环。似乎您想对齐firms上的所有内容,因此将其设置为索引将解决所有不等长的连接或除法。

df1 = df1.set_index('firms')
df2 = df2.set_index('firms')

l = []
for col in df2.columns:
    l.append(df1.div(df2[col], axis=0).add_suffix(f'_by_{col}'))
pd.concat(l, axis=1)

输出:

       Sales_by_Salary  Profit_by_Salary  Sales_by_employees  Profit_by_employees
firms                                                                            
1                0.015            0.0200                75.0                100.0
2                0.010            0.0105                50.0                 52.5
3                0.100            0.1800                10.0                 18.0