#python #pandas #dataframe
#python #pandas #фрейм данных
Вопрос:
Я новичок в pandas. Я хочу сравнить два фрейма данных, сгруппированных по 2 столбцам каждого фрейма данных. В у df1
нас есть Brand
и Signal_range
как столбцы. В df2
, у нас есть order
, Brand
и signal
как столбцы. Мне нужно сравнить 2 Brand
и signal
df2 Sinal_range
с df1.
df1
------- -------------------
|Brand | Signal_range
------- -------------------
| AB | {"Weak": {"low": 15, "high": 120}, "Strong": {"low": null, "high": -240}, "Average": {"low": -240, "high": 15}}
| CA |
| FZ | {"Weak": {"low": 10, "high": 100}, "Strong": {"low": null, "high": -200}, "Average": {"low": -200, "high": 10}}
------- ------- ------------
df2
------- ------- --------
|order | Brand | signal |
------- ------- --------
| 1233 | AB | -250 |
| 34565 | AB | 100 |
| 34552 | FZ | 5 |
------- ------- --------
Мне нужно взять signal
бренд df2
и сравнить его df1
с Signal_range
брендом. Если сигнал попадает в диапазон Signal_range
, создайте новый столбец в df1 как логическое значение, как показано ниже
------- ------- -------------------- ------------- ------------
|order | Brand | signal | weak_ind | Average_ind | Strong_ind |
------- ------- -------------------- ------------- ------------
| 1233 | AB | -250 | 0 | 0 | 1 |
| 34565 | AB | 100 | 1 | 0 | 0 |
| 34552 | FZ | 5 | 0 | 1 | 0 |
------- ------- -------- ----------- ------------- ------------
Есть ли какой-либо способ, которым мы можем легко этого добиться?
Ответ №1:
Все дело в prep. Превратите встроенный JSON в столбцы, тогда это прямая логика. Вы не определили свою логику, поэтому я попробовал ее для целей этого примера.
sr = """
|Brand|Signal_range
| AB | {"Weak": {"low": 15, "high": 120}, "Strong": {"low": null, "high": -240}, "Average": {"low": -240, "high": 15}}
| CA |
| FZ | {"Weak": {"low": 10, "high": 100}, "Strong": {"low": null, "high": -200}, "Average": {"low": -200, "high": 10}}"""
df = pd.read_csv(io.StringIO(sr), sep="|", engine="python").drop(columns="Unnamed: 0")
# cleanup the data and convert JSON to columns
df["Brand"] = df["Brand"].str.strip()
df["Signal_range"] = df["Signal_range"].str.strip().replace("", "{}")
df["Signal_range"] = df["Signal_range"].apply(lambda x: json.loads(x))
df = pd.json_normalize(df.to_dict(orient="records"))
df1 = pd.read_csv(io.StringIO("""|order|Brand|signal
| 1233 | AB | -250
| 34565 | AB | 100
| 34552 | FZ | 5 """), sep="|").drop(columns="Unnamed: 0")
df1["Brand"] = df1["Brand"].str.strip()
dfm = df1.merge(df, on="Brand")
# derive columns...
dfm = dfm.assign(
weak_ind=np.where(1, (dfm["Signal_range.Weak.low"]<=dfm["signal"])amp;(dfm["signal"]<=dfm["Signal_range.Weak.high"]), 0),
average_ind=np.where(1, (dfm["Signal_range.Average.low"]<=dfm["signal"])amp;(dfm["signal"]<=dfm["Signal_range.Average.high"]), 0),
strong_ind=np.where(1, (dfm["Signal_range.Strong.low"]<=dfm["signal"])amp;(dfm["signal"]<=dfm["Signal_range.Strong.high"]), 0),
)
dfr = dfm.copy()
print(dfr.drop(columns=[c for c in dfr.columns if "Signal" in c]).to_string(index=False))
вывод
order Brand signal weak_ind average_ind strong_ind
1233 AB -250 0 0 0
34565 AB 100 1 0 0
34552 FZ 5 0 1 0
Комментарии:
1. Привет @Rob Raymod Спасибо, я понял вашу идею, однако я получаю ошибку типа: ‘<=’ не поддерживается между экземплярами ‘float’ и ‘NoneType’ во время dfm.assign(). Есть ли какая-то конкретная причина для этого?
2. это ваши типы данных
dfm.dtypes
возвращаетfloat64
orint64
для всех сигнальных столбцов в данных, которые я сгенерировал из ваших выборочных данных. очевидно, что <= — это сравнение чисел. введите usingastype()
, чтобы преобразовать ваши фактические данные в числовые типы