I keep getting an error saying my value is not positioned on a valid record. I've executed my query successfully in MySQL, but I think I'm overlooking something in my code.
query = QtSql.QSqlQuery("select patient_id," +
"(SUM(IF(uom_id = 1, value, 0)) / SUM(IF(uom_id = 1, 1, 0))) AS `Average radius`," +
"(SUM(IF(uom_id = 2, value, 0)) / SUM(IF(uom_id = 2, 1, 0))) AS `Average Volume`," +
"(SUM(IF(uom_id = 3, value, 0)) / SUM(IF(uom_id = 3, 1, 0))) AS `Average SA`" +
"from measurements" +
"WHERE image_id = " + self.dbImage.id.toString() +
"AND status = 'A'" +
"GROUP BY patient_id", self.db)
query.next()
radius_acc = query.value(1).toDouble()
volume_acc = query.value(2).toDouble()
SA_acc = query.value(3).toDouble()
print('average of previously accepted measurements includes ' +
'radius = ' + str(radius_acc) +
'volume = ' + str(volume_acc) +
'SA = ' + str(SA_acc))
Specifically I want to know if there is something wrong with the way I input the query to QSqlQuery? Or maybe I am trying to use the value(n) method incorrectly?
If neither of those appear to be the case I'll bet I'm using the wrong parameter for self.dbImage.id.toString() in my query, in which case I'll just ask a coworker tomorrow.
To iterate over the result set you usually use a while loop:
while(query.next()){
// do whatever you need with query.value()
}
If you're interested only in the first row, you can use first(), again with a while loop:
while(query.first()){
// do whatever you need with query.value()
}
Edit: Sorry, misunderstood your problem. Now I see that you possibly forgot to put some spaces in some strings:
"from measurements"
to
" from measurements "
#^ Here and here ^^
Without these spaces, your query will look something like
"...d = 3, 1, 0))) AS `Average SA`from measurementsWHERE image_id = ..."
which of course it's not a valid query.
Related
I have a dataframe and specifically need to find the min, max, and average of the age column using loops. However, try as I might. It just did not work. I hope somebody could help me see where the problem is. Thank you.
Here is my code
total_age = 0
i=0
max_amount = adult_data["age"][i]
min_amount = adult_data["age"][i]
for i in range(len(adult_data["age"])):
total_age = adult_data["age"][i] + total_age,
i = i + 1,
if adult_data["age"][i] > max_amount:
max_amount = adult_data["age"][i],
if adult_data["age"][i] < min_amount:
min_amount = adult_data["age"][i],
print(total_age)
The error I am currently getting is
ValueError: key of type tuple not found and not a MultiIndex
The commas at the end of statements indicate tuples. For example, i = i + 1,is the same as i = (i + 1,), where (i + 1,) is a tuple with one element.
So, your code is essentially the same as:
for i in range(len(adult_data["age"])):
total_age = (adult_data["age"][i] + total_age,)
i = (i + 1,)
if adult_data["age"][i] > max_amount:
max_amount = (adult_data["age"][i],)
if adult_data["age"][i] < min_amount:
min_amount = (adult_data["age"][i],)
That's a lot of tuples!
In other words, you don't need the commas. You also don't need i = i + 1 because the range automatically increments i.
Try:
adult_data["age"].agg(['min','max','mean'])
In the below, Scenario 1 is working fine in both (Code 1 & Code 2). But Scenario 2 is not working in Code 1.
My requirement is Tuple should keep on repeating itself until it fills all the formatting string in the Query dynamically. Because where clauses are not constant for all the queries.
Scenario 1#
query = SELECT * FROM test.order where total_price in {}
Tuple:
finTup=((125, 125, 125, 125),)
SELECT * FROM test.order where total_price in (125, 125, 125, 125)
Scenario 2#
query = SELECT * FROM test.order WHERE order_id IN {} AND product_id IN {}
Tuple:
finTup=((101, 105, 106, 107), (2, 2, 2, 2))
Code 1:
frt = 'finTup[{}]'
half = ''
val = ''
i = 0
le = len(finTup)
for i in range(le):
print(i)
print(eval(frt.format(i)))
if i == le -1:
half = half + frt.format(i)
val = val + " " + frt.format(i)
else:
half = half + frt.format(i)+', '
val = val + " " + frt.format(i)+', '
temp2 = query.format(eval(val))
Code 2:
if le == 1:
query = query.format(finTup[0])
elif le == 2:
query = query.format(finTup[0], finTup[1])
elif le == 3:
query = query.format(finTup[0], finTup[1], finTup[2])
elif le == 4:
query = query.format(finTup[0], finTup[1], finTup[2], finTup[3])
Error:
temp2 = query.format(eval(val))
IndexError: tuple index out of range
Please help me to fix this.
TL;DR
Hello, you have this error because you are trying to provide a single argument to the format function which expects two parameters (since you have 2 {}).
Note: Avoid using the eval function... That's pretty not recommended, even less in the current situation that you are. Everything can be done without having to evaluate a str.
In what follows, I only run the code for Scenario #2, i.e.
query2 = """SELECT * FROM test.order WHERE order_id IN {} AND product_id IN {}"""
finTup = ((101, 105, 106, 107), (2, 2, 2, 2))
Step 1: Debugging
Let's imagine you update your code for debugging as follows:
frt = 'finTup[{}]'
half = ''
val = ''
i = 0 # btw, you don't need to initialize i here
le = len(finTup)
for i in range(le):
if i == le -1:
half = half + frt.format(i)
val = val + " " + frt.format(i)
else:
half = half + frt.format(i)+', '
val = val + " " + frt.format(i)+', '
print val
print eval(val)
temp2 = query.format(eval(val))
Your output should be:
vars[0], vars[1]
((101, 105, 106, 107), (2, 2, 2, 2))
So, imagine you write python code from the above output, what you would do is:
query.format(((101, 105, 106, 107), (2, 2, 2, 2)))
You are actually providing a single parameter of type tuple with a two elements. But what's important here is that you provide format with a single parameter. The format function will try to access the second parameter, which you don't provide. It breaks.
Step 2: Fixing the code
Have a look at this SO article. It shows you how to use the * operator. It basically transforms a list or tuple into a sequence of items. Perfect for functions parameters and so forth.
So, applied to your current case:
temp2 = query.format(*eval(val))
And the trick is done.
Step 3: Optimization
Now, let's trash the Code 1 and use what we've learn with Code 2. We need to unpack the tuple of tuple into parameters to feed in to format. So, why not just do:
# I renamed `finTup` to `vars` since I don't know what it means
def get_query(query, vars):
return query.format(*vars)
It basically combines the logic of Code 1 and Code 2 into a single line.
I have a list of values that I want to update into multiple columns, this is fine for a single row. However when I try to update over multiple rows it simply overrides the whole column with the last value.
List for each row looks like below (note: list length is of variable size):
['2016-03-16T09:53:05',
'2016-03-16T16:13:33',
'2016-03-17T13:30:31',
'2016-03-17T13:39:09',
'2016-03-17T16:59:01',
'2016-03-23T12:20:47',
'2016-03-23T13:22:58',
'2016-03-29T17:26:26',
'2016-03-30T09:08:17']
I can store this in empty columns by using:
for i in range(len(trans_dates)):
df[('T' + str(i + 1) + ' - Date')] = trans_dates[i]
However this updates the whole column with the single trans_dates[i] value
I thought looping over each row with the above code would work but it still overwrites.
for issues in all_issues:
for i in range(len(trans_dates)):
df[('T' + str(i + 1) + ' - Date')] = trans_dates[i]
How do I only update my current row in the loop?
Am I even going about this the right way? Or is there a faster vectorised way of doing it?
Full code snippet below:
for issues in all_issues:
print(issues)
changelog = issues.changelog
trans_dates = []
from_status = []
to_status = []
for history in changelog.histories:
for item in history.items:
if item.field == 'status':
trans_dates.append(history.created[:19])
from_status.append(item.fromString)
to_status.append(item.toString)
trans_dates = list(reversed(trans_dates))
from_status = list(reversed(from_status))
to_status = list(reversed(to_status))
print(trans_dates)
# Store raw data in created columns and convert dates to pd.to_datetime
for i in range(len(trans_dates)):
df[('T' + str(i + 1) + ' - Date')] = trans_dates[i]
for i in range(len(to_status)):
df[('T' + str(i + 1) + ' - To')] = to_status[i]
for i in range(len(from_status)):
df[('T' + str(i + 1) + ' - From')] = from_status[i]
for i in range(len(trans_dates)):
df['T' + str(i + 1) + ' - Date'] = pd.to_datetime(df['T' + str(i + 1) + ' - Date'])
EDIT: Sample input and output added.
input:
issue/row #1 list (note year changes):
['2016-03-16T09:53:05',
'2016-03-16T16:13:33',
'2016-03-17T13:30:31',
'2016-03-17T13:39:09']
issue #2
['2017-03-16T09:53:05',
'2017-03-16T16:13:33',
'2017-03-17T13:30:31']
issue #3
['2018-03-16T09:53:05',
'2018-03-16T16:13:33',
'2018-03-17T13:30:31']
issue #4
['2015-03-16T09:53:05',
'2015-03-16T16:13:33']
output:
col T1 T2 T3 T4
17 '2016-03-16T09:53:05' '2016-03-16T16:13:33' '2016-03-17T13:30:31' '2016-03-17T13:30:31'
18 '2017-03-16T09:53:05' '2017-03-16T16:13:33' '2017-03-17T13:30:31' np.nan
19 '2018-03-16T09:53:05' '2018-03-16T16:13:33' '2018-03-17T13:30:31' np.nan
20 '2015-03-16T09:53:05' '2015-03-16T16:13:33' np.nan np.nan
Instead of this:
for i in range(len(trans_dates)):
df[('T' + str(i + 1) + ' - Date')] = trans_dates[i]
Try this:
for i in range(len(trans_dates)):
df.loc[i, ('T' + str(i + 1) + ' - Date')] = trans_dates[i]
There are probably better ways to do this... df.merge or df.replace come to mind... it would be helpful if you posted what the input dataframe looked like and what the expected result is.
I have ipython 5.3.0 and when i am in the middle of expression (cursor is marked as <cursor>), for example:
In [69]: x = np.arange(<cursor>1, 21, 2).reshape(2, 5)
Than pressing enter causes split this line into two lines.
In [69]: x = np.arange(
...: 1, 21, 2).reshape(2, 5)
But when i have cursor in other place for example:
In [69]: x = np.<cursor>arange(1, 21, 2).reshape(2, 5)
It executes expression.
Which keyboard shortcut forces execution of expression without taking care of cursor position?
I tried CTRL + ENTER or SHIFT + ENTER but no one of them working for first example.
This was fixed in IPython 5.4. Earlier, there's no way short of patching/monkey-patching at startup, but there's an easy workaround.
Here's the relevant logic from 5.4.1, in IPython/terminal/shortcuts.py. The fragment with a comment referring to the issue on the first link is the fix.
def newline_or_execute_outer(shell):
def newline_or_execute(event):
"""When the user presses return, insert a newline or execute the code."""
b = event.current_buffer
d = b.document
if b.complete_state:
cc = b.complete_state.current_completion
if cc:
b.apply_completion(cc)
else:
b.cancel_completion()
return
# If there's only one line, treat it as if the cursor is at the end.
# See https://github.com/ipython/ipython/issues/10425
if d.line_count == 1:
check_text = d.text
else:
check_text = d.text[:d.cursor_position]
status, indent = shell.input_splitter.check_complete(check_text + '\n')
if not (d.on_last_line or
d.cursor_position_row >= d.line_count - d.empty_line_count_at_the_end()
):
b.insert_text('\n' + (' ' * (indent or 0)))
return
if (status != 'incomplete') and b.accept_action.is_returnable:
b.accept_action.validate_and_handle(event.cli, b)
else:
b.insert_text('\n' + (' ' * (indent or 0)))
return newline_or_execute
As you can see, the action depends on the cursor's position relevant to a code's token.
So, if you have a complete statement, you can force execution by simply pressing End before Enter.
I would like to transform this code to have a function instead :
variables = ['oki']
for var in variables:
lm_full = sm.formula.ols(formula='%s ~ diag + age + ICVcm3' % var, data=dfwo2).fit()
print("===============================================================================")
print(" formule = %s ~ diag + age + ICVcm3" % var)
print("===============================================================================")
print(lm_full.summary())
At the end I would like something that looks like :
function(oki,diag,age,ICVcm3,dfwo2) that would return the result of the loop.
I have no clue of how to do it. The examples that I found on the internet are very basic.... I don't even know what to type on google to get an answer.
You can return a list of tuples:
def myFunction(variables):
result = []
for var in variables:
formula = " formule = %s ~ diag + age + ICVcm3" % var
lm_full = sm.formula.ols(formula=formula, data=dfwo2).fit()
result.append((formula, lm_full.summary()))
return result
This code shows you how to return the items that have been computed in the function and how to retrieve them in the calling function. Notice how you can return as many, or as few, items as you wish, and that, even if the function returns items your calling code doesn't need you can ignore them. (That's the purpose of the variables named dummy.)
I'm using one of the datasets that comes with statsmodels since I don't recognise the one you're using.
import statsmodels as sm
df = sm.datasets.get_rdataset("Guerry", "HistData").data
df = df[['Lottery', 'Literacy', 'Wealth', 'Region']].dropna()
import statsmodels.formula.api as smf
def regress(variables):
results = [ ]
for variable in variables:
mod = smf.ols(formula='Lottery ~ %s' % variable, data=df)
result = mod.fit()
results . append ( (variable, result.params, result.df_resid, result.rsquared) )
return results
for result in regress (['Literacy', 'Wealth', 'Region']):
variable, dummy, dummy, R_squared = result
print ( variable, R_squared )
Results are like this:
Literacy 0.145720612937
Wealth 0.243180384656
Region 0.142107524677
your loop is var in variables which only contains 1 item: a string.
So what is the purpose of such a loop anyway? diag,age,ICVcm3,dfwo2 where are all these values delcared? What is the function about? Is seems to be some very specific wierd topic.
Though just guessing, something like this could be what you've been looking for:
def myfunction(variables,diag,age,ICVcm3,dfwo2):
for var in variables:
lm_full = sm.formula.ols(formula='%s ~ diag + age + ICVcm3' % var, data=dfwo2).fit()
print("===============================================================================")
print(" formule = %s ~ diag + age + ICVcm3" % var)
print("===============================================================================")
print(lm_full.summary())