如何移动pandas数据框中单个值的列?

3
使用pandas的first_valid_index()方法获取某一列第一个非空值的索引,如何只移动该列的一个单独值而不是整个列。例如:
data = {'year': [2010, 2011, 2012, 2013, 2014, 2015, 2016,2017, 2018, 2019],
        'columnA': [10, 21, 20, 10, 39, 30, 31,45, 23, 56],
        'columnB': [None, None, None, 10, 39, 30, 31,45, 23, 56],
         'total': [100, 200, 300, 400, 500, 600, 700,800, 900, 1000]}

df = pd.DataFrame(data)
df = df.set_index('year')
print df
      columnA  columnB  total
year                         
2010       10      NaN    100
2011       21      NaN    200
2012       20      NaN    300
2013       10       10    400
2014       39       39    500
2015       30       30    600
2016       31       31    700
2017       45       45    800
2018       23       23    900
2019       56       56   1000

for col in df.columns:
    if col not in ['total']:
        idx = df[col].first_valid_index()
        df.loc[idx, col] = df.loc[idx, col] + df.loc[idx, 'total'].shift(1)

print df     

AttributeError: 'numpy.float64' object has no attribute 'shift'

期望结果:

print df
      columnA  columnB  total
year                         
2010       10      NaN    100
2011       21      NaN    200
2012       20      NaN    300
2013       10      310    400
2014       39       39    500
2015       30       30    600
2016       31       31    700
2017       45       45    800
2018       23       23    900
2019       56       56   1000
2个回答

2

这是您想要的吗?

In [63]: idx = df.columnB.first_valid_index()

In [64]: df.loc[idx, 'columnB'] += df.total.shift().loc[idx]

In [65]: df
Out[65]:
      columnA  columnB  total
year
2010       10      NaN    100
2011       21      NaN    200
2012       20      NaN    300
2013       10    310.0    400
2014       39     39.0    500
2015       30     30.0    600
2016       31     31.0    700
2017       45     45.0    800
2018       23     23.0    900
2019       56     56.0   1000

更新:从Pandas 0.20.1开始,.ix索引器已被弃用,推荐使用更严格的.iloc和.loc索引器


对于df的每一列: 如果该列不是'total',则找到第一个有效索引idx, 打印出df.ix[idx, col] + df.total.shift().ix[idx] - ArchieTiger
@ArchieTiger,你为什么要使用for循环? - Merlin

1
你可以筛选所有至少有一个NaN值的列名,然后使用union与列total合并:
for col in df.columns:
    if col not in pd.Index(['total']).union(df.columns[~df.isnull().any()]):
        idx = df[col].first_valid_index()
        df.loc[idx, col] += df.total.shift().loc[idx]
print (df)
      columnA  columnB  total
year                         
2010       10      NaN    100
2011       21      NaN    200
2012       20      NaN    300
2013       10    310.0    400
2014       39     39.0    500
2015       30     30.0    600
2016       31     31.0    700
2017       45     45.0    800
2018       23     23.0    900
2019       56     56.0   1000

Total 是否总是在最后? - jezrael
或者更好的是,如果“总计”列中有“NaN”值,是否可能? - jezrael

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接