Копирование Pandas с использованием iloc работает не так, как ожидалось

#python #pandas

#python #pandas

Вопрос:

Я относительно новичок в pandas, поэтому я ожидаю, что я просто еще недостаточно хорошо его понял. Я пытался создать копию фрейма данных, и мне нужно изменить порядок строк, как я делаю, в соответствии с внешним отображением (есть веская, но неуместная причина для установки df2 в nan). Когда я пытаюсь выполнить это как одну операцию, используя .iloc, порядок игнорируется, но если я выполняю цикл и выполняю его по одной строке за раз, он работает так, как я ожидал. Кто-нибудь может объяснить, где я ошибаюсь в этом MWE? (Кроме того, приветствуются более эффективные / элегантные способы сделать это).

 import pandas as pd
import numpy as np

df1 = pd.DataFrame([[100,200,300,400]]).T
df1.columns = ['A']

df2 = df1.copy()
df2[:] = np.nan

assign = np.array([[0,0],[1,1],[3,2],[2,3]])

print df1

# This does not work:
# df2.iloc[assign[:,1]] = df1.iloc[assign[:,0]]
# Output:
#      A
# 0  100
# 1  200
# 2  300
# 3  400
#
#      A
# 0  100
# 1  200
# 2  300
# 3  400

# This does:
for x in assign:
  df2.iloc[x[1]] = df1.iloc[x[0]]
# Output:
#      A
# 0  100
# 1  200
# 2  300
# 3  400
#
#      A
# 0  100
# 1  200
# 2  400
# 3  300

print df2
  

Ответ №1:

Здесь нам понадобится pandas разработчик, чтобы объяснить, почему это работает именно так, но я знаю, что следующее решение поможет вам ( pandas 0.13.1 ):

 In [179]:
df2.iloc[assign[:,1]] = df1.iloc[assign[:,0]].values
print df2

out[179]:
     A
0  100
1  200
2  400
3  300

[4 rows x 1 columns] 
  

Как указал @Jeff, в df2.iloc[assign[:,1]] = df1.iloc[assign[:,0]] , вы присваиваете a Series a Series , и два индекса будут совпадать. Но при df2.iloc[assign[:,1]] = df1.iloc[assign[:,0]].values этом вы присваиваете a array для an Series , и нет индекса, который нужно сопоставить.

Также рассмотрите следующий пример в качестве иллюстрации поведения сопоставления индексов.

 In [208]:
#this will work and there will be missing values
df1['B']=pd.Series({0:'a', 3:'b', 2:'c'})
print df1
     A    B
0  100    a
1  200  NaN
2  300    c
3  400    b

[4 rows x 2 columns]
In [209]:
#this won't work
df1['B']=['a', 'b', 'c'] #one element less than df1
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
  

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

1. при назначении rhs автоматически выравнивается по lhs, то есть выбираются соответствующие метки. это особенность! в этом soln вы просто присваиваете значения (массив numpy), поэтому их нечего выравнивать (что в данном случае и нужно)

2. Привет, Джефф, хорошее объяснение. И я знал, что вы печатаете с мобильного устройства, ура!

3. Эй, CT, я думаю, ты имеешь в виду версию pandas 0.13.1.

4. Это фантастика, спасибо за объяснение! Это действительно проясняет ситуацию для меня.