Сравните два столбца в двух фреймах данных и создайте логический столбец

#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 or int64 для всех сигнальных столбцов в данных, которые я сгенерировал из ваших выборочных данных. очевидно, что <= — это сравнение чисел. введите using astype() , чтобы преобразовать ваши фактические данные в числовые типы