2016-04-06 1 views
2

Я читал по этому поводу и до сих пор находят предмет немного запутанным: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copyУстановите первую и последнюю строку столбца в dataframe

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

df.iloc[[0, -1]].mycol = [1, 2]

, который говорит мне A value is trying to be set on a copy of a slice from a DataFrame. и что это потенциально опасно.

Вместо этого я мог бы использовать .loc, но тогда мне нужно знать индекс первой и последней строк (в constrast, .iloc позволяет мне получить доступ по местоположению).

Что является самым безопасным способом Pandasy для этого?

Чтобы добраться до этой точки:

# Django queryset 
query = market.stats_set.annotate(distance=F("end_date") - query_date) 

# Generate a dataframe from this queryset, and order by distance 
df = pd.DataFrame.from_records(query.values("distance", *fields), coerce_float=True) 
df = df.sort_values("distance").reset_index(drop=True) 

Затем я пытаюсь вызова df.distance.iloc[[0, -1]] = [1, 2]. Это вызывает предупреждение.

+1

делает 'df ['mycol']. Iloc [[0, -1]] = [1, 2]' работает? – EdChum

+0

Такое же предупреждение, если я сначала индексирую строки или столбцы. – Quentin

+0

Вам нужно будет показать точно все шаги, которые приводят к предупреждению, поскольку мой ответ показывает, что это правильно работает – EdChum

ответ

2

Проблема не с iloc, это когда вы получаете доступ к .mycol, чтобы создать копию. Вы можете сделать это все в пределах iloc:

df.iloc[[0, -1], df.columns.get_loc('mycol')] = [1, 2] 

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

+0

Ah! Здесь создается копия. Благодаря ! – Quentin

1

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

In [24]: 
df = pd.DataFrame(np.random.randn(5,3), columns=list('abc')) 

Out[24]: 
      a   b   c 
0 1.589940 0.735713 -1.158907 
1 0.485653 0.044611 0.070907 
2 1.123221 -0.862393 -0.807051 
3 0.338653 -0.734169 -0.070471 
4 0.344794 1.095861 -1.300339 

In [25]: 
df['a'].iloc[[0,-1]] ='foo' 
df 

Out[25]: 
      a   b   c 
0  foo 0.735713 -1.158907 
1 0.485653 0.044611 0.070907 
2 1.12322 -0.862393 -0.807051 
3 0.338653 -0.734169 -0.070471 
4  foo 1.095861 -1.300339 

Если вы делаете это по-другому, то это поднимает предупреждение:

In [27]: 
df.iloc[[0,-1]]['a'] ='foo' 

C:\WinPython-64bit-3.4.3.1\python-3.4.3.amd64\lib\site-packages\IPython\kernel\__main__.py:1: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame. 
Try using .loc[row_indexer,col_indexer] = value instead 

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy 
    if __name__ == '__main__': 
+0

На самом деле 'df.mycol.iloc [[0, -1]]' все еще вызывает предупреждение для меня. Я нахожусь на 0.17.1. Интересно, это потому, что он был создан с помощью 'pd.DataFrame.from_records', потому что когда я запускаю ваш, никаких предупреждений. – Quentin

+0

У меня была такая же проблема на 0.18.0. Когда я запускал код выше, я не получил предупреждение, но предупреждение было поднято, когда я использовал тот же метод для некоторых тестовых данных, которые я создал. Странный. – root

+0

Иногда заставляет вас пожелать, чтобы Python сделал понятие указателей более явным;) – Quentin