networkx calculating numeric assortativity requires int? - python

I am trying to use networkx to calculate numeric assortativity based on a numeric attribute that I set to nodes. My node attributes are floats. When I call the assortativity function:
assort = nx.numeric_assortativity_coefficient(G,'float_attr')
I got the following errors.
File "/some dir.../networkx/algorithms/assortativity/correlation.py", line 229, in numeric_assortativity_coefficient
a = numeric_mixing_matrix(G,attribute,nodes)
File "/some dir.../networkx/algorithms/assortativity/mixing.py", line 193, in numeric_mixing_matrix
mapping=dict(zip(range(m+1),range(m+1)))
TypeError: range() integer end argument expected, got float.
I checked the documentation page of networkx assortativity algorithm and it did not say the numeric attributes have to be int. Anyone knows if that's required?
BTW, I used the same network and a gender attribute (set to 0 and 1) to calculate both the attribute and the numeric assortativity. I had no problem with that. So it seems that the problem is with the int/float type of the node attribute.

problem solved by converting the float variable into int using the following method
int(round(float_attr*1000, 0))
submitted an issue here and got a confirmatory answer that it only deals with discrete int values.
Peformance-wise, since my network is not huge (200+ nodes), it still takes <1 min to do the calculation.

Related

how to add float typed weights to an retworkx digraph

In my pursuit after a fast graph library for python, I stumbled upon retworkx,
and I'm trying to achieve the same (desired) result I've achieved using networkx.
In my networkx code, I instantiate a digraph object with an array of weighted edges,
activate it's built-in shortest_path (dijkstra-based), and receive that path. I do so by using the following code:
graph = nx.DiGraph()
in_out_weight_triplets = np.concatenate((in_node_indices, out_node_indices,
np.abs(weights_matrix)), axis=1)
graph.add_weighted_edges_from(in_out_weight_triplets)
shortest_path = nx.algorithms.shortest_path(graph, source=n_nodes, target=n_nodes + 1,
weight='weight')
when trying to reproduce the same shortest path using retworkx:
graph = rx.PyDiGraph(multigraph=False)
in_out_weight_triplets = np.concatenate((in_node_indices.astype(int),
out_node_indices.astype(int),
np.abs(weights_matrix)), axis=1)
unique_nodes = np.unique([in_node_indices.astype(int), out_node_indices.astype(int)])
graph.add_nodes_from(unique_nodes)
graph.extend_from_weighted_edge_list(list(map(tuple, in_out_weight_triplets)))
shortest_path = rx.digraph_dijkstra_shortest_paths(graph, source=n_nodes,
target=n_nodes + 1)
but for using a triplet with float weights I get the error:
"C:\Users\tomer.d\Anaconda3\lib\site-packages\IPython\core\interactiveshell.py",
line 3437, in run_code
exec(code_obj, self.user_global_ns, self.user_ns) File "<ipython-input-23-752a42ce79d7>", line 1, in <module>
graph.extend_from_weighted_edge_list(list(map(tuple, in_out_weight_triplets))) TypeError: argument 'edge_list':
'numpy.float64' object cannot be interpreted as an integer ```
and when i try the workaround of multiplying the weights by factor of 10^4 and casting them to ints:
np.concatenate((in_node_indices.astype(int), out_node_indices.astype(int),
(np.abs(weights_matrix) * 10000).astype(int), axis=1)
so that I supposedly won't lose the weight subtleties - no errors are being raised,
but the output of the shortest path is different than the one I get when using networkx.
I'm aware of the fact that the weights aren't necessarily the issue here,
but they are currently my main suspect.
any other advice would be thankfully accepted.
Without knowing what in_node_indices, out_node_indices and weights_matrix contain in the code snippets it's hard to provide an exact working example for your use case. But, I can take a guess based on the error message. I think the issue you're hitting here is likely because you're trying to use the values in in_node_indices and out_node_indices as retworkx indices but there isn't a 1:1 mapping necessarily. The retworkx index for a node is assigned when the node is added and is the returned value. So if you do something like graph.add_node(3), the return from that will not necessarily be 3 it will be the node index assigned to that instance of 3 when it's added as a node in the graph. If you ran graph.add_nodes_from([3, 3]) you'd get two different indices returned. This is different from networkx which treats the data payloads as a lookup key in the graph (so graph.add_node(3) adds a node 3 to the graph which you look up by 3, but then you can only have a single node with the payload 3). You can refer to the documentation on retworkx for networkx users for more details here: https://qiskit.org/documentation/retworkx/networkx.html
So when you call add_nodes_from() you need to map the value at a position in the input array to the returned index from the method at the same position to identify that node in the graph. I think if you do something like:
import retworkx as rx
graph = rx.PyDiGraph(multigraph=False)
unique_indices = np.unique([in_node_indices, out_node_indices])
rx_indices = graph.add_nodes_from(unique_indices)
index_map = dict(zip(unique_indices, rx_indices))
in_out_weight_triplets = np.concatenate((in_node_indices, out_node_indices,
np.abs(weights_matrix)), axis=1)
graph.add_nodes_from([(index_map[in], index_map[out], weight) for in, out, weight in in_out_weight_triplets])
I haven't tested the above snippet (so there might be typos or other issues with it) because I don't know what the contents of in_node_indices, out_node_indices, and weight_matrix are. But it should give you an a better idea of what I described above.
That being said I do wonder if weight_matrix is an adjacency matrix, if it is then it's probably easier to just do:
import retworkx
graph = retworkx.PyDiGraph.from_adjacency_matrix(weight_matrix)
this is also typically faster (assuming you already have the matrix) because it uses the numpy C api and avoids the type conversion going between python and rust and all the pre-processing steps.
There was also an issue opened similar to this in the retworkx issue tracker recently: https://github.com/Qiskit/retworkx/issues/546. My response there contains more details on the internals of retworkx.

Why is 'DataFrame' object not callable

I have used Python for years and am trying to get more familiar with Pandas. I keep finding things that do not seem Pythonic to me. In this case, I want to use the largest value from my DataFrame to build a range object but I find that I cannot make an integer to feed to the range() function from the float returned as the maximum value of my DataFrame. As a minimal reproducible example, here is some code illustrating the error.
# Create a DataFrame
pairs = pd.DataFrame({'Pair': ['A-B', 'A-C'], 'Distance': [54.3, 9009.122894715296]})
# Select the max
pairs['Distance'].max()
9009.122894715296
# Check the type
type(pairs['Distance'].max())
<class 'float'>
# Make an integer to use in range function
int(pairs['Distance'].max())
TypeError: 'DataFrame' object is not callable
I have never had an issue converting a float to an integer so I do not understand why a) it is calling it a DataFrame object when it is clearly a float and b) it cannot convert this float to an integer. Hopefully someone has some knowledge of the operations that lead to this error.

TypeError: size; expecting a recognized type filling string dict

I have been working on Python script for Abaqus and it has to do with dynamic changes in the parameters of the model. The script opens up a .txt file and reads different values. The values are separated using tabs and I am using split() function of the Abaqus-Python to read the values properly once I have assigned them to a list.
The last index is [5] and it contains mesh size, again a float value. The structure is properly drawn in ABAQUS, the only error it throws me is while assigning the mesh size:
File "C:/Users/ANANT/PyCharmProjects/test_final/test_copy.py", line 104, in <module>
beamPart.seedPart(deviationFactor=0.1, minSizeFactor=0.1, size=mesh)
TypeError: size; found 'module', expecting a recognized type filling string dict
So I tried using repr() to make it a string, but I was it will throw me that the input should be float/integer value and it did exactly the same. Now I am stuck and I can't work any further. I even tried to truncate the float value to 3-decimal points for the mesh size, but it would still throw the same error.
Any help is much appreciated, thanks a lot :)
input file with truncated mesh size
The error message says that seedPart expects a size argument that fulfills the requirement "a recognized type filling string dict". I don't know what this means, but the example here is:
p.seedPart(size=2.0)
So you probably need a float. But mesh is a module. You probably have something like:
import mesh
Or:
import ... as mesh
in your code.
Try to print mesh before the line that raises the error.
so, the 'size=mesh' parameter passed is apparently not of correct type. mesh is of type 'module'. is this intended?

pulling Dict values in a loop

I'm having trouble isolating the values of a graphs edge weight in networkx
Im using kruskals algorithm to find a the MST of a given graph. U and V are point in Euclidean space and data is a dictionary for the weight of each edge. I'm using the values function for dictionaries to store the value in the set however I am returned this error
File "/Users/mac/anaconda3/lib/python3.6/site-packages/networkx/convert_matrix.py", line 1143, in to_numpy_array
A[index[u], index[v]] = d.get(weight, 1)
TypeError: float() argument must be a string or a number, not 'dict_values'
the particular piece of code I am having trouble with is this.
for u,v, data in sorted(self.original_graph.edges(data=True), key=lambda x: x[2]['weight']):
setu = UF.find(u)
setv= UF.find(v)
if setu != setv:
A.append((u,v,data.values()))
UF.union(setu,setv)
I am fully aware that networkx has their own minimum spanning tree functions built in, however I am trying to learn these algorithms on my own instead before blindly implementing built in functions
Upon reading into the documents for python, I realized that data.values() returns a list of all values in the dict, what I needed to do was reference the key such as data['weight'] in order to get the value it holds.

TypeError: SetPoint argument 1: integer argument expected, got float

can someone help me with this?
pts.InsertPoint(fl[i+1][j+1][k+1], xx[0][i+1], yy[0][j+1], zz[0][k+1])
TypeError: InsertPoint argument 1: integer argument expected, got float
fl is supposed to have float, I have the array from real world experiment, I can't change the values to int.
Is this an issue related to InsertPoint, is it only taking int? Can someone help me fix it?
Also, I don't have experience in Python, never wrote a program, this is the first program I am working with, I made changes to an old program to get it work for my purposes, but can't figure out what I did wrong
Thanks :)
If you look at the documentation of vtkpoints::InsertPoint you will see that the expected arguments are (id,x,y,z). You use this method when you have to want to set the value of the point at position id (that's why it must be an integer). http://www.vtk.org/doc/nightly/html/classvtkPoints.html#ab7f990c73fb291737abe4203994ce2a2
from the python shell, you can also check help(pts.InsertPoint) - but since these are wrapped objects sometimes the help appears a bit obscure.
The method InsertNextPoint, instead, just requires x,y,z and can be used as you are doing. It doesn't require an explicit id because it will just your point at the end
Specifically for python , you could be interested also in vtk.util.numpy_support which makes conversions between numpy and vtk elements easier (you can convert your points from numpy to a vtkdoublearray, then assign it to a vtkpoints with the method setdata )
The problem is not whether or not fl is composed of floats. The problem is that the method signature for InsertPoint expects each value to be an int.
From the python documentation:
exception TypeError:
Raised when an operation or function is applied to an object of inappropriate type. The associated value is a string giving details about the type mismatch.
This information is clearly available in the error message you pasted - it has both the exception type (TypeError) and the object by which it was thrown (InsertPoint). Had you accidentally included a float in your array indexers, the exception would have been thrown by something other than InsertPoint.
In the future, you should do some research on Google based on your exception error. I'm not telling you anything you couldn't find there.
If you still want to use InsertPoints, you have two options:
You can use the (int) cast to truncate edit: the first of your arguments to the whole, integer value (1.2 truncates to 1, 2.67 to 2, etc.), like so:
int(fl[i+1][j+1][k+1])
You can do #1, but round the value to the nearest integer value, like below (keep in mind that you'll need to import Math):
int(Math.Round(fl[i+1][j+1][k+1]))
Try wrapping each or your values in int(), like so:
pts.InsertPoint(int(fl[i+1][j+1][k+1]), int(xx[0][i+1]), int(yy[0][j+1]), int(zz[0][k+1]))

Categories