web-dev-qa-db-ja.com

Python:NaNをデータフレーム内の条件に置き換える方法は?

ネットワーク内のnodesのegelistとノード自体のvalueに対応するデータフレームdf1が次のようにあります。

df
    node_i    node_j    value_i   value_j
0    3         4          89         33
1    3         2          89         NaN
2    3         5          89         69
3    0         2          45         NaN
4    0         3          45         89
5    1         2          109        NaN
6    1         8          109        NaN

値がある場合は、value_jに対応する列wを追加したいと思います。 value_jNaNの場合、wの隣接ノードの値の平均としてiを設定したいと思います。 node_iに、NaNの値がw=1に設定された隣接ノードのみがある場合。

したがって、最終的なデータフレームは次のようになります。

df
    node_i    node_j    value_i   value_j      w
0    3         4          89         33       33
1    3         2          89         NaN      51      # average of adjacent nodes
2    3         5          89         69       69
3    0         2          45         NaN      89      # average of adjacent nodes
4    0         3          45         89       89
5    1         2          109        NaN       1      # 1
6    1         8          109        NaN       1      # 1

次のようなループを実行していますが、applyを使用したいと思います。

nodes = pd.unique(df['node_i'])
df['w'] = 0
for i in nodes:
    tmp = df[df['node_i'] == i]
    avg_w = np.mean(tmp['value_j'])
    if np.isnan(avg_w):
          df['w'][idx] = 1
    else:
          tmp.ix[tmp.value_j.isnull(), 'value_j'] = avg_w ## replace NaN with values
          df['w'][idx] = tmp['value_j'][idx]  
7
emax

groupbyを使用してこれを行うことができます。

fill_value = df.groupby("node_i")["value_j"].mean().fillna(1.0)
df["w"] = fill_value.reindex(df["node_i"]).values
df["w"][df["value_j"].notnull()] = df["value_j"][df["value_j"].notnull()]
4
cncggvg

fillnaffillを1回使用して、bfillを平均し、次にfillna1として使用する必要があると思います。

df['w'] = ((df['value_j'].fillna(method='ffill')+df['value_j'].fillna(method='bfill'))/2).fillna(1).astype(int)

df
    node_i  node_j  value_i value_j w
0   3       4       89      33.0    33
1   3       2       89      NaN     51
2   3       5       89      69.0    69
3   0       2       45      NaN     79
4   0       3       45      89.0    89
5   1       2       109     NaN     1
6   1       8       109     NaN     1

更新された回答:

groupbytransformを使用してmeanを検索し、次にfillna1で検索し、np.whereを使用してwの値を次のように入力できます。

values = df.groupby('node_i')['value_j'].transform('mean').fillna(1)
df['w'] = np.where(df['value_j'].notnull(),df['value_j'],values).astype(int)

df

    node_i  node_j  value_i value_j w
0   3       4       89      33.0    33
1   3       2       89      NaN     51
2   3       5       89      69.0    69
3   0       2       45      NaN     89
4   0       3       45      89.0    89
5   1       2       109     NaN     1
6   1       8       109     NaN     1
4
Sandeep Kadapa

iの「隣接ノード」によって、最終的には同じiのすべての行にわたるvalue_jの平均が必要になると思います。

この場合、groupbytransformfillnaとともに使用できます。

means = df.groupby('i')['value_j'].transform(np.mean)
# this gives the correct values for w in the rows where value_j is null,
# except when all the adjacent nodes have null value_j  (in which case it's still null)
filled_means = means.fillna(1)
# this corrects the last problem
df['w'] = df['value_j'].fillna(filled_means)
# this copies value_j, and fills the null rows with the corresponding rows from filled_means
# and assigns it to the column 'w'
2
Ken Wei

このコードはあなたを助けるかもしれません。確認してお知らせください。

import pandas as pd
import numpy as np

df = pd.DataFrame({
        'node_i':[3,3,3,0,0,1,1],
        'node_j':[4,2,5,2,3,2,8],
        'value_i':[89,89,89,45,45,109,109],
        'value_j':[33,np.nan,69,np.nan,89,np.nan,np.nan]

        })

wList = []

for index,value in enumerate(df['value_j'].values):
    curValueNode_i = df.iloc[index,0]
    if not np.isnan(value):
        wList.append(value)
    else:
        checkIfNaNReturns = len(df[(df['node_i']==curValueNode_i) & (df['value_j'].notnull())].iloc[:,3].values)
        if (checkIfNaNReturns>0):
            meanValue = np.mean(df[(df['node_i']==curValueNode_i) & (df['value_j'].notnull())].iloc[:,3].values)
            wList.append(meanValue)
        else:
            wList.append(1)

df['w'] = wList
print(df)


'''
Output of the code:

   node_i  node_j  value_i  value_j     w
0       3       4       89     33.0  33.0
1       3       2       89      NaN  51.0
2       3       5       89     69.0  69.0
3       0       2       45      NaN  89.0
4       0       3       45     89.0  89.0
5       1       2      109      NaN   1.0
6       1       8      109      NaN   1.0

'''
0
Adrish

最後の行に適用および追加のステートメントを使用

def func(x):
    if len(x)==1:
        if math.isnan(x[0]):
            return 1
        else:
            return x[0]
    Elif not math.isnan(x[1]):
        return x[1]
    Elif len(x)==2:
        return 1
    Elif math.isnan(x[0]) or math.isnan(x[2]):
        return 1
    else:
        return (x[0]+x[2])/2



df['Output']=df['value_j'].rolling(window=3, min_periods=0).apply(lambda x: func(x), raw=True).shift(-1)
df['Output'].iloc[-1]=func(list(df['value_j'].tail(2)))
0
Sergey

applyは最速の解決策ではないかもしれませんが、それはあなたの要求なので、次のように進めることができます。

def nan_with_cond(row):
    if ~np.isnan(row['value_j']) : return row['value_j']
    else: return df.loc[df['node_i'] == row['node_i'], 'value_j'].mean()

df['w'] = df.apply(nan_with_cond , axis=1).fillna(1)

またはapplyのみを使用:

def nan_with_cond(row):
    if ~np.isnan(row['value_j']) : return row['value_j']
    else: 
        value = df.loc[df['node_i'] == row['node_i'], 'value_j'].mean()
        if np.isnan(value) : return 1
        else : return value

df['w'] = df.apply(nan_with_cond , axis=1)
0
Florian Mutel