Python Pandas,如何将MultiIndex DataFrame与单个索引DataFrame连接

时间:2017-11-29 20:58:46

标签: python pandas join merge concatenation

我有一个这种类型的MultiIndex pandas DataFrame:

import pandas as pd

df_multi = pd.DataFrame([['A', 'A1', 0,234,2002],['A', 'A1', 1,324,2550],
['A', 'A1', 2,345,3207],['A', 'A1', 3,458,4560],['A', 'A2', 0,569,1980],
['A', 'A2', 1,657,2314],['A', 'A2', 2,768,4568],['A', 'A2', 3,823,5761]], 
columns=['Product','Scenario','Time','Quantity','Price']).set_index(
['Product', 'Scenario'])

和这种类型的单个索引DataFrame:

df_single = pd.DataFrame([['A', -3,100],['A', -2,100], ['A', -1,100]],
columns=['Product','Time','Quantity']).set_index(['Product'])

对于df_multi的第一个索引级别中的每个“Product”,以及第二个级别中的每个“Scenario”,我想追加/连接df_single中的行,其中包含一些要附加的负“时间”值在df_multi中的正“时间”值开始之前。

我还希望得到的DataFrame首先由['Product','Scenario']进行MultiIndexed(就像df_multi),其次是按'Time'的递增值排序的行。换句话说,期望的结果是:

df_result = pd.DataFrame([['A', 'A1', -3,100,'NaN'],['A', 'A1', -2,100,'NaN'],
['A', 'A1', -1,100,'NaN'],['A', 'A1', 0,234,2002],['A', 'A1', 1,324,2550],
['A', 'A1', 2,345,3207],['A', 'A1', 3,458,4560],['A','A2', -3,100,'NaN'],
['A', 'A2', -2,100,'NaN'],['A', 'A2', -1,100,'NaN'],['A', 'A2', 0,569,1980],
['A', 'A2', 1,657,2314],['A', 'A2', 2,768,4568],['A', 'A2', 3,823,5761]],
columns=['Product','Scenario','Time','Quantity','Price']).set_index(
['Product', 'Scenario'])

编辑:df_single没有'Scenario'值,这可能令人困惑。只要“Product”匹配,df_single的相同行将附加到df_multi中的每个场景,并且它们只是“继承”Scenario值的免费。

我正在使用的实际DataFrame相当大(几千'产品',每个产品几千'方案',每个方案几百'时间'步骤,加上额外的列,我没有写在例如),所以我需要以完全自动化(并且希望快速)的方式做到这一点。

我尝试使用join,concat和merge进行全部实现,但是我没有成功。达到预期结果的最佳方法是什么?

1 个答案:

答案 0 :(得分:0)

考虑将索引重置为nil的列,然后仅 @doc false def changeset(%User{} = user, attrs) do user |> cast(attrs, [:email, :phone]) |> validate_required_inclusion([:email, :phone]) |> validate_required_inclusion_format([:email, :phone]) end defp validate_required_inclusion(changeset, fields) do if Enum.any?(fields, &present?(changeset, &1)) do changeset else # Add the error to the first field only since Ecto requires a field name for each error. add_error(changeset, hd(fields), "One of these fields must be present: #{inspect fields}") end end defp present?(changeset, field) do value = get_field(changeset, field) value && value != "" end ## TODO - this doesnt work defp validate_required_inclusion_format(changeset, fields) do if Enum.member?(fields, :email) do value = get_field(changeset, :email) if value && value != "" do IO.inspect(value, label: "email found: ") changeset |> email_changeset() end end if Enum.member?(fields, :phone) do value = get_field(changeset, :phone) if value && value != "" do IO.inspect(value, label: "phone found: ") changeset |> phone_changeset() end end changeset end defp email_changeset(changeset) do changeset |> validate_required([:email]) |> validate_format(:email, ~r/.+@.+/) |> unique_constraint(:email) end defp phone_changeset(changeset) do changeset |> validate_required([:phone]) |> valid_phone(:phone) |> unique_constraint(:phone) end defp valid_phone(changeset, field) do phone = get_field(changeset, field) IO.inspect(phone, label: "phone: ") {:ok, phone_number} = ExPhoneNumber.parse(phone, "US") IO.inspect(phone_number, label: "ExPhoneNumber: ") if ExPhoneNumber.is_valid_number?(phone_number) do changeset else changeset |> add_error(field, "Invalid Phone Number") end end 聚合,以便每组返回一个匹配项并避免重复。然后,运行连接merge,然后进行列排序并设置多索引。

groupby