Панды, присваивающие значения фрейму данных, зависящие от значений в другом с теми же размерами проблема / вопрос

#python #pandas #dataframe

#python #pandas #фрейм данных

Вопрос:

Я пытаюсь лучше понять Pandas / Python, поэтому я поиграл с некоторыми вещами. Я столкнулся с проблемой, я знаю некоторые обходные пути, но мне интересно, почему это произошло в первую очередь.

Вот мой полный код, за которым следует объяснение:

 df1 = pd.DataFrame(np.random.rand(5, 10).round(2), index = list(range(1,6)), columns = list(range(1, 11)) )
df2 = pd.DataFrame(index = range(df1.shape[0]), columns = range(df1.shape[1]) )

df2[df1.iloc[:]>0.6] = 1
df2[df1.iloc[:]<0.6] = 0
 

Я создаю 2 фрейма данных. Первый со случайными числами, второй фрейм данных пуст, но имеет те же размеры, что и первый. Основываясь на значениях в первом фрейме данных, я хотел бы изменить значения во втором.

 df1 = pd.DataFrame(np.random.rand(5, 10), index = list(range(1,6)), columns = list(range(1, 11)) )
 

Мой первый созданный мной фрейм данных выглядит так:

 df1

      1      2       3        4      5        6      7       8        9     10
1   0.24    0.03    0.93    0.38    0.03    0.83    0.47    0.85    0.79    0.65
2   0.66    0.25    0.01    0.28    0.19    0.26    0.25    0.48    0.33    0.92
3   0.53    0.33    0.78    0.04    0.36    0.63    0.16    0.16    0.21    0.96
4   0.76    0.03    0.89    0.15    0.24    0.90    0.59    0.41    0.92    0.98
5   0.72    0.45    0.95    0.44    0.79    0.93    0.90    0.48    0.61    0.02
 

Я создаю второй фрейм данных на основе измерений второго:

 df2 = pd.DataFrame(index = range(df1.shape[0]), columns = range(df1.shape[1]) )
 

Что я хотел бы сделать сейчас, так это сказать, что для значений, которые больше 0,6 в df1, я бы хотел, чтобы соответствующее значение в df2 было равно 1. И для значений меньше 0,6 я бы хотел, чтобы значения были равны 0.

Я сделал это следующим образом, разрезав df1, а затем используя этот фрагмент для df2, а затем присвоив значения.

 df2[df1.loc[:]>0.6] = 1
df2[df1.loc[:]<0.6] = 0
 

Я думал, что это сработает, но вместо этого первая строка и первый столбец по-прежнему являются NaNs

 df2

         0   1   2   3   4  5   6   7   8   9
 0      NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
 1      NaN  0   0   1   0   0   1   0   1   1
 2      NaN  1   0   0   0   0   0   0   0   0
 3      NaN  0   0   1   0   0   1   0   0   0
 4      NaN  1   0   1   0   0   1   0   0   1
 

Я думаю, причина, по которой это не сработало, заключается в том, что имена столбцов и имена строк не совпадают между двумя индексами, но я пытаюсь понять, почему это происходит.

Я думал, что когда я нарезал df1 на основе условия, он создал массив истинных / ложных данных, который я мог бы использовать в любом другом фрейме данных с тем же измерением:

 [df1.loc[:]>0.6]
 

r

        1      2      3      4      5      6      7      8      9      10
  1  False  False   True  False  False   True  False   True   True   True
  2   True  False  False  False  False  False  False  False  False   True
  3  False  False   True  False  False   True  False  False  False   True
  4   True  False   True  False  False   True  False  False   True   True
  5   True  False   True  False   True   True   True  False   True  False
 

Я думал, что приведенное выше сопоставление истинных и ложных значений можно использовать где угодно, но, похоже, это невозможно. Есть ли способ обойти это, не требующий переименования столбцов / строк для сопоставления между 2 фреймами данных?

Ответ №1:

Просто нужно сделать:

 import pandas as pd
import numpy as np

np.random.seed(42)  # for reproducibility
df1 = pd.DataFrame(np.random.rand(5, 10), index = list(range(1,6)), columns = list(range(1, 11)))
df2 = df1 > 0.6
print(df2)
 

Выходной сигнал

       1      2      3      4      5      6      7      8      9      10
1  False   True   True  False  False  False  False   True   True   True
2  False   True   True  False  False  False  False  False  False  False
3   True  False  False  False  False   True  False  False  False  False
4   True  False  False   True   True   True  False  False   True  False
5  False  False  False   True  False   True  False  False  False  False
 

Если нужно, чтобы выходные данные были целочисленными:

 df2 = (df1 > 0.6).astype(int)
print(df2)
 

Вывод (целое число)

    1   2   3   4   5   6   7   8   9   10
1   0   1   1   0   0   0   0   1   1   1
2   0   1   1   0   0   0   0   0   0   0
3   1   0   0   0   0   1   0   0   0   0
4   1   0   0   1   1   1   0   0   1   0
5   0   0   0   1   0   1   0   0   0   0
 

Если необходимо сопоставить значения со значениями True и False, используйте np.где:

 df2 = (df1 > 0.6)
df2[:] = np.where(df2, 'M', 'F')
print(df2)
 

Выход (где)

   1  2  3  4  5  6  7  8  9  10
1  F  M  M  F  F  F  F  M  M  M
2  F  M  M  F  F  F  F  F  F  F
3  M  F  F  F  F  M  F  F  F  F
4  M  F  F  M  M  M  F  F  M  F
5  F  F  F  M  F  M  F  F  F  F
 

Комментарии:

1. Что ж, черт возьми, это, кажется, приближает меня к цели. Если вы не возражаете, у меня есть несколько дополнительных вопросов. Когда я это делаю, df2 превращается в true и false, любой способ преобразовать это в 0s и 1s или любые другие 2 значения? Кроме того, я действительно хочу понять, почему способ нарезки, который я пробовал, зависит от названия столбцов и строк? Есть ли способ просто создать общий массив истинных / ложных значений, который может быть применен к любому фрейму данных независимо от имени строк или столбцов?

2. «Pandas выравнивает все ОСИ при настройке рядов и фрейма данных из .loc и .iloc». Индексирование фрейма данных с помощью оператора [] будет использовать любой доступный индекс. Фреймы данных в ваших примерах имеют разные индексы, поэтому здесь это работает как внешнее соединение SQL. pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html

3. @MSCRN обновил ответ примерами для ваших вопросов. Я не понимаю: кроме того, я действительно хочу понять, почему способ нарезки, который я пробовал, зависит от имени столбцов и строк? Есть ли способ просто создать общий массив истинных / ложных значений, который может быть применен к любому фрейму данных независимо от имени строк или столбцов?

4. @skuzzy Я думаю, что я следую, хотя я не уверен в бите внешнего соединения SQL. Итак, если я понимаю, если вы используете, .loc , .iloc или оператор [], Pandas сначала проверяет соответствие осей (столбцов и строк) на основе их имен, а не на позиции?

5. Позиция может иметь много значений. Как вы определяете позицию в фрейме данных, который может иметь много уровней / уровней? То, о чем вы думаете, — это относительные координаты. Индексы — это своего рода абсолютные координаты. В качестве примера возьмем студентов из двух университетов. Является ли первый ранг в университете 1 эквивалентным первому рангу в университете 2?

Ответ №2:

Попробуйте с np.where помощью , обратите внимание, что здесь находится открытая ячейка, что означает, что будет возвращено значение, равное 0.6 NaN

 df2[:] = np.where(df1>0.6,1,0)
df2
   0  1  2  3  4  5  6  7  8  9
0  0  1  1  1  0  0  0  0  1  0
1  1  0  0  0  0  0  1  1  0  0
2  1  0  0  1  1  0  1  0  1  1
3  1  0  0  1  1  1  0  1  0  0
4  1  0  1  1  1  0  0  1  1  0
 

Комментарии:

1. Это невероятно элегантно, спасибо. Я не знал об этой функции numpy или о том, что вы можете использовать ее в pandas frame подобным образом.