Замена запредельных (комплексных) значений в фрейме данных pandas
(Python 2.7, pandas 0.13.0)
Фон: я читаю кучу данных из CSV-файла и загружаю их в фрейм данных pandas. Некоторые данные являются сложными (я преобразую их из строк при загрузке). Некоторые из значений были погрешностями оборудования, отличающимися тем, что они слишком велики. Я хочу заменить все значения, величина которых превышает определенный порог, на np.бабушка. Это легко с массивом numpy (при условии, что вы используете "сложный nan", как показано на рисунке), но было сложно в pandas. Я задокументировал шаги, которые я попробовал ниже - последняя попытка почти достигает этого, но любая строка, где происходит замена, преобразуется в реальную.
В этот момент я думаю о том, чтобы просто вытянуть значения в массив numpy, изменить, а затем загрузить обратно в фрейм данных, но это кажется довольно неэлегантным.
EDIT: решение, приведенное ниже, работает, но мне интересно, есть ли еще ошибка в том, как панды обращаются с НАН. в коде, который я написал. Похоже, что созданный НАН-это nan +0.j вместо nan +nanj. Matplotlib построит график последнего без проблем, если вы делаете что-то вроде plot(np.real(signal), np.imag(signal)), но не любит первый, так как он строит пару (Nan, 0). Похоже, мне нужно заменить новые записи nan +0j на записи nan +nanj, что рекурсивно перезапускает проблему. :)
EDIT2: кажется, есть визуальная разница в NaN, но новая ошибка, которую я нашел, не была связана с этой разницей. Разница, вероятно, неважна. Неправильный вещи выше пробиты насквозь.
# begin by making a fake data set that resembles the CSV struction
headers = ['Z1', 'Z2', 'Z3']
temp = np.arange(12).reshape((4,3)) + 1j*np.arange(12,24).reshape((4,3))
temp[0,1] = 5000 + 1j*5000
temp[1,1] = 5000 + 1j*8000
temp[2,2] = 7000 + 1j*3000
junk = ['exists to', 'make life', 'extra', 'difficult']
df_junk = pd.DataFrame(data=junk, columns=['other junk'])
df = pd.DataFrame(data=temp, columns=headers)
df = pd.concat((df, df_junk), axis=1)
# very simple to do this in an np.array if we only take the numbers
temp2 = np.copy(temp)
# temp2 is the desired result, but in the frame with everything else
temp2[ np.abs(temp2) > 5000 ] = np.nan + 1j*np.nan
df2 = df.copy()
# Executing the next line replaces the value with NaN,
# but turns all of column Z2 into real numbers
#df[np.abs(df[headers]) > 5000 ] = np.nan + 1j*np.nan
# Trying to grab the index first gives
# ValueError: Cannot index with multidimensional key
#df.ix[np.abs(df[headers]) > 5000 ]
for column in headers:
# The following line would turn the entire 3rd row into NaN
# df[np.abs(df[column]) > 5000] = np.nan + 1j*np.nan
# Attempts along these lines to apply a lambda (tried different ones)
# didn't seem to work
#csv_data[column] = csv_data[column].apply(lambda x:
# pd.replace(x, np.nan) if abs(x) > 5000 else pd.replace(x,x))
# This last one almost works, but again turns columns with replacements into reals
df2[column].where(abs(df2[column]) <= 5000, np.nan+1j*np.nan, inplace=True)
Z1 Z2 Z3 other junk
0 12j NaN 2 exists to
1 (3+15j) NaN 5 make life
2 (6+18j) 7 NaN extra
3 (9+21j) 10 11 difficult
1 ответ:
Похоже, что это работает без флага inplace:
In [11]: df3 = df2[['Z1', 'Z2', 'Z3']] In [12]: df3.where(df3 <= 5000) # replaces by NaN by default Out[12]: Z1 Z2 Z3 0 12j NaN (2+14j) 1 (3+15j) NaN (5+17j) 2 (6+18j) (7+19j) NaN 3 (9+21j) (10+22j) (11+23j) In [13]: df2[['Z1', 'Z2', 'Z3']] = df3.where(df3 <= 5000)вообще я думаю, что избегать флага inplace-хорошая идея (хотя это, вероятно, ошибка ):
In [21]: df3.where(df3 <= 5000, inplace=True) In [22]: df3 Out[22]: Z1 Z2 Z3 0 12j NaN 2 1 (3+15j) NaN 5 2 (6+18j) 7 NaN 3 (9+21j) 10 11
Comments