我理解标题不是很清楚我要问的问题,但我认为我的例子会解决这个问题。
我需要计算数据集中几个变量的百分比变化。为此,我使用函数:
Content
我在网上找到了。问题是,在我应用它之后,我的数据看起来像这样:
pcchange=function(x,lag=1) c(diff(x,lag),rep(NA,lag))/x
我想要完成的是:
color shade value pcchange
RED LIGHT -1.05 N/A
RED LIGHT -1.37 0.3
RED LIGHT -0.32 -0.8
RED LIGHT 0.87 -3.7
RED LIGHT -0.20 -1.2
RED DARK 0.52 -3.6
RED DARK -0.20 -1.4
RED DARK 0.64 -4.2
RED DARK 1.12 1
RED DARK 4.00 2.6
BLUE LIGHT 0.93 -0.8
BLUE LIGHT 0.78 -0.2
BLUE LIGHT -1.84 -3.3
BLUE LIGHT -0.50 -0.7
BLUE LIGHT -1.11 1.2
BLUE DARK -4.86 3.4
BLUE DARK 1.11 -1.2
BLUE DARK 0.14 -0.9
BLUE DARK 0.12 -0.1
BLUE DARK -1.65 -14.5
GREEN LIGHT 3.13 -2.9
GREEN LIGHT 2.65 -0.2
GREEN LIGHT -2.36 -1.9
GREEN LIGHT -3.11 0.3
GREEN LIGHT 3.49 -2.1
GREEN DARK 1.91 -0.5
GREEN DARK -1.10 -1.6
GREEN DARK -1.93 0.8
GREEN DARK 1.00 -1.5
GREEN DARK -0.23 -1.2
很抱歉很长的例子,但我想尽可能清楚地问我的问题。
所以你可以看到我需要一种方法在某些变量值之后使值“重置”(在我的例子中它将是变量:shade)。
有没有简单的方法可以做到这一点,或者只有解决方案基于循环?
提前谢谢!
答案 0 :(得分:2)
我会把这一点添加到评论中,但我没有足够的代表:) 因此,如果您仍希望将NA放在每个组的开头,则必须将该函数更改为如下所示:
import sys
from PyQt4 import QtGui, QtCore
class MyFileViewDelegate(QtGui.QStyledItemDelegate ):
def __init__(self, parent=None, *args, **kwargs):
QtGui.QItemDelegate.__init__(self, parent, *args)
self.condition = None
self.isMatch = False
self.brush_active = QtGui.QBrush(QtGui.QColor("#79b9ed"))
self.brush_active_matched = QtGui.QBrush(QtGui.QColor("#58cd1c"))
self.pen = QtGui.QPen(QtGui.QColor("#414141") )
self.pen_matched = QtGui.QPen(QtGui.QColor("#39c819") )
self.pen_active = QtGui.QPen(QtGui.QColor("#eef2fd") )
self.pen_active_matched = QtGui.QPen(QtGui.QColor("#e7fade") )
def paint(self, painter, option, index):
text = index.data(QtCore.Qt.DisplayRole)
self.matchText(text)
painter.save()
######## set background
painter.setPen(QtGui.QPen(QtCore.Qt.NoPen))
if option.state & QtGui.QStyle.State_Selected:
if self.isMatch:
painter.setBrush(self.brush_active_matched)
else:
painter.setBrush(self.brush_active)
painter.drawRect(option.rect)
######## set font color
if option.state & QtGui.QStyle.State_Selected:
if self.isMatch:
painter.setPen(self.pen_active_matched)
else:
painter.setPen(self.pen_active)
else:
if self.isMatch:
painter.setPen(self.pen_matched)
else:
painter.setPen(self.pen)
painter.drawText(option.rect, QtCore.Qt.AlignLeft, text)
painter.restore()
def matchText(self, filename):
# testing condition. In the real case this is much more complicated
if (self.condition != None) and (self.condition != "") and (self.condition in filename):
self.isMatch = True
else:
self.isMatch = False
def setCondition(self, condition):
self.condition = condition
class MainWidget(QtGui.QWidget):
def __init__(self, parent=None, useDelegate = False):
super(MainWidget, self).__init__(parent)
self.setLayout(QtGui.QVBoxLayout())
self.FolderModel = QtGui.QFileSystemModel()
self.FolderModel.setFilter(QtCore.QDir.NoDotAndDotDot | QtCore.QDir.AllDirs)
self.FolderModel.setRootPath("")
self.FolderView = QtGui.QTreeView(parent=self)
self.FolderView.setModel(self.FolderModel)
self.FolderView.setHeaderHidden(True)
self.FolderView.hideColumn(1)
self.FolderView.hideColumn(2)
self.FolderView.hideColumn(3)
self.FolderView.expanded.connect(self.FolderView.scrollTo)
self.FolderView.clicked[QtCore.QModelIndex].connect(self.browserClicked)
self.FileModel = QtGui.QFileSystemModel()
self.FileModel.setFilter(QtCore.QDir.NoDotAndDotDot | QtCore.QDir.Files)
self.FileView = QtGui.QListView(parent=self)
self.FileView.setModel(self.FileModel)
self.FileViewDelegate = None
if useDelegate:
self.FileViewDelegate = MyFileViewDelegate()
self.FileView.setItemDelegate(self.FileViewDelegate)
self.FileView.setSelectionMode( QtGui.QAbstractItemView.ExtendedSelection )
self.LineEdit = QtGui.QLineEdit()
self.LineEdit.textChanged.connect(self.changeCondition)
# Add Widgets to layout
self.layout().addWidget(self.FolderView)
self.layout().addWidget(self.FileView)
self.layout().addWidget(self.LineEdit)
def changeCondition(self, text):
if self.FileViewDelegate:
self.FileViewDelegate.setCondition(text)
def browserClicked(self, index):
# the signal passes the index of the clicked item
# set the FileView's root_index to the clicked index
dir_path = self.FileModel.filePath(index)
root_index = self.FileModel.setRootPath(dir_path)
self.FileView.setRootIndex(root_index)
class App(QtGui.QMainWindow):
def __init__(self, parent=None, useDelegate=False):
super(App, self).__init__(parent)
self.central = MainWidget(parent =self, useDelegate=useDelegate)
self.setCentralWidget(self.central)
if __name__=='__main__':
app = QtGui.QApplication(sys.argv)
thisapp = App(None, True) # set False to view App without custom FileViewDelegate
thisapp.show()
sys.exit(app.exec_())
由于您只计算连续值之间的百分比变化(因此您不需要跳过之间的任何值),因此您不需要LineEdit.textChange
和多个NAs每个小组的开头。由于每个组只需要一个NA,pcchange = function(x){ c( NA, diff(x)/x[-length(x)] ) }
也可以忽略不计。
答案 1 :(得分:1)
使用dplyr
,按破坏数据框的内容进行分组,改变:
data %>% group_by(color, shade) %>% mutate(pcchange = pcchange(value))
生成一个数据框(实际上是tbl
),如下所示:
color shade value pcchange
1 RED LIGHT -1.05 0.3047619
2 RED LIGHT -1.37 -0.7664234
3 RED LIGHT -0.32 -3.7187500
4 RED LIGHT 0.87 -1.2298851
5 RED LIGHT -0.20 NA
6 RED DARK 0.52 -1.3846154
7 RED DARK -0.20 -4.2000000
8 RED DARK 0.64 0.7500000
9 RED DARK 1.12 2.5714286
10 RED DARK 4.00 NA
11 BLUE LIGHT 0.93 -0.1612903
12 BLUE LIGHT 0.78 -3.3589744
13 BLUE LIGHT -1.84 -0.7282609
14 BLUE LIGHT -0.50 1.2200000
15 BLUE LIGHT -1.11 NA
16 BLUE DARK -4.86 -1.2283951
[etc]
我注意到你的答案在每个序列的开头都有NA,但是你的pcchange
函数将它放在最后。如果需要,请修改pcchange
。
期待使用数据表和基础R(split
)的解决方案很快......
答案 2 :(得分:1)
这是一个data.table
(开发版本1.9.7)解决方案,与OP的预期结果非常相似。
但首先,我们需要为可重现的示例创建数据。来自fread
的{{1}}功能非常方便。
data.table
library(data.table)
# prepare data, reading first 3 columns
dt <- fread("color shade value pcchange
RED LIGHT -1.05 N/A
RED LIGHT -1.37 0.3
RED LIGHT -0.32 -0.8
RED LIGHT 0.87 -3.7
RED LIGHT -0.20 -1.2
RED DARK 0.52 -3.6
RED DARK -0.20 -1.4
RED DARK 0.64 -4.2
RED DARK 1.12 1
RED DARK 4.00 2.6
BLUE LIGHT 0.93 -0.8
BLUE LIGHT 0.78 -0.2
BLUE LIGHT -1.84 -3.3
BLUE LIGHT -0.50 -0.7
BLUE LIGHT -1.11 1.2
BLUE DARK -4.86 3.4
BLUE DARK 1.11 -1.2
BLUE DARK 0.14 -0.9
BLUE DARK 0.12 -0.1
BLUE DARK -1.65 -14.5
GREEN LIGHT 3.13 -2.9
GREEN LIGHT 2.65 -0.2
GREEN LIGHT -2.36 -1.9
GREEN LIGHT -3.11 0.3
GREEN LIGHT 3.49 -2.1
GREEN DARK 1.91 -0.5
GREEN DARK -1.10 -1.6
GREEN DARK -1.93 0.8
GREEN DARK 1.00 -1.5
GREEN DARK -0.23 -1.2",
drop = "pcchange")
默认情况下,# Now, compute relative changes by group
dt[, pcchange := value/shift(value) - 1, by = "color,shade"]
print(dt)
color shade value pcchange
1: RED LIGHT -1.05 NA
2: RED LIGHT -1.37 0.3047619
3: RED LIGHT -0.32 -0.7664234
4: RED LIGHT 0.87 -3.7187500
5: RED LIGHT -0.20 -1.2298851
6: RED DARK 0.52 NA
7: RED DARK -0.20 -1.3846154
8: RED DARK 0.64 -4.2000000
9: RED DARK 1.12 0.7500000
10: RED DARK 4.00 2.5714286
11: BLUE LIGHT 0.93 NA
12: BLUE LIGHT 0.78 -0.1612903
13: BLUE LIGHT -1.84 -3.3589744
14: BLUE LIGHT -0.50 -0.7282609
15: BLUE LIGHT -1.11 1.2200000
16: BLUE DARK -4.86 NA
17: BLUE DARK 1.11 -1.2283951
18: BLUE DARK 0.14 -0.8738739
19: BLUE DARK 0.12 -0.1428571
20: BLUE DARK -1.65 -14.7500000
21: GREEN LIGHT 3.13 NA
22: GREEN LIGHT 2.65 -0.1533546
23: GREEN LIGHT -2.36 -1.8905660
24: GREEN LIGHT -3.11 0.3177966
25: GREEN LIGHT 3.49 -2.1221865
26: GREEN DARK 1.91 NA
27: GREEN DARK -1.10 -1.5759162
28: GREEN DARK -1.93 0.7545455
29: GREEN DARK 1.00 -1.5181347
30: GREEN DARK -0.23 -1.2300000
color shade value pcchange
函数将值滞后1,并使用shift
填充缺失值。根据OP的要求,这方便地返回NA
每组的第一行。
计算相对变化的公式在数学上等同于较少的输入。
参数NA
告诉by = "color,shade"
按data.table
和color
进行分组。
shade
来显示结果。 print(dt)
通过引用创建新变量(不复制整个对象),从而节省时间和内存。